From a6068419e7fe1a5a0eda007b2e989769c0a92262 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 22 Sep 2017 18:04:03 +0100 Subject: SL-794, SL-790 - viewer-side enforcement in UI for various animated object limits that are also enforced on the server. --- indra/newview/llmeshrepository.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index c2a0393170..92c2be4a8b 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4021,6 +4021,33 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } +F32 LLMeshRepository::getEstTrianglesHigh(LLUUID mesh_id) +{ + F32 triangles_high = 0.f; + if (mThread && mesh_id.notNull()) + { + LLMutexLock lock(mThread->mHeaderMutex); + LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + { + LLSD& header = iter->second; + if (header.has("404") + || !header.has("lowest_lod") + || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)) + { + return 0.f; + } + + S32 bytes_high = header["high_lod"]["size"].asInteger(); + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + } + } + return triangles_high; +} + F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { if (mThread && mesh_id.notNull()) -- cgit v1.3 From 853924c7efd5c1d067c237d5a44c44db313745e9 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Fri, 29 Sep 2017 19:08:41 +0100 Subject: SL-794 - use largest LOD for est tri count, instead of trusting that it's always the high LOD --- indra/newview/llmeshrepository.cpp | 13 +++++++++---- indra/newview/llmeshrepository.h | 3 ++- indra/newview/llselectmgr.cpp | 2 +- indra/newview/llviewerobject.cpp | 8 ++++---- indra/newview/llviewerobject.h | 4 ++-- indra/newview/llvovolume.cpp | 19 +++++++++++-------- indra/newview/llvovolume.h | 2 +- 7 files changed, 30 insertions(+), 21 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 92c2be4a8b..093afdb880 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4021,9 +4021,9 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } -F32 LLMeshRepository::getEstTrianglesHigh(LLUUID mesh_id) +F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) { - F32 triangles_high = 0.f; + F32 triangles_max = 0.f; if (mThread && mesh_id.notNull()) { LLMutexLock lock(mThread->mHeaderMutex); @@ -4039,13 +4039,18 @@ F32 LLMeshRepository::getEstTrianglesHigh(LLUUID mesh_id) } S32 bytes_high = header["high_lod"]["size"].asInteger(); + S32 bytes_med = header["medium_lod"]["size"].asInteger(); + S32 bytes_low = header["low_lod"]["size"].asInteger(); + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + S32 bytes_max = llmax(bytes_high, bytes_med, bytes_low, bytes_lowest); + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); - triangles_high = llmax((F32) bytes_high-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + triangles_max = llmax((F32) bytes_max-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; } } - return triangles_high; + return triangles_max; } F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 28f037b85e..d2eac449f7 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -472,7 +472,8 @@ public: static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events - F32 getEstTrianglesHigh(LLUUID mesh_id); + // Estimated triangle count of the largest LOD + F32 getEstTrianglesMax(LLUUID mesh_id); F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index d3f240ac91..81fd228997 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -7444,7 +7444,7 @@ bool LLObjectSelection::checkAnimatedObjectEstTris() { anim_count++; } - est_tris += object->recursiveGetEstTrianglesHigh(); + est_tris += object->recursiveGetEstTrianglesMax(); max_tris = llmax((F32)max_tris,(F32)object->getAnimatedObjectMaxTris()); } return anim_count==0 || est_tris <= max_tris; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 99c68dab10..616db8ae2f 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3580,14 +3580,14 @@ F32 LLViewerObject::getLinksetPhysicsCost() return mLinksetPhysicsCost; } -F32 LLViewerObject::recursiveGetEstTrianglesHigh() const +F32 LLViewerObject::recursiveGetEstTrianglesMax() const { - F32 est_tris = getEstTrianglesHigh(); + F32 est_tris = getEstTrianglesMax(); for (child_list_t::const_iterator iter = mChildList.begin(); iter != mChildList.end(); iter++) { const LLViewerObject* child = *iter; - est_tris += child->recursiveGetEstTrianglesHigh(); + est_tris += child->recursiveGetEstTrianglesMax(); } return est_tris; } @@ -3607,7 +3607,7 @@ S32 LLViewerObject::getAnimatedObjectMaxTris() const return max_tris; } -F32 LLViewerObject::getEstTrianglesHigh() const +F32 LLViewerObject::getEstTrianglesMax() const { return 0.f; } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index a1a7eed002..345fd1fb27 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -358,8 +358,8 @@ public: virtual void setScale(const LLVector3 &scale, BOOL damped = FALSE); S32 getAnimatedObjectMaxTris() const; - F32 recursiveGetEstTrianglesHigh() const; - virtual F32 getEstTrianglesHigh() const; + F32 recursiveGetEstTrianglesMax() const; + virtual F32 getEstTrianglesMax() const; virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; virtual U32 getHighLODTriangleCount(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 121fb9c11e..efddc9235e 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3376,7 +3376,7 @@ bool LLVOVolume::canBeAnimatedObject() const { return false; } - F32 est_tris = recursiveGetEstTrianglesHigh(); + F32 est_tris = recursiveGetEstTrianglesMax(); if (est_tris > getAnimatedObjectMaxTris()) { LL_INFOS() << "est_tris " << est_tris << " exceeds limit " << getAnimatedObjectMaxTris() << LL_ENDL; @@ -3388,12 +3388,15 @@ bool LLVOVolume::canBeAnimatedObject() const bool LLVOVolume::isAnimatedObject() const { LLVOVolume *root_vol = (LLVOVolume*)getRootEdit(); - bool can_be_animated = canBeAnimatedObject(); - bool root_can_be_animated = root_vol->canBeAnimatedObject(); - bool root_is_animated = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; - if (can_be_animated && root_can_be_animated && root_is_animated) + bool root_is_animated_flag = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + if (root_is_animated_flag) { - return true; + bool root_can_be_animated = root_vol->canBeAnimatedObject(); + bool this_can_be_animated = ((root_vol == this) && root_can_be_animated) || canBeAnimatedObject(); + if (this_can_be_animated && root_can_be_animated) + { + return true; + } } return false; } @@ -3852,11 +3855,11 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const return (U32)shame; } -F32 LLVOVolume::getEstTrianglesHigh() const +F32 LLVOVolume::getEstTrianglesMax() const { if (isMesh()) { - return gMeshRepo.getEstTrianglesHigh(getVolume()->getParams().getSculptID()); + return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID()); } return 0.f; } diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 5891b36da8..24bcf41c74 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -134,7 +134,7 @@ public: /*virtual*/ const LLMatrix4 getRenderMatrix() const; typedef std::map texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; - /*virtual*/ F32 getEstTrianglesHigh() const; + /*virtual*/ F32 getEstTrianglesMax() const; F32 getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const; /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL) { return getStreamingCost(bytes, visible_bytes, NULL); } -- cgit v1.3 From a3fd0801c3030ff9a5a6761c9618f381aa965983 Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Mon, 26 Mar 2018 20:59:37 +0100 Subject: SL-897 - display for DebugAnimatedObjects now includes streaming cost triangle count --- indra/newview/llcontrolavatar.cpp | 7 ++- indra/newview/llmeshrepository.cpp | 90 +++++++++++++++++++++++++++++++++++--- indra/newview/llmeshrepository.h | 2 + indra/newview/llviewerobject.cpp | 5 +++ indra/newview/llviewerobject.h | 1 + indra/newview/llvovolume.cpp | 9 ++++ indra/newview/llvovolume.h | 1 + 7 files changed, 106 insertions(+), 9 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index e1715d567b..a16fa3cd26 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -242,7 +242,9 @@ void LLControlAvatar::updateDebugText() std::string lod_string; S32 total_tris = 0; S32 total_verts = 0; - S32 est_tris = 0; + F32 est_tris = 0.f; + F32 est_streaming_tris = 0.f; + for (std::vector::iterator it = volumes.begin(); it != volumes.end(); ++it) { @@ -251,6 +253,7 @@ void LLControlAvatar::updateDebugText() total_tris += volp->getTriangleCount(&verts); total_verts += verts; est_tris += volp->getEstTrianglesMax(); + est_streaming_tris += volp->getEstTrianglesStreamingCost(); lod_string += llformat("%d",volp->getLOD()); if (volp && volp->mDrawable) { @@ -287,7 +290,7 @@ void LLControlAvatar::updateDebugText() addDebugText(llformat("CAV obj %d anim %d active %s impost %d", total_linkset_count, animated_volume_count, active_string.c_str(), (S32) isImpostor())); addDebugText(llformat("types %s lods %s", type_string.c_str(), lod_string.c_str())); - addDebugText(llformat("tris %d (est %d), verts %d", total_tris, est_tris, total_verts)); + addDebugText(llformat("tris %d (est %.1f, streaming %.1f), verts %d", total_tris, est_tris, est_streaming_tris, total_verts)); addDebugText(llformat("pxarea %s", LLStringOps::getReadableNumber(getPixelArea()).c_str())); #if 0 std::string region_name = "no region"; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 4f0fb56ba6..b27fdefb83 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4062,9 +4062,14 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } -F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) +bool LLMeshRepository::getLODSizes(LLUUID mesh_id, std::vector& lod_byte_sizes, std::vector& lod_tri_counts) { - F32 triangles_max = 0.f; + lod_byte_sizes.resize(4); + lod_tri_counts.resize(4); + + std::fill(lod_byte_sizes.begin(), lod_byte_sizes.end(), 0); + std::fill(lod_tri_counts.begin(), lod_tri_counts.end(), 0.f); + if (mThread && mesh_id.notNull()) { LLMutexLock lock(mThread->mHeaderMutex); @@ -4076,22 +4081,93 @@ F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) || !header.has("lowest_lod") || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)) { - return 0.f; + return false; } S32 bytes_high = header["high_lod"]["size"].asInteger(); S32 bytes_med = header["medium_lod"]["size"].asInteger(); + if (bytes_med == 0) + { + bytes_med = bytes_high; + } S32 bytes_low = header["low_lod"]["size"].asInteger(); + if (bytes_low == 0) + { + bytes_low = bytes_med; + } S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); - S32 bytes_max = llmax(bytes_high, bytes_med, bytes_low, bytes_lowest); + if (bytes_lowest == 0) + { + bytes_lowest = bytes_low; + } + lod_byte_sizes[0] = bytes_high; + lod_byte_sizes[1] = bytes_med; + lod_byte_sizes[2] = bytes_low; + lod_byte_sizes[3] = bytes_lowest; F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); - triangles_max = llmax((F32) bytes_max-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + + for (S32 i=0; i<4; i++) + { + lod_tri_counts[i] = llmax((F32) lod_byte_sizes[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + } + + return true; + } + } + return false; +} + +F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) +{ + std::vector lod_byte_sizes; + std::vector lod_tri_counts; + bool succ = getLODSizes(mesh_id, lod_byte_sizes, lod_tri_counts); + if (!succ) + { + return 0.f; + } + + return llmax(lod_tri_counts[0], lod_tri_counts[1], lod_tri_counts[2], lod_tri_counts[3]); +} + +F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) +{ + std::vector lod_byte_sizes; + std::vector tris_by_lod; + bool succ = getLODSizes(mesh_id, lod_byte_sizes, tris_by_lod); + + if (!succ) + { + LL_DEBUGS("StreamingCost") << "couldn't get tris_by_lod" << LL_ENDL; + return 0.f; + } + + LL_DEBUGS("StreamingCost") << "tris_by_lod: " + << tris_by_lod[0] << ", " + << tris_by_lod[1] << ", " + << tris_by_lod[2] << ", " + << tris_by_lod[3] << LL_ENDL; + + F32 charged_tris = tris_by_lod[0]; + F32 allowed_tris = tris_by_lod[0]; + const F32 ENFORCE_FLOOR = 64.0f; + for (S32 i=1; i<4; i++) + { + // How many tris can we have in this LOD without affecting land impact? + // - normally an LOD should be at most half the size of the previous one. + // - once we reach a floor of ENFORCE_FLOOR, don't require LODs to get any smaller. + allowed_tris = llclamp(allowed_tris/2.0f,ENFORCE_FLOOR,tris_by_lod[i]); + F32 excess_tris = tris_by_lod[i]-allowed_tris; + if (excess_tris>0.f) + { + LL_DEBUGS("StreamingCost") << "excess tris in lod[" << i << "] " << excess_tris << " allowed " << allowed_tris << LL_ENDL; + charged_tris += excess_tris; } } - return triangles_max; + return charged_tris; } F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) @@ -4203,7 +4279,7 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 F32 weighted_avg = triangles_high*high_area + triangles_mid*mid_area + triangles_low*low_area + - triangles_lowest*lowest_area; + triangles_lowest*lowest_area; if (unscaled_value) { diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index d2eac449f7..bae3f66a72 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -472,8 +472,10 @@ public: static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events + bool getLODSizes(LLUUID mesh_id, std::vector& lod_byte_sizes, std::vector& lod_tri_counts); // Estimated triangle count of the largest LOD F32 getEstTrianglesMax(LLUUID mesh_id); + F32 getEstTrianglesStreamingCost(LLUUID mesh_id); F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 531f9a9527..f606abedf5 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -3692,6 +3692,11 @@ F32 LLViewerObject::getEstTrianglesMax() const return 0.f; } +F32 LLViewerObject::getEstTrianglesStreamingCost() const +{ + return 0.f; +} + F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const { return 0.f; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index ab0e74bc97..2fe14c2fcf 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -365,6 +365,7 @@ public: S32 getAnimatedObjectMaxTris() const; F32 recursiveGetEstTrianglesMax() const; virtual F32 getEstTrianglesMax() const; + virtual F32 getEstTrianglesStreamingCost() const; virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; virtual U32 getHighLODTriangleCount(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 69c2d2cccd..3b5129d994 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3905,6 +3905,15 @@ F32 LLVOVolume::getEstTrianglesMax() const return 0.f; } +F32 LLVOVolume::getEstTrianglesStreamingCost() const +{ + if (isMesh() && getVolume()) + { + return gMeshRepo.getEstTrianglesStreamingCost(getVolume()->getParams().getSculptID()); + } + return 0.f; +} + F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const { F32 radius = getScale().length()*0.5f; diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 4aec48e8ff..f6738945d8 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -135,6 +135,7 @@ public: typedef std::map texture_cost_t; U32 getRenderCost(texture_cost_t &textures) const; /*virtual*/ F32 getEstTrianglesMax() const; + /*virtual*/ F32 getEstTrianglesStreamingCost() const; F32 getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const; /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL) { return getStreamingCost(bytes, visible_bytes, NULL); } -- cgit v1.3 From bc773adf618eb531fdccacd95f4cd51f6b87497a Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Tue, 24 Apr 2018 16:55:55 +0100 Subject: MAINT-8549 - refactoring of streaming cost and related calculations --- indra/llcharacter/lljoint.cpp | 2 +- indra/newview/llmeshrepository.cpp | 290 ++++++++++++++++++++++++++----------- indra/newview/llmeshrepository.h | 47 +++++- indra/newview/llvovolume.cpp | 4 - 4 files changed, 255 insertions(+), 88 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index abc5a95c8d..9d10f53bed 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -440,7 +440,7 @@ void LLJoint::addAttachmentPosOverride( const LLVector3& pos, const LLUUID& mesh llclamp(pos[2],-LL_MAX_PELVIS_OFFSET, LL_MAX_PELVIS_OFFSET)); if (constrained_pos != pos) { - LL_DEBUGS("Avatar") << "attachment pos override constrained to " + LL_DEBUGS("Avatar") << mesh_id << " joint " << getName() << " attachment pos override constrained to " << constrained_pos << " was " << pos << LL_ENDL; } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index b27fdefb83..9687376cff 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4062,7 +4062,7 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } -bool LLMeshRepository::getLODSizes(LLUUID mesh_id, std::vector& lod_byte_sizes, std::vector& lod_tri_counts) +bool LLMeshRepository::getLODSizes(LLSD& header, std::vector& lod_byte_sizes, std::vector& lod_tri_counts) { lod_byte_sizes.resize(4); lod_tri_counts.resize(4); @@ -4070,120 +4070,111 @@ bool LLMeshRepository::getLODSizes(LLUUID mesh_id, std::vector& lod_byte_si std::fill(lod_byte_sizes.begin(), lod_byte_sizes.end(), 0); std::fill(lod_tri_counts.begin(), lod_tri_counts.end(), 0.f); - if (mThread && mesh_id.notNull()) + S32 bytes_high = header["high_lod"]["size"].asInteger(); + S32 bytes_med = header["medium_lod"]["size"].asInteger(); + if (bytes_med == 0) { - LLMutexLock lock(mThread->mHeaderMutex); - LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); - if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) - { - LLSD& header = iter->second; - if (header.has("404") - || !header.has("lowest_lod") - || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)) - { - return false; - } - - S32 bytes_high = header["high_lod"]["size"].asInteger(); - S32 bytes_med = header["medium_lod"]["size"].asInteger(); - if (bytes_med == 0) - { - bytes_med = bytes_high; - } - S32 bytes_low = header["low_lod"]["size"].asInteger(); - if (bytes_low == 0) - { - bytes_low = bytes_med; - } - S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); - if (bytes_lowest == 0) - { - bytes_lowest = bytes_low; - } - lod_byte_sizes[0] = bytes_high; - lod_byte_sizes[1] = bytes_med; - lod_byte_sizes[2] = bytes_low; - lod_byte_sizes[3] = bytes_lowest; - - F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead - F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" - F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + bytes_med = bytes_high; + } + S32 bytes_low = header["low_lod"]["size"].asInteger(); + if (bytes_low == 0) + { + bytes_low = bytes_med; + } + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + if (bytes_lowest == 0) + { + bytes_lowest = bytes_low; + } + lod_byte_sizes[0] = bytes_lowest; + lod_byte_sizes[1] = bytes_low; + lod_byte_sizes[2] = bytes_med; + lod_byte_sizes[3] = bytes_high; - for (S32 i=0; i<4; i++) - { - lod_tri_counts[i] = llmax((F32) lod_byte_sizes[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; - } + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); - return true; - } + for (S32 i=0; i<4; i++) + { + lod_tri_counts[i] = llmax((F32) lod_byte_sizes[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; } - return false; + + return true; } F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) { - std::vector lod_byte_sizes; - std::vector lod_tri_counts; - bool succ = getLODSizes(mesh_id, lod_byte_sizes, lod_tri_counts); - if (!succ) + LLMeshCostData costs; + if (getCostData(mesh_id, costs)) + { + return costs.mEstTrisMax; + } + else { return 0.f; } - - return llmax(lod_tri_counts[0], lod_tri_counts[1], lod_tri_counts[2], lod_tri_counts[3]); } F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) { - std::vector lod_byte_sizes; - std::vector tris_by_lod; - bool succ = getLODSizes(mesh_id, lod_byte_sizes, tris_by_lod); - - if (!succ) + LLMeshCostData costs; + if (getCostData(mesh_id, costs)) { - LL_DEBUGS("StreamingCost") << "couldn't get tris_by_lod" << LL_ENDL; - return 0.f; + return costs.computeEstTrisForStreamingCost(); } - - LL_DEBUGS("StreamingCost") << "tris_by_lod: " - << tris_by_lod[0] << ", " - << tris_by_lod[1] << ", " - << tris_by_lod[2] << ", " - << tris_by_lod[3] << LL_ENDL; - - F32 charged_tris = tris_by_lod[0]; - F32 allowed_tris = tris_by_lod[0]; - const F32 ENFORCE_FLOOR = 64.0f; - for (S32 i=1; i<4; i++) + else { - // How many tris can we have in this LOD without affecting land impact? - // - normally an LOD should be at most half the size of the previous one. - // - once we reach a floor of ENFORCE_FLOOR, don't require LODs to get any smaller. - allowed_tris = llclamp(allowed_tris/2.0f,ENFORCE_FLOOR,tris_by_lod[i]); - F32 excess_tris = tris_by_lod[i]-allowed_tris; - if (excess_tris>0.f) - { - LL_DEBUGS("StreamingCost") << "excess tris in lod[" << i << "] " << excess_tris << " allowed " << allowed_tris << LL_ENDL; - charged_tris += excess_tris; - } + return 0.f; } - return charged_tris; } +// FIXME replace with calc based on LLMeshCostData F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { + F32 result = 0.f; if (mThread && mesh_id.notNull()) { LLMutexLock lock(mThread->mHeaderMutex); LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) { - return getStreamingCost(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); + result = getStreamingCost(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); } } - return 0.f; + if (result > 0.f) + { + LLMeshCostData data; + if (getCostData(mesh_id, data)) + { + F32 ref_streaming_cost = data.computeRadiusBasedStreamingCost(radius); + F32 ref_weighted_tris = data.computeRadiusWeightedTris(radius); + if (!is_approx_equal(ref_streaming_cost,result)) + { + LL_WARNS() << mesh_id << "streaming mismatch " << result << " " << ref_streaming_cost << LL_ENDL; + } + if (unscaled_value && !is_approx_equal(ref_weighted_tris,*unscaled_value)) + { + LL_WARNS() << mesh_id << "weighted_tris mismatch " << *unscaled_value << " " << ref_weighted_tris << LL_ENDL; + } + if (bytes && (*bytes != data.mSizeTotal)) + { + LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.mSizeTotal << LL_ENDL; + } + if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.mSizeByLOD[lod])) + { + LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.mSizeByLOD[lod] << LL_ENDL; + } + } + else + { + LL_WARNS() << "getCostData failed!!!" << LL_ENDL; + } + } + return result; } +// FIXME replace with calc based on LLMeshCostData //static F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { @@ -4289,6 +4280,141 @@ F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32 return weighted_avg/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; } +LLMeshCostData::LLMeshCostData() +{ + mSizeByLOD.resize(4); + mEstTrisByLOD.resize(4); + + std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); + std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); + + mSizeTotal = 0; + mEstTrisMax = 0; +} + +F32 LLMeshCostData::computeRadiusWeightedTris(F32 radius) +{ + F32 max_distance = 512.f; + + F32 dlowest = llmin(radius/0.03f, max_distance); + F32 dlow = llmin(radius/0.06f, max_distance); + F32 dmid = llmin(radius/0.24f, max_distance); + + F32 triangles_lowest = mEstTrisByLOD[0]; + F32 triangles_low = mEstTrisByLOD[1]; + F32 triangles_mid = mEstTrisByLOD[2]; + F32 triangles_high = mEstTrisByLOD[3]; + + F32 max_area = 102944.f; //area of circle that encompasses region (see MAINT-6559) + F32 min_area = 1.f; + + F32 high_area = llmin(F_PI*dmid*dmid, max_area); + F32 mid_area = llmin(F_PI*dlow*dlow, max_area); + F32 low_area = llmin(F_PI*dlowest*dlowest, max_area); + F32 lowest_area = max_area; + + lowest_area -= low_area; + low_area -= mid_area; + mid_area -= high_area; + + high_area = llclamp(high_area, min_area, max_area); + mid_area = llclamp(mid_area, min_area, max_area); + low_area = llclamp(low_area, min_area, max_area); + lowest_area = llclamp(lowest_area, min_area, max_area); + + F32 total_area = high_area + mid_area + low_area + lowest_area; + high_area /= total_area; + mid_area /= total_area; + low_area /= total_area; + lowest_area /= total_area; + + F32 weighted_avg = triangles_high*high_area + + triangles_mid*mid_area + + triangles_low*low_area + + triangles_lowest*lowest_area; + + return weighted_avg; +} + +F32 LLMeshCostData::computeEstTrisForStreamingCost() +{ + LL_DEBUGS("StreamingCost") << "tris_by_lod: " + << mEstTrisByLOD[0] << ", " + << mEstTrisByLOD[1] << ", " + << mEstTrisByLOD[2] << ", " + << mEstTrisByLOD[3] << LL_ENDL; + + F32 charged_tris = mEstTrisByLOD[3]; + F32 allowed_tris = mEstTrisByLOD[3]; + const F32 ENFORCE_FLOOR = 64.0f; + for (S32 i=2; i>=0; i--) + { + // How many tris can we have in this LOD without affecting land impact? + // - normally an LOD should be at most half the size of the previous one. + // - once we reach a floor of ENFORCE_FLOOR, don't require LODs to get any smaller. + allowed_tris = llclamp(allowed_tris/2.0f,ENFORCE_FLOOR,mEstTrisByLOD[i]); + F32 excess_tris = mEstTrisByLOD[i]-allowed_tris; + if (excess_tris>0.f) + { + LL_DEBUGS("StreamingCost") << "excess tris in lod[" << i << "] " << excess_tris << " allowed " << allowed_tris << LL_ENDL; + charged_tris += excess_tris; + } + } + return charged_tris; +} + +F32 LLMeshCostData::computeRadiusBasedStreamingCost(F32 radius) +{ + return computeRadiusWeightedTris(radius)/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; +} + +F32 LLMeshCostData::computeTriangleBasedStreamingCost() +{ + F32 result = ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * computeEstTrisForStreamingCost()/0.06; + return result; +} + +bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) +{ + data = LLMeshCostData(); + + if (mThread && mesh_id.notNull()) + { + LLMutexLock lock(mThread->mHeaderMutex); + LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); + if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) + { + LLSD& header = iter->second; + + bool header_invalid = (header.has("404") + || !header.has("lowest_lod") + || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)); + if (!header_invalid) + { + return getCostData(header, mesh_id, data); + } + + return true; + } + } + return false; +} + +bool LLMeshRepository::getCostData(LLSD& header, LLUUID mesh_id, LLMeshCostData& data) +{ + data = LLMeshCostData(); + + if (!getLODSizes(header, data.mSizeByLOD, data.mEstTrisByLOD)) + { + return false; + } + + data.mEstTrisMax = llmax(data.mEstTrisByLOD[0], data.mEstTrisByLOD[1], data.mEstTrisByLOD[2], data.mEstTrisByLOD[3]); + + data.mSizeTotal = data.mSizeByLOD[0] + data.mSizeByLOD[1] + data.mSizeByLOD[2] + data.mSizeByLOD[3]; + + return true; +} LLPhysicsDecomp::LLPhysicsDecomp() : LLThread("Physics Decomp") diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index bae3f66a72..e43f719471 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -451,6 +451,45 @@ private: LLCore::HttpRequest::priority_t mHttpPriority; }; +// Params related to streaming cost, render cost, and scene complexity tracking. +struct LLMeshCostData +{ + LLMeshCostData(); + + // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. + std::vector mSizeByLOD; + + // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. + std::vector mEstTrisByLOD; + + // Estimated triangle counts for the largest LOD. Typically this + // is also the "high" LOD, but not necessarily. + F32 mEstTrisMax; + + // Sum of all LOD sizes. + S32 mSizeTotal; + + // Helper functions for building data + + // Triangle count as computed by original streaming cost + // formula. Triangles in each LOD are weighted based on how + // frequently they will be seen. + // This was called "unscaled_value" in the original getStreamingCost() functions. + F32 computeRadiusWeightedTris(F32 radius); + + // Triangle count used by triangle-based cost formula. Based on + // triangles in highest LOD plus potentially partial charges for + // lower LODs depending on complexity. + F32 computeEstTrisForStreamingCost(); + + // Streaming cost. This should match the server-side calculation + // for the corresponding volume. + F32 computeRadiusBasedStreamingCost(F32 radius); + + // New streaming cost formula, currently only used for animated objects. + F32 computeTriangleBasedStreamingCost(); +}; + class LLMeshRepository { public: @@ -472,12 +511,14 @@ public: static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events - bool getLODSizes(LLUUID mesh_id, std::vector& lod_byte_sizes, std::vector& lod_tri_counts); + bool getLODSizes(LLSD& header, std::vector& lod_byte_sizes, std::vector& lod_tri_counts); // Estimated triangle count of the largest LOD F32 getEstTrianglesMax(LLUUID mesh_id); F32 getEstTrianglesStreamingCost(LLUUID mesh_id); F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + bool getCostData(LLUUID mesh_id, LLMeshCostData& data); + bool getCostData(LLSD& header, LLUUID mesh_id, LLMeshCostData& data); LLMeshRepository(); @@ -588,5 +629,9 @@ public: extern LLMeshRepository gMeshRepo; +// AXON make sure this is consistent with the final simulator-side values. +const F32 ANIMATED_OBJECT_BASE_COST = 15.0f; +const F32 ANIMATED_OBJECT_COST_PER_KTRI = 1.5f; + #endif diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index bf646eb44b..9db4b3de0c 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3918,10 +3918,6 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_v { F32 radius = getScale().length()*0.5f; - // AXON make sure this is consistent with the final simulator-side values. - const F32 ANIMATED_OBJECT_BASE_COST = 15.0f; - const F32 ANIMATED_OBJECT_COST_PER_KTRI = 1.5f; - F32 linkset_base_cost = 0.f; if (isAnimatedObject() && isRootEdit()) { -- cgit v1.3 From 7d91a263a8a634b0148fcd9b1a3af28f7b58ca1c Mon Sep 17 00:00:00 2001 From: "Brad Payne (Vir Linden)" Date: Wed, 25 Apr 2018 17:10:21 +0100 Subject: MAINT-8549 - more on animesh ARC and associated refactoring --- indra/newview/llfloatermodelpreview.cpp | 6 +- indra/newview/llmeshrepository.cpp | 156 ++++++++++++++++++-------------- indra/newview/llmeshrepository.h | 52 +++++++---- indra/newview/llsceneview.cpp | 19 ++-- indra/newview/llselectmgr.cpp | 12 ++- indra/newview/llviewerobject.cpp | 11 ++- indra/newview/llviewerobject.h | 5 +- indra/newview/llviewerwindow.cpp | 9 +- indra/newview/llvovolume.cpp | 82 ++++++++++++----- indra/newview/llvovolume.h | 4 +- 10 files changed, 231 insertions(+), 125 deletions(-) (limited to 'indra/newview/llmeshrepository.cpp') diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 168fb13d11..1667f01272 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1360,7 +1360,11 @@ U32 LLModelPreview::calcResourceCost() F32 radius = scale.length()*0.5f*debug_scale; - streaming_cost += LLMeshRepository::getStreamingCost(ret, radius); + LLMeshCostData costs; + if (gMeshRepo.getCostData(ret, costs)) + { + streaming_cost += costs.getRadiusBasedStreamingCost(radius); + } } } diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 9687376cff..215cdf3394 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4062,53 +4062,12 @@ void LLMeshRepository::uploadError(LLSD& args) mUploadErrorQ.push(args); } -bool LLMeshRepository::getLODSizes(LLSD& header, std::vector& lod_byte_sizes, std::vector& lod_tri_counts) -{ - lod_byte_sizes.resize(4); - lod_tri_counts.resize(4); - - std::fill(lod_byte_sizes.begin(), lod_byte_sizes.end(), 0); - std::fill(lod_tri_counts.begin(), lod_tri_counts.end(), 0.f); - - S32 bytes_high = header["high_lod"]["size"].asInteger(); - S32 bytes_med = header["medium_lod"]["size"].asInteger(); - if (bytes_med == 0) - { - bytes_med = bytes_high; - } - S32 bytes_low = header["low_lod"]["size"].asInteger(); - if (bytes_low == 0) - { - bytes_low = bytes_med; - } - S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); - if (bytes_lowest == 0) - { - bytes_lowest = bytes_low; - } - lod_byte_sizes[0] = bytes_lowest; - lod_byte_sizes[1] = bytes_low; - lod_byte_sizes[2] = bytes_med; - lod_byte_sizes[3] = bytes_high; - - F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead - F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" - F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); - - for (S32 i=0; i<4; i++) - { - lod_tri_counts[i] = llmax((F32) lod_byte_sizes[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; - } - - return true; -} - F32 LLMeshRepository::getEstTrianglesMax(LLUUID mesh_id) { LLMeshCostData costs; if (getCostData(mesh_id, costs)) { - return costs.mEstTrisMax; + return costs.getEstTrisMax(); } else { @@ -4121,7 +4080,7 @@ F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) LLMeshCostData costs; if (getCostData(mesh_id, costs)) { - return costs.computeEstTrisForStreamingCost(); + return costs.getEstTrisForStreamingCost(); } else { @@ -4130,7 +4089,7 @@ F32 LLMeshRepository::getEstTrianglesStreamingCost(LLUUID mesh_id) } // FIXME replace with calc based on LLMeshCostData -F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { F32 result = 0.f; if (mThread && mesh_id.notNull()) @@ -4139,7 +4098,7 @@ F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); if (iter != mThread->mMeshHeader.end() && mThread->mMeshHeaderSize[mesh_id] > 0) { - result = getStreamingCost(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); + result = getStreamingCostLegacy(iter->second, radius, bytes, bytes_visible, lod, unscaled_value); } } if (result > 0.f) @@ -4147,8 +4106,8 @@ F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S LLMeshCostData data; if (getCostData(mesh_id, data)) { - F32 ref_streaming_cost = data.computeRadiusBasedStreamingCost(radius); - F32 ref_weighted_tris = data.computeRadiusWeightedTris(radius); + F32 ref_streaming_cost = data.getRadiusBasedStreamingCost(radius); + F32 ref_weighted_tris = data.getRadiusWeightedTris(radius); if (!is_approx_equal(ref_streaming_cost,result)) { LL_WARNS() << mesh_id << "streaming mismatch " << result << " " << ref_streaming_cost << LL_ENDL; @@ -4157,13 +4116,13 @@ F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S { LL_WARNS() << mesh_id << "weighted_tris mismatch " << *unscaled_value << " " << ref_weighted_tris << LL_ENDL; } - if (bytes && (*bytes != data.mSizeTotal)) + if (bytes && (*bytes != data.getSizeTotal())) { - LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.mSizeTotal << LL_ENDL; + LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.getSizeTotal() << LL_ENDL; } - if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.mSizeByLOD[lod])) + if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.getSizeByLOD(lod))) { - LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.mSizeByLOD[lod] << LL_ENDL; + LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.getSizeByLOD(lod) << LL_ENDL; } } else @@ -4176,7 +4135,7 @@ F32 LLMeshRepository::getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes, S // FIXME replace with calc based on LLMeshCostData //static -F32 LLMeshRepository::getStreamingCost(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { if (header.has("404") || !header.has("lowest_lod") @@ -4287,12 +4246,79 @@ LLMeshCostData::LLMeshCostData() std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); +} + +bool LLMeshCostData::init(const LLSD& header) +{ + mSizeByLOD.resize(4); + mEstTrisByLOD.resize(4); + + std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); + std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); - mSizeTotal = 0; - mEstTrisMax = 0; + S32 bytes_high = header["high_lod"]["size"].asInteger(); + S32 bytes_med = header["medium_lod"]["size"].asInteger(); + if (bytes_med == 0) + { + bytes_med = bytes_high; + } + S32 bytes_low = header["low_lod"]["size"].asInteger(); + if (bytes_low == 0) + { + bytes_low = bytes_med; + } + S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + if (bytes_lowest == 0) + { + bytes_lowest = bytes_low; + } + mSizeByLOD[0] = bytes_lowest; + mSizeByLOD[1] = bytes_low; + mSizeByLOD[2] = bytes_med; + mSizeByLOD[3] = bytes_high; + + F32 METADATA_DISCOUNT = (F32) gSavedSettings.getU32("MeshMetaDataDiscount"); //discount 128 bytes to cover the cost of LLSD tags and compression domain overhead + F32 MINIMUM_SIZE = (F32) gSavedSettings.getU32("MeshMinimumByteSize"); //make sure nothing is "free" + F32 bytes_per_triangle = (F32) gSavedSettings.getU32("MeshBytesPerTriangle"); + + for (S32 i=0; i<4; i++) + { + mEstTrisByLOD[i] = llmax((F32) mSizeByLOD[i]-METADATA_DISCOUNT, MINIMUM_SIZE)/bytes_per_triangle; + } + + return true; } -F32 LLMeshCostData::computeRadiusWeightedTris(F32 radius) + +S32 LLMeshCostData::getSizeByLOD(S32 lod) +{ + if (llclamp(lod,0,3) != lod) + { + return 0; + } + return mSizeByLOD[lod]; +} + +S32 LLMeshCostData::getSizeTotal() +{ + return mSizeByLOD[0] + mSizeByLOD[1] + mSizeByLOD[2] + mSizeByLOD[3]; +} + +F32 LLMeshCostData::getEstTrisByLOD(S32 lod) +{ + if (llclamp(lod,0,3) != lod) + { + return 0.f; + } + return mEstTrisByLOD[lod]; +} + +F32 LLMeshCostData::getEstTrisMax() +{ + return llmax(mEstTrisByLOD[0], mEstTrisByLOD[1], mEstTrisByLOD[2], mEstTrisByLOD[3]); +} + +F32 LLMeshCostData::getRadiusWeightedTris(F32 radius) { F32 max_distance = 512.f; @@ -4336,7 +4362,7 @@ F32 LLMeshCostData::computeRadiusWeightedTris(F32 radius) return weighted_avg; } -F32 LLMeshCostData::computeEstTrisForStreamingCost() +F32 LLMeshCostData::getEstTrisForStreamingCost() { LL_DEBUGS("StreamingCost") << "tris_by_lod: " << mEstTrisByLOD[0] << ", " @@ -4363,14 +4389,14 @@ F32 LLMeshCostData::computeEstTrisForStreamingCost() return charged_tris; } -F32 LLMeshCostData::computeRadiusBasedStreamingCost(F32 radius) +F32 LLMeshCostData::getRadiusBasedStreamingCost(F32 radius) { - return computeRadiusWeightedTris(radius)/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; + return getRadiusWeightedTris(radius)/gSavedSettings.getU32("MeshTriangleBudget")*15000.f; } -F32 LLMeshCostData::computeTriangleBasedStreamingCost() +F32 LLMeshCostData::getTriangleBasedStreamingCost() { - F32 result = ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * computeEstTrisForStreamingCost()/0.06; + F32 result = ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrisForStreamingCost(); return result; } @@ -4391,7 +4417,7 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)); if (!header_invalid) { - return getCostData(header, mesh_id, data); + return getCostData(header, data); } return true; @@ -4400,19 +4426,15 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) return false; } -bool LLMeshRepository::getCostData(LLSD& header, LLUUID mesh_id, LLMeshCostData& data) +bool LLMeshRepository::getCostData(LLSD& header, LLMeshCostData& data) { data = LLMeshCostData(); - if (!getLODSizes(header, data.mSizeByLOD, data.mEstTrisByLOD)) + if (!data.init(header)) { return false; } - data.mEstTrisMax = llmax(data.mEstTrisByLOD[0], data.mEstTrisByLOD[1], data.mEstTrisByLOD[2], data.mEstTrisByLOD[3]); - - data.mSizeTotal = data.mSizeByLOD[0] + data.mSizeByLOD[1] + data.mSizeByLOD[2] + data.mSizeByLOD[3]; - return true; } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index e43f719471..9bf12e9e41 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -452,42 +452,57 @@ private: }; // Params related to streaming cost, render cost, and scene complexity tracking. -struct LLMeshCostData +class LLMeshCostData { +public: LLMeshCostData(); - // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. - std::vector mSizeByLOD; + bool init(const LLSD& header); + + // Size for given LOD + S32 getSizeByLOD(S32 lod); - // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. - std::vector mEstTrisByLOD; + // Sum of all LOD sizes. + S32 getSizeTotal(); + // Estimated triangle counts for the given LOD. + F32 getEstTrisByLOD(S32 lod); + // Estimated triangle counts for the largest LOD. Typically this // is also the "high" LOD, but not necessarily. - F32 mEstTrisMax; - - // Sum of all LOD sizes. - S32 mSizeTotal; - - // Helper functions for building data + F32 getEstTrisMax(); // Triangle count as computed by original streaming cost // formula. Triangles in each LOD are weighted based on how // frequently they will be seen. // This was called "unscaled_value" in the original getStreamingCost() functions. - F32 computeRadiusWeightedTris(F32 radius); + F32 getRadiusWeightedTris(F32 radius); // Triangle count used by triangle-based cost formula. Based on // triangles in highest LOD plus potentially partial charges for // lower LODs depending on complexity. - F32 computeEstTrisForStreamingCost(); + F32 getEstTrisForStreamingCost(); // Streaming cost. This should match the server-side calculation // for the corresponding volume. - F32 computeRadiusBasedStreamingCost(F32 radius); + F32 getRadiusBasedStreamingCost(F32 radius); // New streaming cost formula, currently only used for animated objects. - F32 computeTriangleBasedStreamingCost(); + F32 getTriangleBasedStreamingCost(); + +private: + // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. + std::vector mSizeByLOD; + + // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. + std::vector mEstTrisByLOD; + + // Estimated triangle counts for the largest LOD. Typically this + // is also the "high" LOD, but not necessarily. + F32 mEstTrisMax; + + // Sum of all LOD sizes. + S32 mSizeTotal; }; class LLMeshRepository @@ -511,14 +526,13 @@ public: static LLDeadmanTimer sQuiescentTimer; // Time-to-complete-mesh-downloads after significant events - bool getLODSizes(LLSD& header, std::vector& lod_byte_sizes, std::vector& lod_tri_counts); // Estimated triangle count of the largest LOD F32 getEstTrianglesMax(LLUUID mesh_id); F32 getEstTrianglesStreamingCost(LLUUID mesh_id); - F32 getStreamingCost(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); - static F32 getStreamingCost(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + F32 getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + static F32 getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); bool getCostData(LLUUID mesh_id, LLMeshCostData& data); - bool getCostData(LLSD& header, LLUUID mesh_id, LLMeshCostData& data); + bool getCostData(LLSD& header, LLMeshCostData& data); LLMeshRepository(); diff --git a/indra/newview/llsceneview.cpp b/indra/newview/llsceneview.cpp index 112fa5b4e1..f7aa63e34d 100644 --- a/indra/newview/llsceneview.cpp +++ b/indra/newview/llsceneview.cpp @@ -33,6 +33,7 @@ #include "llviewerregion.h" #include "llagent.h" #include "llvolumemgr.h" +#include "llmeshrepository.h" LLSceneView* gSceneView = NULL; @@ -129,17 +130,23 @@ void LLSceneView::draw() visible_triangles[idx].push_back(visible); triangles[idx].push_back(high_triangles); - S32 bytes = 0; - S32 visible_bytes = 0; - - F32 streaming = object->getStreamingCost(&bytes, &visible_bytes); - total_streaming[idx] += streaming; - streaming_cost[idx].push_back(streaming); + F32 streaming = object->getStreamingCost(); + total_streaming[idx] += streaming; + streaming_cost[idx].push_back(streaming); F32 physics = object->getPhysicsCost(); total_physics[idx] += physics; physics_cost[idx].push_back(physics); + S32 bytes = 0; + S32 visible_bytes = 0; + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible_bytes = costs.getSizeByLOD(object->getLOD()); + } + total_bytes[idx] += bytes; total_visible_bytes[idx] += visible_bytes; } diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index d29a06f7e5..ce5fc7a71e 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -7252,10 +7252,16 @@ F32 LLObjectSelection::getSelectedObjectStreamingCost(S32* total_bytes, S32* vis if (object) { - S32 bytes = 0; - S32 visible = 0; - cost += object->getStreamingCost(&bytes, &visible); + cost += object->getStreamingCost(); + S32 bytes = 0; + S32 visible = 0; + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible = costs.getSizeByLOD(object->getLOD()); + } if (total_bytes) { *total_bytes += bytes; diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 72cb1d4cf6..32a1ccd852 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -106,6 +106,7 @@ #include "llvocache.h" #include "llcleanup.h" #include "llcallstack.h" +#include "llmeshrepository.h" //#define DEBUG_UPDATE_TYPE @@ -3698,11 +3699,19 @@ F32 LLViewerObject::getEstTrianglesStreamingCost() const return 0.f; } -F32 LLViewerObject::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +// virtual +F32 LLViewerObject::getStreamingCost() const { return 0.f; } +// virtual +bool LLViewerObject::getCostData(LLMeshCostData& costs) const +{ + costs = LLMeshCostData(); + return false; +} + U32 LLViewerObject::getTriangleCount(S32* vcount) const { return 0; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 2fe14c2fcf..9552d4e99e 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -68,6 +68,8 @@ class LLViewerRegion; class LLViewerTexture; class LLWorld; +class LLMeshCostData; + typedef enum e_object_update_type { OUT_FULL, @@ -366,7 +368,8 @@ public: F32 recursiveGetEstTrianglesMax() const; virtual F32 getEstTrianglesMax() const; virtual F32 getEstTrianglesStreamingCost() const; - virtual F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL, F32* unscaled_value = NULL) const; + virtual F32 getStreamingCost() const; + virtual bool getCostData(LLMeshCostData& costs) const; virtual U32 getTriangleCount(S32* vcount = NULL) const; virtual U32 getHighLODTriangleCount(); F32 recursiveGetScaledSurfaceArea() const; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index b87a6d14e5..467b0c6fcb 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -546,7 +546,14 @@ public: object_count++; S32 bytes = 0; S32 visible = 0; - cost += object->getStreamingCost(&bytes, &visible); + cost += object->getStreamingCost(); + LLMeshCostData costs; + if (object->getCostData(costs)) + { + bytes = costs.getSizeTotal(); + visible = costs.getSizeByLOD(object->getLOD()); + } + S32 vt = 0; count += object->getTriangleCount(&vt); vcount += vt; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 9db4b3de0c..88f2ba34d3 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3691,16 +3691,25 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const path_params = volume_params.getPathParams(); profile_params = volume_params.getProfileParams(); - F32 weighted_triangles = -1.0; - getStreamingCost(NULL, NULL, &weighted_triangles); - - if (weighted_triangles > 0.0) + LLMeshCostData costs; + if (getCostData(costs)) { - num_triangles = (U32)(weighted_triangles); + if (isAnimatedObject() && isRiggedMesh()) + { + // AXON Scaling here is to make animated object vs + // non-animated object ARC proportional to the + // corresponding calculations for streaming cost. + num_triangles = (ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * costs.getEstTrisForStreamingCost())/0.06; + } + else + { + F32 radius = getScale().length()*0.5f; + num_triangles = costs.getRadiusWeightedTris(radius); + } } } - if (num_triangles == 0) + if (num_triangles <= 0) { num_triangles = 4; } @@ -3888,6 +3897,14 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const shame += media_faces * ARC_MEDIA_FACE_COST; } + // AXON streaming cost for animated objects includes a fixed cost + // per linkset. Add a corresponding charge here translated into + // triangles, but not weighted by any graphics properties. + if (isAnimatedObject() && isRootEdit()) + { + shame += (ANIMATED_OBJECT_BASE_COST/0.06) * 5.0f; + } + if (shame > mRenderComplexity_current) { mRenderComplexity_current = (S32)shame; @@ -3914,33 +3931,50 @@ F32 LLVOVolume::getEstTrianglesStreamingCost() const return 0.f; } -F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const +F32 LLVOVolume::getStreamingCost() const { F32 radius = getScale().length()*0.5f; - F32 linkset_base_cost = 0.f; - if (isAnimatedObject() && isRootEdit()) + + LLMeshCostData costs; + if (getCostData(costs)) { - // Root object of an animated object has this to account for skeleton overhead. - linkset_base_cost = ANIMATED_OBJECT_BASE_COST; - } - if (isMesh()) - { - if (isAnimatedObject() && isRiggedMesh()) + if (isAnimatedObject() && isRootEdit()) + { + // Root object of an animated object has this to account for skeleton overhead. + linkset_base_cost = ANIMATED_OBJECT_BASE_COST; + } + if (isMesh()) { - if (unscaled_value) + if (isAnimatedObject() && isRiggedMesh()) { - *unscaled_value = (linkset_base_cost + ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrianglesStreamingCost())/0.06; + return linkset_base_cost + costs.getTriangleBasedStreamingCost(); + } + else + { + return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); } - return linkset_base_cost + ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * getEstTrianglesStreamingCost(); } else { - return linkset_base_cost + gMeshRepo.getStreamingCost(getVolume()->getParams().getSculptID(), radius, bytes, visible_bytes, mLOD, unscaled_value); + return linkset_base_cost + costs.getRadiusBasedStreamingCost(radius); } - } - else - { + } + else + { + return 0.f; + } +} + +// virtual +bool LLVOVolume::getCostData(LLMeshCostData& costs) const +{ + if (isMesh()) + { + return gMeshRepo.getCostData(getVolume()->getParams().getSculptID(), costs); + } + else + { LLVolume* volume = getVolume(); S32 counts[4]; LLVolume::getLoDTriangleCounts(volume->getParams(), counts); @@ -3951,8 +3985,8 @@ F32 LLVOVolume::getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_v header["medium_lod"]["size"] = counts[2] * 10; header["high_lod"]["size"] = counts[3] * 10; - return linkset_base_cost + LLMeshRepository::getStreamingCost(header, radius, NULL, NULL, -1, unscaled_value); - } + return gMeshRepo.getCostData(header, costs); + } } //static diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index f6738945d8..3ffb7c140a 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -136,8 +136,8 @@ public: U32 getRenderCost(texture_cost_t &textures) const; /*virtual*/ F32 getEstTrianglesMax() const; /*virtual*/ F32 getEstTrianglesStreamingCost() const; - F32 getStreamingCost(S32* bytes, S32* visible_bytes, F32* unscaled_value) const; - /*virtual*/ F32 getStreamingCost(S32* bytes = NULL, S32* visible_bytes = NULL) { return getStreamingCost(bytes, visible_bytes, NULL); } + /* virtual*/ F32 getStreamingCost() const; + /*virtual*/ bool getCostData(LLMeshCostData& costs) const; /*virtual*/ U32 getTriangleCount(S32* vcount = NULL) const; /*virtual*/ U32 getHighLODTriangleCount(); -- cgit v1.3