From 921087c794d5bdd1053fda4f9212dea564da53ad Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 15 Nov 2018 00:25:16 +0000 Subject: [PATCH 1/3] Auto-scaling amortisation of dynamic BB calcs This fix limits the overhead of the new dynamic BB calcs to AvatarExtentRefreshMaxPerBatch per AvatarExtentRefreshPeriodBatch frames default is 5 avatar per 4 frames. Thus a standard busy region 25 avatars would take 20 frames to refresh the BBs. --- indra/newview/app_settings/settings.xml | 22 ++++++++++++++++ indra/newview/llviewerobjectlist.cpp | 8 +++++- indra/newview/llviewerobjectlist.h | 8 +++++- indra/newview/llvoavatar.cpp | 34 ++++++++++++++++++++----- 4 files changed, 63 insertions(+), 9 deletions(-) diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 54507531e9..f5a074903a 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -3869,6 +3869,28 @@ Value 3 + AvatarExtentRefreshPeriodBatch + + Comment + how many frames do we spread over by default when refreshing extents (default is 4) + Persist + 1 + Type + S32 + Value + 4 + + AvatarExtentRefreshMaxPerBatch + + Comment + how many avatars do we want to handle in total per batch (default is 5) + Persist + 1 + Type + S32 + Value + 5 + DebugAvatarAppearanceMessage Comment diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 2e04022892..9b70d85d11 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -1001,7 +1001,9 @@ void LLViewerObjectList::update(LLAgent &agent) static std::vector idle_list; U32 idle_count = 0; - + // need avatar count for dynamic BB load balancing + mNumAvatars = 0; + // { LL_RECORD_BLOCK_TIME(FTM_IDLE_COPY); @@ -1020,6 +1022,10 @@ void LLViewerObjectList::update(LLAgent &agent) idle_list[idle_count] = objectp; } ++idle_count; +// need avatar count for dynamic BB load balancing + if (objectp->isAvatar()) + mNumAvatars++; +// } else { // There shouldn't be any NULL pointers in the list, but they have caused diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 597847278a..4bbfbbf6af 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -152,7 +152,6 @@ public: boost::signals2::connection setNewObjectCallback(new_object_callback_t cb); new_object_signal_t mNewObjectSignal; // - //////////////////////////////////////////// // // Only accessed by markDead in LLViewerObject @@ -162,6 +161,10 @@ public: S32 getOrphanParentCount() const { return (S32) mOrphanParents.size(); } S32 getOrphanCount() const { return mNumOrphans; } + // need avatar count for dynamic BB load balancing + S32 getAvatarCount() const { return mNumAvatars; } + // + void orphanize(LLViewerObject *childp, U32 parent_id, U32 ip, U32 port); void findOrphans(LLViewerObject* objectp, U32 ip, U32 port); @@ -208,6 +211,9 @@ protected: std::vector mOrphanParents; // LocalID/ip,port of orphaned objects std::vector mOrphanChildren; // UUID's of orphaned objects S32 mNumOrphans; + // need avatar count for dynamic BB load balancing + S32 mNumAvatars; + // typedef std::vector > vobj_list_t; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 48639e849a..e205d4831d 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1390,9 +1390,10 @@ static LLTrace::BlockTimerStatHandle FTM_AVATAR_EXTENT_UPDATE("Av Upd Extent"); void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) { LL_RECORD_BLOCK_TIME(FTM_AVATAR_EXTENT_UPDATE); - - S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity"); - +// not called as often as it used to be but still no harm in optimising +// S32 box_detail = gSavedSettings.getS32("AvatarBoundingBoxComplexity"); + static const LLCachedControl box_detail(gSavedSettings, "AvatarBoundingBoxComplexity"); +// // FIXME the update_min_max function used below assumes there is a // known starting point, but in general there isn't. Ideally the // box update logic should be modified to handle the no-point-yet @@ -2569,7 +2570,21 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) } // Update should be happening max once per frame. - const S32 upd_freq = 4; // force update every upd_freq frames. + // enable dynamic spreading of the BB calculations + //const S32 upd_freq = 4; // force update every upd_freq frames. + static LLCachedControl refreshPeriod(gSavedSettings, "AvatarExtentRefreshPeriodBatch"); + static LLCachedControl refreshMaxPerPeriod(gSavedSettings, "AvatarExtentRefreshMaxPerBatch"); + static S32 upd_freq = refreshPeriod; // initialise to a reasonable defauilt of 1 batch + static S32 lastRecalibrationFrame{ 0 }; + + const S32 thisFrame = LLDrawable::getCurrentFrame(); + if (thisFrame - lastRecalibrationFrame >= upd_freq) + { + // Only update at the start of a cycle. . + upd_freq = (((gObjectList.getAvatarCount() - 1) / refreshMaxPerPeriod) + 1)*refreshPeriod; + lastRecalibrationFrame = thisFrame; + } + // if ((mLastAnimExtents[0]==LLVector3())|| (mLastAnimExtents[1])==LLVector3()) { @@ -2577,7 +2592,10 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) } else { - mNeedsExtentUpdate = ((LLDrawable::getCurrentFrame()+mID.mData[0])%upd_freq==0); + // enable dynamic spreading of the BB calculations + //mNeedsExtentUpdate = ((LLDrawable::getCurrentFrame()+mID.mData[0]) % upd_freq == 0); + mNeedsExtentUpdate = ((thisFrame + mID.mData[0]) % upd_freq == 0); + // } LLScopedContextString str("avatar_idle_update " + getFullname()); @@ -10661,8 +10679,10 @@ void LLVOAvatar::updateRiggingInfo() //LL_INFOS() << "done update rig count is " << countRigInfoTab(mJointRiggingInfoTab) << LL_ENDL; //LL_DEBUGS("RigSpammish") << getFullname() << " after update rig tab:" << LL_ENDL; // Performance tweak - S32 joint_count, box_count; - showRigInfoTabExtents(this, mJointRiggingInfoTab, joint_count, box_count); + // remove debug only stuff on hot path + //S32 joint_count, box_count; + //showRigInfoTabExtents(this, mJointRiggingInfoTab, joint_count, box_count); + // //LL_DEBUGS("RigSpammish") << "uses " << joint_count << " joints " << " nonzero boxes: " << box_count << LL_ENDL; // Performance tweak } From 3af9f62d4c9fb348e47dbc94a4eee612434bafd0 Mon Sep 17 00:00:00 2001 From: Beq Date: Sun, 28 Oct 2018 20:39:49 +0000 Subject: [PATCH 2/3] Performance tweaks by reducing Matrix operations per render pass. --- indra/newview/lldrawpoolavatar.cpp | 49 +++++++++--- indra/newview/lldrawpoolavatar.h | 4 +- indra/newview/llface.h | 7 +- indra/newview/llfloatermodelpreview.cpp | 12 ++- indra/newview/llskinningutil.cpp | 100 ++++++++++++++++-------- indra/newview/llskinningutil.h | 7 +- indra/newview/llvovolume.cpp | 6 +- 7 files changed, 133 insertions(+), 52 deletions(-) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index f7f86dbf26..016ea2a637 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1864,9 +1864,13 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL; //build matrix palette - LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - U32 count = LLSkinningUtil::getMeshJointCount(skin); - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); + // per frame cache of skinning matrices + //LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + //U32 count = LLSkinningUtil::getMeshJointCount(skin); + //LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar); + U32 count = LLSkinningUtil::getMeshJointCount(skin); + auto mat = getCacheSkinningMats(face, skin, count, avatar); + // LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin); LLMatrix4a bind_shape_matrix; @@ -1902,6 +1906,23 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( } } +// cache per frame Skinning mats +LLMatrix4a* LLDrawPoolAvatar::getCacheSkinningMats(LLFace * face, const LLMeshSkinInfo* skin, U32 count, LLVOAvatar* avatar) +{ + if (LLFrameTimer::getFrameCount() != face->mLastSkinningMatCacheFrame) + { +// LL_DEBUGS("Skinning") << "Call InitSkinningMatrixPalette for @" << (U64)face << " type=[" << type << "]" << LL_ENDL; + face->mLastSkinningMatCacheFrame = LLFrameTimer::getFrameCount(); + LLSkinningUtil::initSkinningMatrixPalette(face->mSkinningMatCache, count, skin, avatar); + } + else + { +// LL_DEBUGS("Skinning") << "Avoiding InitSkinningMatrixPalette for face @" << (U64)face << " type=[" << type << "]" << LL_ENDL; + } + return face->mSkinningMatCache; +} +// + void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { if (!avatar->shouldRenderRigged()) @@ -1956,11 +1977,16 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) { if (sShaderLevel > 0) { - // upload matrix palette to shader - LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - U32 count = LLSkinningUtil::getMeshJointCount(skin); - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); + // upload matrix palette to shader + // per frame cache of skinning matrices + //LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + //U32 count = LLSkinningUtil::getMeshJointCount(skin); + //LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar); + U32 count = LLSkinningUtil::getMeshJointCount(skin); + auto mat = getCacheSkinningMats(face, skin, count, avatar); + // + stop_glerror(); F32 mp[LL_MAX_JOINTS_PER_MESH_OBJECT*12]; @@ -2152,9 +2178,14 @@ void LLDrawPoolAvatar::renderRiggedShadows(LLVOAvatar* avatar) if (sShaderLevel > 0) { // upload matrix palette to shader - LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + + // per frame cache of skinning matrices + //LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; + //U32 count = LLSkinningUtil::getMeshJointCount(skin); + //LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar); U32 count = LLSkinningUtil::getMeshJointCount(skin); - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); + auto mat = getCacheSkinningMats(face, skin, count, avatar); + // stop_glerror(); diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 5959631b85..44757d25f9 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -64,7 +64,9 @@ public: /*virtual*/ BOOL isDead(); static LLMatrix4& getModelView(); - + // per frame cache + static LLMatrix4a* getCacheSkinningMats(LLFace* face, const LLMeshSkinInfo* skin, U32 count, LLVOAvatar* avatar); + // /*virtual*/ LLDrawPool *instancePool(); /*virtual*/ S32 getNumPasses(); diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 945a44c814..27b58b98ca 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -39,6 +39,7 @@ #include "llvertexbuffer.h" #include "llviewertexture.h" #include "lldrawable.h" +#include "lljoint.h" class LLFacePool; class LLVolume; @@ -262,12 +263,16 @@ public: F32 mLastMoveTime; LLMatrix4* mTextureMatrix; LLMatrix4* mSpecMapMatrix; + // per frame matrix cache + U32 mLastSkinningMatCacheFrame; + // TODO: we could dynamically create this using count to save memory. + LLMatrix4a mSkinningMatCache[LL_MAX_JOINTS_PER_MESH_OBJECT]; + // LLMatrix4* mNormalMapMatrix; LLDrawInfo* mDrawInfo; private: LLPointer mVertexBuffer; - U32 mState; LLFacePool* mDrawPoolp; U32 mPoolType; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index c743275dc8..26692a5f8d 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -4318,12 +4318,16 @@ BOOL LLModelPreview::render() //quick 'n dirty software vertex skinning //build matrix palette - + // use Mat4a part of the caching changes, no point in using the cache itself in the preview though. + //LLMatrix4 mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - const LLMeshSkinInfo *skin = &model->mSkinInfo; + const LLMeshSkinInfo *skin = &model->mSkinInfo; U32 count = LLSkinningUtil::getMeshJointCount(skin); - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, - skin, getPreviewAvatar()); + //LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, + // skin, getPreviewAvatar()); + LLSkinningUtil::initSkinningMatrixPalette(mat, count, + skin, getPreviewAvatar()); + // LLMatrix4a bind_shape_matrix; bind_shape_matrix.loadu(skin->mBindShapeMatrix); U32 max_joints = LLSkinningUtil::getMaxJointCount(); diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 70ef135665..1789e593e0 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -128,49 +128,81 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin skin->mInvalidJointsScrubbed = true; } +// Per frame SkinningMatrix Caching +//void LLSkinningUtil::initSkinningMatrixPalette( +// LLMatrix4* mat, +// S32 count, +// const LLMeshSkinInfo* skin, +// LLVOAvatar *avatar) +//{ +// initJointNums(const_cast(skin), avatar); +// for (U32 j = 0; j < count; ++j) +// { +// LLJoint *joint = avatar->getJoint(skin->mJointNums[j]); +// if (joint) +// { +//#define MAT_USE_SSE +//#ifdef MAT_USE_SSE +// LLMatrix4a bind, world, res; +// bind.loadu(skin->mInvBindMatrix[j]); +// world.loadu(joint->getWorldMatrix()); +// matMul(bind, world, res); +// memcpy(mat[j].mMatrix, res.mMatrix, 16 * sizeof(float)); +//#else +// mat[j] = skin->mInvBindMatrix[j]; +// mat[j] *= joint->getWorldMatrix(); +//#endif +// } +// else +// { +// mat[j] = skin->mInvBindMatrix[j]; +// // This shouldn't happen - in mesh upload, skinned +// // rendering should be disabled unless all joints are +// // valid. In other cases of skinned rendering, invalid +// // joints should already have been removed during scrubInvalidJoints(). +// LL_WARNS_ONCE("Avatar") << avatar->getFullname() +// << " rigged to invalid joint name " << skin->mJointNames[j] +// << " num " << skin->mJointNums[j] << LL_ENDL; +// LL_WARNS_ONCE("Avatar") << avatar->getFullname() +// << " avatar build state: isBuilt() " << avatar->isBuilt() +// << " mInitFlags " << avatar->mInitFlags << LL_ENDL; +//#if 0 +// dump_avatar_and_skin_state("initSkinningMatrixPalette joint not found", avatar, skin); +//#endif +// } +// } +//} +static LLTrace::BlockTimerStatHandle FTM_SKINNING_INIT("Init Skinning Mats"); + void LLSkinningUtil::initSkinningMatrixPalette( - LLMatrix4* mat, + LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar) { - initJointNums(const_cast(skin), avatar); - for (U32 j = 0; j < count; ++j) +#ifndef LL_RELEASE_FOR_DOWNLOAD + // This timer is too hot for normal use (though better now with caching) + LL_RECORD_BLOCK_TIME(FTM_SKINNING_INIT); +#endif + LLMatrix4a bind[LL_MAX_JOINTS_PER_MESH_OBJECT]; + LLMatrix4a world[LL_MAX_JOINTS_PER_MESH_OBJECT]; + + initJointNums(const_cast(skin), avatar); +// TODO: Refactored to encourage the compiler to optimise better but it's too old and stubborn. Need to hand tool the SIMD. +// TODO: There are two overheads in this function casued by the unaligned loads. use Matrix4a +// TODO: getWorldMatrix forces a reverse recursion up through the skelly. Check if this is happening efficiently. + for (S32 j = 0; j < count; ++j) { LLJoint *joint = avatar->getJoint(skin->mJointNums[j]); - if (joint) - { -#define MAT_USE_SSE -#ifdef MAT_USE_SSE - LLMatrix4a bind, world, res; - bind.loadu(skin->mInvBindMatrix[j]); - world.loadu(joint->getWorldMatrix()); - matMul(bind,world,res); - memcpy(mat[j].mMatrix,res.mMatrix,16*sizeof(float)); -#else - mat[j] = skin->mInvBindMatrix[j]; - mat[j] *= joint->getWorldMatrix(); -#endif - } - else - { - mat[j] = skin->mInvBindMatrix[j]; - // This shouldn't happen - in mesh upload, skinned - // rendering should be disabled unless all joints are - // valid. In other cases of skinned rendering, invalid - // joints should already have been removed during scrubInvalidJoints(). - LL_WARNS_ONCE("Avatar") << avatar->getFullname() - << " rigged to invalid joint name " << skin->mJointNames[j] - << " num " << skin->mJointNums[j] << LL_ENDL; - LL_WARNS_ONCE("Avatar") << avatar->getFullname() - << " avatar build state: isBuilt() " << avatar->isBuilt() - << " mInitFlags " << avatar->mInitFlags << LL_ENDL; -#if 0 - dump_avatar_and_skin_state("initSkinningMatrixPalette joint not found", avatar, skin); -#endif - } + llassert_always(joint != nullptr); + + bind[j].loadu(skin->mInvBindMatrix[j]); + world[j].loadu(joint->getWorldMatrix()); + matMul(bind[j],world[j],mat[j]); +//LL_DEBUGS("Skinning") << "[" << avatar->getFullname() << "] joint(" << skin->mJointNames[j] << ") matices bind(" << bind << ") world(" << world << ")" << LL_ENDL; } } +// void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) { diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h index 104743a378..d626655abd 100644 --- a/indra/newview/llskinningutil.h +++ b/indra/newview/llskinningutil.h @@ -38,8 +38,11 @@ namespace LLSkinningUtil U32 getMaxJointCount(); U32 getMeshJointCount(const LLMeshSkinInfo *skin); void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); - void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar); - void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); + // Per frame SkinningMatrix Caching + //void initSkinningMatrixPalette(LLMatrix4* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar* avatar); + void initSkinningMatrixPalette(LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar* avatar); + // + void checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); void scrubSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin); void getPerVertexSkinMatrix(F32* weights, LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); void initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 0cb2b5adab..d083675a98 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4941,6 +4941,7 @@ static LLTrace::BlockTimerStatHandle FTM_RIGGED_OCTREE("Octree"); void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume) { + bool copy = false; if (volume->getNumVolumeFaces() != getNumVolumeFaces()) { @@ -4982,7 +4983,10 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLMatrix4a mat[kMaxJoints]; U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin); - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar); + // Skinning Matrix caching + //LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4)mat, maxJoints, skin, avatar); + LLSkinningUtil::initSkinningMatrixPalette(mat, maxJoints, skin, avatar); + // S32 rigged_vert_count = 0; S32 rigged_face_count = 0; From 35ecc970b083144c870fc29c224c61699b15a6a8 Mon Sep 17 00:00:00 2001 From: Beq Date: Thu, 15 Nov 2018 20:56:35 +0000 Subject: [PATCH 3/3] Clean up unnecessary stuff and more JointMatrix Palette caching tweaks. Move cache to drawable for more benefit. Reduces CPU overhead when rendering shadows and materials by caching the jointmatrixpallette. Sacrifices some potential cache locality but savings seem to outweigh this. --- indra/llappearance/llavatarjoint.cpp | 6 ++- indra/newview/lldrawable.cpp | 13 +++-- indra/newview/lldrawable.h | 10 +++- indra/newview/lldrawpoolavatar.cpp | 29 +++++++---- indra/newview/lldrawpoolavatar.h | 4 +- indra/newview/llface.h | 5 -- indra/newview/llskinningutil.cpp | 29 +++++++++-- indra/newview/llvovolume.cpp | 72 +++++++++++++++++++--------- indra/newview/pipeline.cpp | 8 +++- 9 files changed, 125 insertions(+), 51 deletions(-) diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp index 29642be099..381665a1d5 100644 --- a/indra/llappearance/llavatarjoint.cpp +++ b/indra/llappearance/llavatarjoint.cpp @@ -181,7 +181,11 @@ BOOL LLAvatarJoint::updateLOD(F32 pixel_area, BOOL activate) for (child_list_t::iterator iter = mChildren.begin(); iter != mChildren.end(); ++iter) { - LLAvatarJoint* joint = dynamic_cast(*iter); +// Make this s static cast. The dynamic cast must be working or it would have been crashing on the nullptr in the next line. +// LLAvatarJoint* joint = dynamic_cast(*iter); + LLAvatarJoint* joint = static_cast(*iter); +// + F32 jointLOD = joint->getLOD(); if (found_lod || jointLOD == DEFAULT_AVATAR_JOINT_LOD) diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index d0c3dafc94..46c195c47c 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -53,6 +53,7 @@ #include "llvocache.h" #include "llcontrolavatar.h" #include "lldrawpoolavatar.h" +#include "llskinningutil.h" const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f; const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; @@ -94,7 +95,10 @@ void LLDrawable::incrementVisible() LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry) : LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE), LLTrace::MemTrackable("LLDrawable"), - mVObjp(vobj) + mVObjp(vobj), + mSkinningMatCache(nullptr), + mLastSkinningMatCacheFrame(0), + mCacheSize(0) { init(new_entry); } @@ -140,7 +144,7 @@ void LLDrawable::init(bool new_entry) llassert(!vo_entry->getGroup()); //not in the object cache octree. } - + llassert(!vo_entry || vo_entry->getEntry() == mEntry); initVisible(sCurVisible - 2);//invisible for the current frame and the last frame. @@ -164,7 +168,10 @@ void LLDrawable::unload() } facep->clearState(LLFace::RIGGED); } - + // ckinning matrix caching + delete[] mSkinningMatCache; + mSkinningMatCache = nullptr; + // pVVol->markForUpdate(TRUE); } diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index c65ccb78b7..46ec3ba15d 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -66,7 +66,9 @@ class LLDrawable public: LLDrawable(const LLDrawable& rhs) : LLTrace::MemTrackable("LLDrawable"), - LLViewerOctreeEntryData(rhs) + LLViewerOctreeEntryData(rhs), + mLastSkinningMatCacheFrame(0), + mCacheSize(0) { *this = rhs; } @@ -79,6 +81,12 @@ public: static void initClass(); + // per frame matrix cache + U32 mLastSkinningMatCacheFrame; + LLMatrix4a* mSkinningMatCache; + U32 mCacheSize; + // + LLDrawable(LLViewerObject *vobj, bool new_entry = false); void markDead(); // Mark this drawable as dead diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 016ea2a637..47bcce45ac 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -1869,7 +1869,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( //U32 count = LLSkinningUtil::getMeshJointCount(skin); //LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar); U32 count = LLSkinningUtil::getMeshJointCount(skin); - auto mat = getCacheSkinningMats(face, skin, count, avatar); + auto mat = getCacheSkinningMats(drawable, skin, count, avatar); // LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin); @@ -1907,19 +1907,28 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( } // cache per frame Skinning mats -LLMatrix4a* LLDrawPoolAvatar::getCacheSkinningMats(LLFace * face, const LLMeshSkinInfo* skin, U32 count, LLVOAvatar* avatar) +LLMatrix4a* LLDrawPoolAvatar::getCacheSkinningMats(LLDrawable* drawable, const LLMeshSkinInfo* skin, + U32 count, LLVOAvatar* avatar) { - if (LLFrameTimer::getFrameCount() != face->mLastSkinningMatCacheFrame) + if (drawable->mCacheSize < count || !drawable->mSkinningMatCache) { -// LL_DEBUGS("Skinning") << "Call InitSkinningMatrixPalette for @" << (U64)face << " type=[" << type << "]" << LL_ENDL; - face->mLastSkinningMatCacheFrame = LLFrameTimer::getFrameCount(); - LLSkinningUtil::initSkinningMatrixPalette(face->mSkinningMatCache, count, skin, avatar); + delete[](drawable->mSkinningMatCache); + drawable->mCacheSize = count; + drawable->mSkinningMatCache = new LLMatrix4a[count]; + } + + if (drawable->mSkinningMatCache && LLFrameTimer::getFrameCount() != drawable->mLastSkinningMatCacheFrame) + { +// LL_DEBUGS("Skinning") << "Call InitSkinningMatrixPalette for drawable @" << (U64)drawable << LL_ENDL; + // add caching of matrix pallette as high up the stack as we can + drawable->mLastSkinningMatCacheFrame = LLFrameTimer::getFrameCount(); + LLSkinningUtil::initSkinningMatrixPalette(drawable->mSkinningMatCache, count, skin, avatar); } else { -// LL_DEBUGS("Skinning") << "Avoiding InitSkinningMatrixPalette for face @" << (U64)face << " type=[" << type << "]" << LL_ENDL; +// LL_DEBUGS("Skinning") << "Avoiding InitSkinningMatrixPalette for drawable @" << (U64)drawable << LL_ENDL; } - return face->mSkinningMatCache; + return drawable->mSkinningMatCache; } // @@ -1984,7 +1993,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) //U32 count = LLSkinningUtil::getMeshJointCount(skin); //LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar); U32 count = LLSkinningUtil::getMeshJointCount(skin); - auto mat = getCacheSkinningMats(face, skin, count, avatar); + auto mat = getCacheSkinningMats(drawable, skin, count, avatar); // stop_glerror(); @@ -2184,7 +2193,7 @@ void LLDrawPoolAvatar::renderRiggedShadows(LLVOAvatar* avatar) //U32 count = LLSkinningUtil::getMeshJointCount(skin); //LLSkinningUtil::initSkinningMatrixPalette(mat, count, skin, avatar); U32 count = LLSkinningUtil::getMeshJointCount(skin); - auto mat = getCacheSkinningMats(face, skin, count, avatar); + auto mat = getCacheSkinningMats(drawable, skin, count, avatar); // stop_glerror(); diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 44757d25f9..41bf13edfa 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -28,6 +28,7 @@ #define LL_LLDRAWPOOLAVATAR_H #include "lldrawpool.h" +#include "fsareasearch.h" class LLVOAvatar; class LLGLSLShader; @@ -65,7 +66,8 @@ public: static LLMatrix4& getModelView(); // per frame cache - static LLMatrix4a* getCacheSkinningMats(LLFace* face, const LLMeshSkinInfo* skin, U32 count, LLVOAvatar* avatar); + static LLMatrix4a* getCacheSkinningMats(LLDrawable* drawable, const LLMeshSkinInfo* skin, U32 count, + LLVOAvatar* avatar); // /*virtual*/ LLDrawPool *instancePool(); diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 27b58b98ca..993437f031 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -263,11 +263,6 @@ public: F32 mLastMoveTime; LLMatrix4* mTextureMatrix; LLMatrix4* mSpecMapMatrix; - // per frame matrix cache - U32 mLastSkinningMatCacheFrame; - // TODO: we could dynamically create this using count to save memory. - LLMatrix4a mSkinningMatCache[LL_MAX_JOINTS_PER_MESH_OBJECT]; - // LLMatrix4* mNormalMapMatrix; LLDrawInfo* mDrawInfo; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 1789e593e0..1573a77bf6 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -172,7 +172,10 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin // } // } //} -static LLTrace::BlockTimerStatHandle FTM_SKINNING_INIT("Init Skinning Mats"); + +#ifndef LL_RELEASE_FOR_DOWNLOAD +static LLTrace::BlockTimerStatHandle FTM_SKINNING_INIT("Init Skinning Mats"); +#endif void LLSkinningUtil::initSkinningMatrixPalette( LLMatrix4a* mat, @@ -194,11 +197,27 @@ void LLSkinningUtil::initSkinningMatrixPalette( for (S32 j = 0; j < count; ++j) { LLJoint *joint = avatar->getJoint(skin->mJointNums[j]); - llassert_always(joint != nullptr); + if (joint != nullptr){ + bind[j].loadu(skin->mInvBindMatrix[j]); + world[j].loadu(joint->getWorldMatrix()); + matMul(bind[j], world[j], mat[j]); + } + else + { + mat[j].loadu(skin->mInvBindMatrix[j]); + // This shouldn't happen - in mesh upload, skinned + // rendering should be disabled unless all joints are + // valid. In other cases of skinned rendering, invalid + // joints should already have been removed during scrubInvalidJoints(). + // Beq note - Oct 2018 Animesh - Many rigged meshes still fail here. ('mElbowLeeft' typo in the rigging data) + LL_WARNS_ONCE("Avatar") << avatar->getFullname() + << " rigged to invalid joint name " << skin->mJointNames[j] + << " num " << skin->mJointNums[j] << LL_ENDL; + LL_WARNS_ONCE("Avatar") << avatar->getFullname() + << " avatar build state: isBuilt() " << avatar->isBuilt() + << " mInitFlags " << avatar->mInitFlags << LL_ENDL; - bind[j].loadu(skin->mInvBindMatrix[j]); - world[j].loadu(joint->getWorldMatrix()); - matMul(bind[j],world[j],mat[j]); + } //LL_DEBUGS("Skinning") << "[" << avatar->getFullname() << "] joint(" << skin->mJointNames[j] << ") matices bind(" << bind << ") world(" << world << ")" << LL_ENDL; } } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index d083675a98..9e88ed506b 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1641,7 +1641,11 @@ BOOL LLVOVolume::updateLOD() if (lod_changed) { - if (debugLoggingEnabled("AnimatedObjectsLinkset")) + // avoid unfortunate sleep during trylock by static check + //if(debugLoggingEnabled("AnimatedObjectsLinkset")) + static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); + if (debug_logging_on) + // { if (isAnimatedObject() && isRiggedMesh()) { @@ -4615,8 +4619,12 @@ const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const void LLVOVolume::markForUpdate(BOOL priority) { - if (debugLoggingEnabled("AnimatedObjectsLinkset")) - { + // avoid unfortunate sleep during trylock by static check + //if(debugLoggingEnabled("AnimatedObjectsLinkset")) + static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); + if (debug_logging_on) + // + { if (isAnimatedObject() && isRiggedMesh()) { std::string vobj_name = llformat("Vol%p", this); @@ -5673,7 +5681,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) continue; } - std::string vobj_name = llformat("Vol%p", vobj); +// Stop doing stupid stuff we don;t need to. +// Moving this inside a debug enabled check +// std::string vobj_name = llformat("Vol%p", vobj); +// if (vobj->isMesh() && ((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled())) @@ -5687,26 +5698,37 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) const LLVector3& scale = vobj->getScale(); group->mSurfaceArea += volume->getSurfaceArea() * llmax(llmax(scale.mV[0], scale.mV[1]), scale.mV[2]); } - - bool is_mesh = vobj->isMesh(); - F32 est_tris = vobj->getEstTrianglesMax(); +// Stop doing stupid stuff we don;t need on the critical path + //bool is_mesh = vobj->isMesh(); + //F32 est_tris = vobj->getEstTrianglesMax(); vobj->updateControlAvatar(); - - LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuilding, isAttachment: " << (U32) vobj->isAttachment() - << " is_mesh " << is_mesh - << " est_tris " << est_tris - << " is_animated " << vobj->isAnimatedObject() - << " can_animate " << vobj->canBeAnimatedObject() - << " cav " << vobj->getControlAvatar() - << " lod " << vobj->getLOD() - << " drawable rigged " << (drawablep->isState(LLDrawable::RIGGED)) - << " drawable state " << drawablep->getState() - << " playing " << (U32) (vobj->getControlAvatar() ? vobj->getControlAvatar()->mPlaying : false) - << " frame " << LLFrameTimer::getFrameCount() - << LL_ENDL; + // Also avoid unfortunate sleep during trylock by static check + //if(debugLoggingEnabled("AnimatedObjectsLinkset")) + static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); + if (debug_logging_on) + // + { + std::string vobj_name = llformat("Vol%p", vobj); + bool is_mesh = vobj->isMesh(); + F32 est_tris = vobj->getEstTrianglesMax(); + + LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuilding, isAttachment: " << (U32) vobj->isAttachment() + << " is_mesh " << is_mesh + << " est_tris " << est_tris + << " is_animated " << vobj->isAnimatedObject() + << " can_animate " << vobj->canBeAnimatedObject() + << " cav " << vobj->getControlAvatar() + << " lod " << vobj->getLOD() + << " drawable rigged " << (drawablep->isState(LLDrawable::RIGGED)) + << " drawable state " << drawablep->getState() + << " playing " << (U32) (vobj->getControlAvatar() ? vobj->getControlAvatar()->mPlaying : false) + << " frame " << LLFrameTimer::getFrameCount() + << LL_ENDL; + } + // Pointless. We already checked this and have used it. + //llassert_always(vobj); - llassert_always(vobj); // Z's protection auto-derender code if (enableVolumeSAPProtection()) @@ -6246,8 +6268,12 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) { LLVOVolume* vobj = drawablep->getVOVolume(); - if (debugLoggingEnabled("AnimatedObjectsLinkset")) - { + // avoid unfortunate sleep during trylock by static check + //if(debugLoggingEnabled("AnimatedObjectsLinkset")) + static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); + if (debug_logging_on) + // + { if (vobj->isAnimatedObject() && vobj->isRiggedMesh()) { std::string vobj_name = llformat("Vol%p", vobj); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 24074386e7..8c7fc16023 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -3480,8 +3480,12 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f { if (drawablep && !drawablep->isDead() && assertInitialized()) { - if (debugLoggingEnabled("AnimatedObjectsLinkset")) - { + // avoid unfortunate sleep during trylock by static check + //if(debugLoggingEnabled("AnimatedObjectsLinkset")) + static auto debug_logging_on = debugLoggingEnabled("AnimatedObjectsLinkset"); + if (debug_logging_on) + // + { LLVOVolume *vol_obj = drawablep->getVOVolume(); if (vol_obj && vol_obj->isAnimatedObject() && vol_obj->isRiggedMesh()) {