summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-03-26 00:01:18 +0200
committerAndrey Kleshchev <117672381+akleshchev@users.noreply.github.com>2026-03-31 18:28:31 +0300
commitc7576cddf3e548a7a6e63776da5674b7cb31297f (patch)
treef8a6d457b42ccd21ca32770829f065773f9c0bd2 /indra
parent136eb7afcf22ea20344f22b1d6c46a6a207a360b (diff)
#5579 Implement partial complexity calculations
Diffstat (limited to 'indra')
-rw-r--r--indra/newview/llvoavatar.cpp473
-rw-r--r--indra/newview/llvoavatar.h95
-rw-r--r--indra/newview/llvovolume.cpp32
3 files changed, 580 insertions, 20 deletions
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 74fcae9849..c3bc51ad12 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -682,6 +682,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mUpdatePeriod(1),
mOverallAppearance(AOA_INVISIBLE),
mVisualComplexityStale(true),
+ mLastFullComplexityUpdate(0.0),
mVisuallyMuteSetting(AV_RENDER_NORMALLY),
mMutedAVColor(LLColor4::white /* used for "uninitialize" */),
mFirstFullyVisible(true),
@@ -7566,7 +7567,8 @@ const LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_o
updateAttachmentOverrides();
}
- updateVisualComplexity();
+ // Inform complexity logic to do partial update.
+ markAttachmentComplexityDirty(viewer_object->getID());
if (viewer_object->isSelected())
{
@@ -7870,7 +7872,7 @@ bool LLVOAvatar::detachObject(LLViewerObject *viewer_object)
if (attachment->isObjectAttached(viewer_object))
{
- updateVisualComplexity();
+ markAttachmentComplexityDirty(viewer_object->getID());
bool is_animated_object = viewer_object->isAnimatedObject();
cleanupAttachedMesh(viewer_object);
@@ -8297,6 +8299,7 @@ void LLVOAvatar::updateRezzedStatusTimers(S32 rez_status)
selfStopPhase("wear_inventory_category", false);
selfStopPhase("process_initial_wearables_update", false);
+ // Start a complexity update.
updateVisualComplexity();
}
}
@@ -9230,6 +9233,7 @@ void LLVOAvatar::releaseComponentTextures()
{
// Regression case of messaging system. Expected 21 textures, received 20. last texture is not valid so set to default
setTETexture(TEX_HAIR_BAKED, IMG_DEFAULT_AVATAR);
+ markBodyPartsComplexityDirty();
}
}
@@ -9247,6 +9251,7 @@ void LLVOAvatar::releaseComponentTextures()
{
const U8 te = (ETextureIndex)bakedDicEntry->mLocalTextures[texture];
setTETexture(te, IMG_DEFAULT_AVATAR);
+ markBodyPartsComplexityDirty();
}
}
}
@@ -10132,6 +10137,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( bool success, LLViewerFetchedTexture
LL_INFOS() << "unexpected image id: " << id << LL_ENDL;
}
self->dirtyMesh();
+ self->markBodyPartsComplexityDirty();
}
else
{
@@ -10186,6 +10192,7 @@ void LLVOAvatar::onBakedTextureLoaded(bool success,
if (selfp && !success)
{
selfp->removeMissingBakedTextures();
+ selfp->markBodyPartsComplexityDirty();
}
if( final || !success )
@@ -10196,6 +10203,7 @@ void LLVOAvatar::onBakedTextureLoaded(bool success,
if( selfp && success && final )
{
selfp->useBakedTexture( id );
+ selfp->markBodyPartsComplexityDirty();
}
}
@@ -11146,10 +11154,432 @@ void LLVOAvatar::idleUpdateDebugInfo()
void LLVOAvatar::updateVisualComplexity()
{
LL_DEBUGS("AvatarRender") << "avatar " << getID() << " appearance changed" << LL_ENDL;
- // Set the cache time to in the past so it's updated ASAP
+ // Trigger cache recalculation on next idle update.
+ // Will recalculate stale data and control avatar.
mVisualComplexityStale = true;
}
+// Constants for body part costs
+static const F32 CACHE_LIFETIME_SECONDS = 30.0; // Todo: should be indefinite, until something actually changes
+
+void LLVOAvatar::calculateAttachmentComplexity(LLViewerObject* attached_object,
+ const F32 max_attachment_complexity,
+ ComplexityComponent& cache)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
+ cache.reset();
+
+ if (!attached_object || attached_object->isDead())
+ {
+ return;
+ }
+
+ // Reuse the existing accountRenderComplexityForObject logic
+ // This ensures compatibility with the legacy implementation
+ hud_complexity_list_t attachment_hud_list;
+ object_complexity_list_t attachment_object_list;
+ cache.render_cost = 0;
+ cache.textures.clear();
+ cache.triangle_count = 0;
+ cache.est_triangle_count = 0;
+ cache.surface_area = 0;
+
+ accountRenderComplexityForObject(
+ attached_object,
+ max_attachment_complexity,
+ cache.textures,
+ cache.render_cost,
+ cache.triangle_count,
+ cache.est_triangle_count,
+ cache.surface_area,
+ attachment_hud_list,
+ attachment_object_list
+ );
+
+ // Store HUD/object complexity info for later reporting
+ if (!attachment_hud_list.empty())
+ {
+ cache.hud_complexity = attachment_hud_list.front();
+ }
+ if (!attachment_object_list.empty())
+ {
+ cache.object_complexity = attachment_object_list.front();
+ }
+
+ cache.last_update_time = LLFrameTimer::getTotalSeconds();
+ cache.needs_update = false;
+}
+
+void LLVOAvatar::calculateBodyPartsComplexity(ComplexityComponent& cache)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
+ cache.reset();
+
+ // Body parts have a fixed cost
+ // This represents the base avatar mesh (eyes, hair, shape, skin, etc.)
+ cache.render_cost = calculateBodyPartsComplexity();
+
+ // For more accurate body part complexity, could enumerate mesh LODs here
+ // For now, using a constant cost as in the original implementation
+
+ cache.last_update_time = LLFrameTimer::getTotalSeconds();
+ cache.needs_update = false;
+}
+
+bool LLVOAvatar::shouldUpdateComplexityComponent(const ComplexityComponent& component) const
+{
+ if (component.needs_update)
+ {
+ return true;
+ }
+
+ F64 current_time = LLFrameTimer::getTotalSeconds();
+ return (current_time - component.last_update_time) > CACHE_LIFETIME_SECONDS;
+}
+
+bool LLVOAvatar::calculateControlAvatarComplexity(ComplexityComponent& cache, const F32 max_attachment_complexity)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
+ cache.reset();
+
+ // For control avatars (animated objects), we need to account for
+ // the skeleton and animation system overhead
+ if (!isControlAvatar())
+ {
+ return false;
+ }
+
+ LLControlAvatar* control_av = dynamic_cast<LLControlAvatar*>(this);
+ if (!control_av)
+ {
+ return false;
+ }
+
+ LLVOVolume* volp = control_av->mRootVolp;
+ if (!volp || volp->isAttachment())
+ {
+ return false;
+ }
+
+ hud_complexity_list_t hud_list;
+ object_complexity_list_t object_list;
+ cache.render_cost = 0;
+ cache.textures.clear();
+ cache.triangle_count = 0;
+ cache.est_triangle_count = 0;
+ cache.surface_area = 0;
+
+ accountRenderComplexityForObject(
+ volp,
+ max_attachment_complexity,
+ cache.textures,
+ cache.render_cost,
+ cache.triangle_count,
+ cache.est_triangle_count,
+ cache.surface_area,
+ hud_list,
+ object_list
+ );
+
+ // Store HUD/object complexity info for later reporting
+ if (!hud_list.empty())
+ {
+ cache.hud_complexity = hud_list.front();
+ }
+ if (!object_list.empty())
+ {
+ cache.object_complexity = object_list.front();
+ }
+
+ cache.last_update_time = LLFrameTimer::getTotalSeconds();
+ cache.needs_update = false;
+
+ return true;
+}
+
+void LLVOAvatar::accumulateComplexityComponent(const ComplexityComponent& component,
+ U32& total_cost,
+ LLVOVolume::texture_cost_t& all_textures,
+ hud_complexity_list_t& hud_list,
+ object_complexity_list_t& object_list)
+{
+ total_cost += component.render_cost;
+ mAttachmentSurfaceArea += component.surface_area;
+ mAttachmentVisibleTriangleCount += component.triangle_count;
+ mAttachmentEstTriangleCount += component.est_triangle_count;
+
+ // Merge textures (avoid double-counting)
+ all_textures.insert(component.textures.begin(), component.textures.end());
+
+ // Add HUD/object complexity info if present
+ if (component.hud_complexity.objectId.notNull())
+ {
+ hud_list.push_back(component.hud_complexity);
+ }
+ if (component.object_complexity.objectId.notNull())
+ {
+ object_list.push_back(component.object_complexity);
+ }
+}
+
+void LLVOAvatar::markAttachmentComplexityDirty(const LLUUID& object_id)
+{
+ mDirtyComplexityAttachments.insert(object_id);
+
+ // Also mark the cache entry if it exists
+ complexity_cache_map_t::iterator it = mComplexityCache.find(object_id);
+ if (it != mComplexityCache.end())
+ {
+ it->second.needs_update = true;
+ }
+
+ // Launch update process if not already scheduled
+ mVisualComplexityStale = true;
+}
+
+void LLVOAvatar::markAllComplexityDirty()
+{
+ for (complexity_cache_map_t::iterator it = mComplexityCache.begin();
+ it != mComplexityCache.end(); ++it)
+ {
+ it->second.needs_update = true;
+ mDirtyComplexityAttachments.insert(it->first);
+ }
+ mBodyPartsComplexity.needs_update = true;
+ mControlAvatarComplexity.needs_update = true;
+
+ // Launch update process if not already scheduled
+ mVisualComplexityStale = true;
+}
+
+void LLVOAvatar::markBodyPartsComplexityDirty()
+{
+ mBodyPartsComplexity.needs_update = true;
+
+ // Launch update process if not already scheduled
+ mVisualComplexityStale = true;
+}
+
+void LLVOAvatar::updateDirtyAttachmentComplexity(const F32 max_attachment_complexity)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
+ if (mDirtyComplexityAttachments.empty())
+ {
+ return;
+ }
+
+ // Update only attachments marked as dirty
+ for (std::set<LLUUID>::iterator dirty_it = mDirtyComplexityAttachments.begin();
+ dirty_it != mDirtyComplexityAttachments.end(); ++dirty_it)
+ {
+ const LLUUID& object_id = *dirty_it;
+
+ // Find the actual attachment object
+ LLViewerObject* attached_obj = gObjectList.findObject(object_id);
+ if (attached_obj && !attached_obj->isDead() && attached_obj->getAttachmentItemID().notNull())
+ {
+ ComplexityComponent& cache = mComplexityCache[object_id];
+ calculateAttachmentComplexity(attached_obj, max_attachment_complexity, cache);
+ }
+ else
+ {
+ // Object no longer exists, remove from cache
+ mComplexityCache.erase(object_id);
+ }
+ }
+
+ mDirtyComplexityAttachments.clear();
+}
+
+void LLVOAvatar::performFullComplexityUpdate(const F32 max_attachment_complexity)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
+ // Clear the cache and recalculate everything
+ mComplexityCache.clear();
+ mDirtyComplexityAttachments.clear();
+
+ // Recalculate all attachments
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end(); ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ if (!attachment || !attachment->getValid())
+ {
+ continue;
+ }
+
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter)
+ {
+ LLViewerObject* attached_object = attachment_iter->get();
+ if (attached_object && !attached_object->isDead())
+ {
+ LLUUID object_id = attached_object->getID();
+ ComplexityComponent& cache = mComplexityCache[object_id];
+ calculateAttachmentComplexity(attached_object, max_attachment_complexity, cache);
+ }
+ }
+ }
+
+ // Recalculate body parts
+ calculateBodyPartsComplexity(mBodyPartsComplexity);
+
+ mLastFullComplexityUpdate = LLFrameTimer::getTotalSeconds();
+}
+
+void LLVOAvatar::performPartialComplexityUpdate(const F32 max_attachment_complexity)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
+ // Update any attachments marked as dirty
+ updateDirtyAttachmentComplexity(max_attachment_complexity);
+
+ // Update stale cache entries
+ for (attachment_map_t::iterator iter = mAttachmentPoints.begin();
+ iter != mAttachmentPoints.end(); ++iter)
+ {
+ LLViewerJointAttachment* attachment = iter->second;
+ if (!attachment || !attachment->getValid())
+ {
+ continue;
+ }
+
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end(); ++attachment_iter)
+ {
+ LLViewerObject* attached_object = attachment_iter->get();
+ if (attached_object && !attached_object->isDead())
+ {
+ LLUUID object_id = attached_object->getID();
+ ComplexityComponent& cache = mComplexityCache[object_id];
+
+ // Update if cache is stale
+ if (shouldUpdateComplexityComponent(cache))
+ {
+ calculateAttachmentComplexity(attached_object, max_attachment_complexity, cache);
+ }
+ }
+ }
+ }
+
+ // Update body parts if stale
+ if (shouldUpdateComplexityComponent(mBodyPartsComplexity))
+ {
+ calculateBodyPartsComplexity(mBodyPartsComplexity);
+ }
+}
+
+// Calculations for mVisualComplexity value
+void LLVOAvatar::calculateUpdateRenderComplexity()
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
+
+ // ****************************************************************
+ // This calculation should not be modified by third party viewers,
+ // since it is used to limit rendering and should be uniform for
+ // everyone. If you have suggested improvements, submit them to
+ // the official viewer for consideration.
+ // ****************************************************************
+
+ if (!mVisualComplexityStale)
+ {
+ return;
+ }
+
+ // Get the attachment complexity limit
+ static LLCachedControl<F32> max_complexity_setting(gSavedSettings, "MaxAttachmentComplexity");
+ F32 max_attachment_complexity = max_complexity_setting;
+ max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY);
+
+ // Reset per-run counters
+ mAttachmentSurfaceArea = 0.f;
+ mAttachmentVisibleTriangleCount = 0;
+ mAttachmentEstTriangleCount = 0.f;
+
+ U32 total_cost = 0;
+ LLVOVolume::texture_cost_t all_textures; // Not currently in use. Perhaps add cost from unique textures?
+ hud_complexity_list_t hud_complexity_list;
+ object_complexity_list_t object_complexity_list;
+
+ // Determine update strategy
+ F64 current_time = LLFrameTimer::getTotalSeconds();
+
+ // Todo: check if it changes anything, then get rid of FULL_UPDATE_INTERVAL,
+ // full recalculation can take over 10ms for very complex avatars,
+ // thus is not practical to do. Leave only partial updates.
+ constexpr F64 FULL_UPDATE_INTERVAL = 60.0; // seconds
+ bool do_full_update = (current_time - mLastFullComplexityUpdate) > FULL_UPDATE_INTERVAL;
+
+ // Perform update based on strategy
+ if (do_full_update)
+ {
+ // Expensive! Todo: don't do.
+ performFullComplexityUpdate(max_attachment_complexity);
+ }
+ else
+ {
+ performPartialComplexityUpdate(max_attachment_complexity);
+ }
+
+ // Calculate and accumulate control avatar complexity if applicable
+ // For now this is on each run.
+ // Todo: See if mControlAvatarComplexity.needs_update is applicable here.
+ if (calculateControlAvatarComplexity(mControlAvatarComplexity, max_attachment_complexity))
+ {
+ accumulateComplexityComponent(
+ mControlAvatarComplexity,
+ total_cost,
+ all_textures,
+ hud_complexity_list,
+ object_complexity_list);
+ }
+
+ // Accumulate body parts complexity
+ accumulateComplexityComponent(mBodyPartsComplexity, total_cost,
+ all_textures, hud_complexity_list, object_complexity_list);
+
+ // Accumulate all attachment complexity from cache
+ // Clean up cache entries for attachments that no longer exist
+ std::vector<LLUUID> to_remove;
+
+ for (complexity_cache_map_t::iterator cache_iter = mComplexityCache.begin();
+ cache_iter != mComplexityCache.end(); ++cache_iter)
+ {
+ const LLUUID& object_id = cache_iter->first;
+
+ // Verify object still exists
+ LLViewerObject* obj = gObjectList.findObject(object_id);
+ if (!obj || obj->isDead())
+ {
+ to_remove.push_back(object_id);
+ continue;
+ }
+
+ // Accumulate this attachment's complexity
+ accumulateComplexityComponent(cache_iter->second, total_cost,
+ all_textures, hud_complexity_list, object_complexity_list);
+ }
+
+ // Remove stale cache entries
+ for (std::vector<LLUUID>::iterator it = to_remove.begin(); it != to_remove.end(); ++it)
+ {
+ mComplexityCache.erase(*it);
+ }
+
+ // Store results
+ mVisualComplexity = total_cost;
+
+ // Call the existing reporting function with the aggregated lists
+ processComplexityCostChange(hud_complexity_list, object_complexity_list);
+
+ // Stop processing until something changes
+ mVisualComplexityStale = false;
+}
U32 LLVOAvatar::calculateBodyPartsComplexity()
{
@@ -11227,15 +11657,18 @@ void LLVOAvatar::accountRenderComplexityForObject(
const F32 max_attachment_complexity,
LLVOVolume::texture_cost_t& textures,
U32& cost,
+ U32& visible_triangle_count,
+ F32& est_triangle_count,
+ F32& surface_area,
hud_complexity_list_t& hud_complexity_list,
object_complexity_list_t& object_complexity_list)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR;
if (attached_object && !attached_object->isHUDAttachment())
{
- mAttachmentVisibleTriangleCount += attached_object->recursiveGetTriangleCount();
- mAttachmentEstTriangleCount += attached_object->recursiveGetEstTrianglesMax();
- mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea();
+ visible_triangle_count += attached_object->recursiveGetTriangleCount();
+ est_triangle_count += attached_object->recursiveGetEstTrianglesMax();
+ surface_area += attached_object->recursiveGetScaledSurfaceArea();
textures.clear();
const LLDrawable* drawable = attached_object->mDrawable;
@@ -11306,7 +11739,7 @@ void LLVOAvatar::accountRenderComplexityForObject(
&& attached_object->mDrawable)
{
textures.clear();
- mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea();
+ surface_area += attached_object->recursiveGetScaledSurfaceArea();
const LLVOVolume* volume = attached_object->mDrawable->getVOVolume();
if (volume)
@@ -11373,7 +11806,7 @@ void LLVOAvatar::accountRenderComplexityForObject(
}
// Calculations for mVisualComplexity value
-void LLVOAvatar::calculateUpdateRenderComplexity()
+void LLVOAvatar::calculateUpdateRenderComplexityLegacy()
{
/*****************************************************************
* This calculation should not be modified by third party viewers,
@@ -11412,8 +11845,16 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
LLVOVolume *volp = control_av->mRootVolp;
if (volp && !volp->isAttachment())
{
- accountRenderComplexityForObject(volp, max_attachment_complexity,
- textures, cost, hud_complexity_list, object_complexity_list);
+ accountRenderComplexityForObject(
+ volp,
+ max_attachment_complexity,
+ textures,
+ cost,
+ mAttachmentVisibleTriangleCount,
+ mAttachmentEstTriangleCount,
+ mAttachmentSurfaceArea,
+ hud_complexity_list,
+ object_complexity_list);
}
}
@@ -11428,8 +11869,16 @@ void LLVOAvatar::calculateUpdateRenderComplexity()
++attachment_iter)
{
LLViewerObject* attached_object = attachment_iter->get();
- accountRenderComplexityForObject(attached_object, max_attachment_complexity,
- textures, cost, hud_complexity_list, object_complexity_list);
+ accountRenderComplexityForObject(
+ attached_object,
+ max_attachment_complexity,
+ textures,
+ cost,
+ mAttachmentVisibleTriangleCount,
+ mAttachmentEstTriangleCount,
+ mAttachmentSurfaceArea,
+ hud_complexity_list,
+ object_complexity_list);
}
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 0e719bbd6f..79a03527fb 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -302,11 +302,19 @@ public:
const F32 max_attachment_complexity,
LLVOVolume::texture_cost_t& textures,
U32& cost,
+ U32& visible_triangle_count,
+ F32& est_triangle_count,
+ F32& surface_area,
hud_complexity_list_t& hud_complexity_list,
object_complexity_list_t& object_complexity_list);
void calculateUpdateRenderComplexity();
+ void calculateUpdateRenderComplexityLegacy();
static const U32 VISUAL_COMPLEXITY_UNKNOWN;
void updateVisualComplexity();
+ // Mark that an attachment needs complexity recalculation
+ void markAttachmentComplexityDirty(const LLUUID& object_id);
+ void markAllComplexityDirty();
+ void markBodyPartsComplexityDirty();
void placeProfileQuery();
void readProfileQuery(S32 retries);
@@ -581,12 +589,6 @@ private:
// CPU render time in ms
F32 mCPURenderTime = 0.f;
- // the isTooComplex method uses these mutable values to avoid recalculating too frequently
- // DEPRECATED -- obsolete avatar render cost values
- mutable U32 mVisualComplexity;
- mutable bool mVisualComplexityStale;
- U32 mReportedVisualComplexity; // from other viewers through the simulator
-
mutable bool mCachedInMuteList;
mutable F64 mCachedMuteListUpdateTime;
mutable bool mCachedInBuddyList = false;
@@ -594,9 +596,90 @@ private:
VisualMuteSettings mVisuallyMuteSetting; // Always or never visually mute this AV
+ //--------------------------------------------------------------------
+ // Complexity calculation and caching
+ //--------------------------------------------------------------------
+
+private:
+ // Structure to cache complexity metrics for individual attachments or components
+ struct ComplexityComponent
+ {
+ U32 render_cost;
+ U32 triangle_count;
+ F32 surface_area;
+ F32 est_triangle_count;
+ LLVOVolume::texture_cost_t textures;
+ F64 last_update_time;
+ bool needs_update;
+
+ // For tracking HUD and object lists
+ LLHUDComplexity hud_complexity;
+ LLObjectComplexity object_complexity;
+
+ ComplexityComponent()
+ : render_cost(0)
+ , triangle_count(0)
+ , surface_area(0.f)
+ , est_triangle_count(0.f)
+ , last_update_time(0.0)
+ , needs_update(true)
+ {
+ }
+
+ void reset()
+ {
+ render_cost = 0;
+ triangle_count = 0;
+ surface_area = 0.f;
+ est_triangle_count = 0.f;
+ textures.clear();
+ hud_complexity.reset();
+ object_complexity.reset();
+ needs_update = true;
+ }
+ };
+
+ void calculateAttachmentComplexity(LLViewerObject* attached_object,
+ const F32 max_attachment_complexity,
+ ComplexityComponent& cache);
+ void calculateBodyPartsComplexity(ComplexityComponent& cache);
U32 calculateBodyPartsComplexity();
+ // return true, if a valid control avatar.
+ bool calculateControlAvatarComplexity(ComplexityComponent& cache, const F32 max_attachment_complexity);
+
+ void accumulateComplexityComponent(const ComplexityComponent& component,
+ U32& total_cost,
+ LLVOVolume::texture_cost_t& all_textures,
+ hud_complexity_list_t& hud_list,
+ object_complexity_list_t& object_list);
+
+ bool shouldUpdateComplexityComponent(const ComplexityComponent& component) const;
+ void updateDirtyAttachmentComplexity(const F32 max_attachment_complexity);
+ void performFullComplexityUpdate(const F32 max_attachment_complexity);
+ void performPartialComplexityUpdate(const F32 max_attachment_complexity);
+
void processComplexityCostChange(hud_complexity_list_t hud_complexity_list, object_complexity_list_t object_complexity_list);
+
+ // Todo: probably safe to store by local instead of global id
+ // since they should be unique to this avatar, but local id might be not known.
+ typedef std::map<LLUUID, ComplexityComponent> complexity_cache_map_t;
+ complexity_cache_map_t mComplexityCache; // Cache per-attachment complexity
+ ComplexityComponent mBodyPartsComplexity; // Cache for body parts (mesh, eyes, hair, etc)
+ ComplexityComponent mControlAvatarComplexity; // Cache for animated object control avatar
+ F64 mLastFullComplexityUpdate;
+
+ // Attachments marked for update,
+ // Todo: probably safe to store by local instead of global id
+ // since they should be unique to this avatar, but local id might be not known.
+ std::set<LLUUID> mDirtyComplexityAttachments;
+
+ // the isTooComplex method uses these mutable values to avoid recalculating too frequently
+ // DEPRECATED -- obsolete avatar render cost values
+ mutable U32 mVisualComplexity;
+ mutable bool mVisualComplexityStale;
+ U32 mReportedVisualComplexity; // from other viewers through the simulator
+
//--------------------------------------------------------------------
// animated object status
//--------------------------------------------------------------------
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index c12f65babf..1cb6d2ecc5 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1253,7 +1253,35 @@ void LLVOVolume::updateSculptTexture()
void LLVOVolume::updateVisualComplexity()
{
- LLVOAvatar* avatar = getAvatarAncestor();
+ LLVOAvatar* avatar = nullptr;
+ LLViewerObject* pobj = (LLViewerObject*)getParent();
+ LLViewerObject* lobj = this;
+ while (pobj)
+ {
+ avatar = pobj->asAvatar();
+ if (avatar)
+ {
+ break;
+ }
+ lobj = pobj;
+ pobj = (LLViewerObject*)pobj->getParent();
+ }
+
+ if (avatar)
+ {
+ // mark parent as dirty, complexity will be updated recursively.
+ avatar->markAttachmentComplexityDirty(lobj->getID());
+ }
+ LLVOAvatar* rigged_avatar = getAvatar();
+ if (rigged_avatar && (rigged_avatar != avatar))
+ {
+ // This might be wrong. Control avatars update each run,
+ // due to lack of dirty mechanics and this might be
+ // where we should implement and call
+ // markCotrolAvatarComplexityDirty() if !isAttachment().
+ rigged_avatar->markAttachmentComplexityDirty(lobj->getID());
+ }
+ /*LLVOAvatar* avatar = getAvatarAncestor();
if (avatar)
{
avatar->updateVisualComplexity();
@@ -1262,7 +1290,7 @@ void LLVOVolume::updateVisualComplexity()
if(rigged_avatar && (rigged_avatar != avatar))
{
rigged_avatar->updateVisualComplexity();
- }
+ }*/
}
void LLVOVolume::notifyMeshLoaded()