From f23f28c8f9ccc36e8f70beb63b58b3114246a09c Mon Sep 17 00:00:00 2001 From: Cosmic Linden Date: Wed, 28 Aug 2024 15:59:03 -0700 Subject: secondlife/viewer#2421: Do not calculate and store silhouette edges for nearly every geometric prim with a corner --- indra/llmath/llvolume.cpp | 415 ++++++++++++++++++++++++++-------------------- indra/llmath/llvolume.h | 15 +- 2 files changed, 246 insertions(+), 184 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 56ac22ca18..700e61467b 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -2710,7 +2710,7 @@ bool LLVolume::unpackVolumeFacesInternal(const LLSD& mdl) } -bool LLVolume::isMeshAssetLoaded() +bool LLVolume::isMeshAssetLoaded() const { return mIsMeshAssetLoaded; } @@ -2733,7 +2733,7 @@ void LLVolume::setMeshAssetUnavaliable(bool unavaliable) } } -bool LLVolume::isMeshAssetUnavaliable() +bool LLVolume::isMeshAssetUnavaliable() const { return mIsMeshAssetUnavaliable; } @@ -3730,6 +3730,207 @@ S32 LLVolume::getNumTriangles(S32* vcount) const return triangle_count; } +void LLVolumeFace::generateSilhouetteEdge(const LLVolume* volume, std::vector& edge) const +{ + llassert(edge.empty()); // edge is supposed to be a scratch array + + if (volume->isMeshAssetLoaded()) { return; } + + if (mTypeMask & CAP_MASK) + { + // Logic copied from LLVolumeFace::createCap - indicates a face created via + // createUnCutCubeCap. + if (!(mTypeMask & HOLLOW_MASK) && + !(mTypeMask & OPEN_MASK) && + ((volume->getParams().getPathParams().getBegin()==0.0f)&& + (volume->getParams().getPathParams().getEnd()==1.0f))&& + (volume->getParams().getProfileParams().getCurveType()==LL_PCODE_PROFILE_SQUARE && + volume->getParams().getPathParams().getCurveType()==LL_PCODE_PATH_LINE) + ) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfgse - CAP_MASK"); + + const LLAlignedArray& profile = volume->getProfile().mProfile; + S32 grid_size = (profile.size()-1)/4; + edge.resize(mNumIndices); + llassert(edge.size() == 6*grid_size*grid_size); + + S32 cur_edge = 0; + for(S32 gx = 0;gx 0) + { + edge[cur_edge++] = edge_value; + } + else + { + edge[cur_edge++] = -1; // Mark face to higlight it + } + + if (gy < grid_size - 1) + { + edge[cur_edge++] = edge_value; + } + else + { + edge[cur_edge++] = -1; + } + + edge[cur_edge++] = edge_value; + + if (gx < grid_size - 1) + { + edge[cur_edge++] = edge_value; + } + else + { + edge[cur_edge++] = -1; + } + + if (gy > 0) + { + edge[cur_edge++] = edge_value; + } + else + { + edge[cur_edge++] = -1; + } + + edge[cur_edge++] = edge_value; + } + else + { + S32 edge_value = grid_size * 2 * gy + gx * 2; + + if (gy > 0) + { + edge[cur_edge++] = edge_value; + } + else + { + edge[cur_edge++] = -1; + } + + if (gx < grid_size - 1) + { + edge[cur_edge++] = edge_value; + } + else + { + edge[cur_edge++] = -1; + } + + edge[cur_edge++] = edge_value; + + if (gy < grid_size - 1) + { + edge[cur_edge++] = edge_value; + } + else + { + edge[cur_edge++] = -1; + } + + if (gx > 0) + { + edge[cur_edge++] = edge_value; + } + else + { + edge[cur_edge++] = -1; + } + + edge[cur_edge++] = edge_value; + } + } + } + } + } + else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK)) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfgse - END_MASK or SIDE_MASK"); + + edge.resize(mNumIndices); + llassert(edge.size() == 6*(mNumS-1)*(mNumT-1)); + + S32 cur_edge = 0; + const bool flat_face = mTypeMask & FLAT_MASK; + for (S32 t = 0; t < (mNumT-1); t++) + { + for (S32 s = 0; s < (mNumS-1); s++) + { + // bottom left/top right neighbor face + edge[cur_edge++] = (mNumS-1)*2*t+s*2+1; + + if (t < mNumT-2) + { // top right/top left neighbor face + edge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; + } + else if (mNumT <= 3 || volume->getPath().isOpen()) + { // no neighbor + edge[cur_edge++] = -1; + } + else + { // wrap on T + edge[cur_edge++] = s*2+1; + } + + if (s > 0) + { // top left/bottom left neighbor face + edge[cur_edge++] = (mNumS-1)*2*t+s*2-1; + } + else if (flat_face || volume->getProfile().isOpen()) + { // no neighbor + edge[cur_edge++] = -1; + } + else + { // wrap on S + edge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1; + } + + if (t > 0) + { // bottom left/bottom right neighbor face + edge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; + } + else if (mNumT <= 3 || volume->getPath().isOpen()) + { // no neighbor + edge[cur_edge++] = -1; + } + else + { // wrap on T + edge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2; + } + + if (s < mNumS-2) + { // bottom right/top right neighbor face + edge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; + } + else if (flat_face || volume->getProfile().isOpen()) + { // no neighbor + edge[cur_edge++] = -1; + } + else + { // wrap on S + edge[cur_edge++] = (mNumS-1)*2*t; + } + + // top right/bottom left neighbor face + edge[cur_edge++] = (mNumS-1)*2*t+s*2; + } + } + } + else + { + LL_ERRS() << "Unknown/uninitialized face type!" << LL_ENDL; + } +} //----------------------------------------------------------------------------- // generateSilhouetteVertices() @@ -3761,6 +3962,13 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, } S32 cur_index = 0; + // Scratch array for per-face silhouette edge information. This also has a + // lot of dev-only debug information that we might not care about anymore. + // (see DEBUG_SILHOUETTE_EDGE_MAP) + // *TODO: Consider removing the debug associated with + // DEBUG_SILHOUETTE_EDGE_MAP, and remove its associated computational + // overhead in generateSilhouetteEdge. + std::vector edge; //for each face for (face_list_t::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); ++iter) @@ -3768,7 +3976,16 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, LLVolumeFace& face = *iter; if (!(face_mask & (0x1 << cur_index++)) || - face.mNumIndices == 0 || face.mEdge.empty()) + face.mNumIndices == 0) + { + continue; + } + // Attempt to generate "edge" info for this silhouette, which is used + // for some prims. If the edge array remains empty, then this + // silhouette generation method is not supported for this face. + edge.clear(); + face.generateSilhouetteEdge(this, edge); + if (edge.empty()) { continue; } @@ -3782,7 +3999,7 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, { for (S32 k = 0; k < 3; k++) { - S32 index = face.mEdge[j * 3 + k]; + S32 index = edge[j * 3 + k]; if (index == -1) { @@ -3834,7 +4051,7 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, //for each edge for (S32 k = 0; k < 3; k++) { - S32 nIndex = face.mEdge[j*3+k]; + S32 nIndex = edge[j*3+k]; if (nIndex <= -1) { continue; } @@ -3949,7 +4166,7 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, // *FIX IF NEEDED: this does not deal with neighboring degenerate faces for (S32 k = 0; k < 3; k++) { - S32 index = face.mEdge[j*3+k]; + S32 index = edge[j*3+k]; if (index != -1) { fFacing[j] = fFacing[index]; @@ -3961,10 +4178,10 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, //for each edge for (S32 k = 0; k < 3; k++) { - S32 index = face.mEdge[j*3+k]; + S32 index = edge[j*3+k]; if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) { //our neighbor is degenerate, make him face our direction - fFacing[face.mEdge[j*3+k]] = fFacing[j]; + fFacing[edge[j*3+k]] = fFacing[j]; continue; } @@ -5775,30 +5992,16 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build) if (!partial_build) { + LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcuccm - generate indices"); + resizeIndices(grid_size*grid_size*6); - if (!volume->isMeshAssetLoaded()) - { - S32 size = grid_size * grid_size * 6; - try - { - mEdge.resize(size); - } - catch (std::bad_alloc&) - { - LL_WARNS("LLVOLUME") << "Resize of mEdge to " << size << " failed" << LL_ENDL; - return false; - } - } U16* out = mIndices; S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0}; - int cur_edge = 0; - for(S32 gx = 0;gx 0) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; // Mark face to higlight it - } - - if (gy < grid_size - 1) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - mEdge[cur_edge++] = edge_value; - - if (gx < grid_size - 1) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - if (gy > 0) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - mEdge[cur_edge++] = edge_value; } else { @@ -5856,48 +6018,6 @@ bool LLVolumeFace::createUnCutCubeCap(LLVolume* volume, bool partial_build) { *out++ = ((gy*(grid_size+1))+gx+idxs[i]); } - - S32 edge_value = grid_size * 2 * gy + gx * 2; - - if (gy > 0) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - if (gx < grid_size - 1) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - mEdge[cur_edge++] = edge_value; - - if (gy < grid_size - 1) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - if (gx > 0) - { - mEdge[cur_edge++] = edge_value; - } - else - { - mEdge[cur_edge++] = -1; - } - - mEdge[cur_edge++] = edge_value; } } } @@ -6377,6 +6497,8 @@ void LLVolumeFace::createTangents() void LLVolumeFace::resizeVertices(S32 num_verts) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + ll_aligned_free<64>(mPositions); //DO NOT free mNormals and mTexCoords as they are part of mPositions buffer ll_aligned_free_16(mTangents); @@ -6499,6 +6621,8 @@ void LLVolumeFace::allocateJointIndices(S32 num_verts) void LLVolumeFace::resizeIndices(S32 num_indices) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + ll_aligned_free_16(mIndices); llassert(num_indices % 3 == 0); @@ -6591,19 +6715,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) { resizeVertices(num_vertices); resizeIndices(num_indices); - - if (!volume->isMeshAssetLoaded()) - { - try - { - mEdge.resize(num_indices); - } - catch (std::bad_alloc&) - { - LL_WARNS("LLVOLUME") << "Resize of mEdge to " << num_indices << " failed" << LL_ENDL; - return false; - } - } } LL_CHECK_MEMORY @@ -6618,6 +6729,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) bool test = (mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2; // Copy the vertices into the array + { LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcs - copy verts"); for (t = mBeginT; t < end_t; t++) { tt = path_data[t].mTexT; @@ -6702,6 +6814,7 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) cur_vertex++; } } + } LL_CHECK_MEMORY mCenter->clear(); @@ -6755,11 +6868,11 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) mCenter->mul(0.5f); S32 cur_index = 0; - S32 cur_edge = 0; - bool flat_face = mTypeMask & FLAT_MASK; if (!partial_build) { + LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("llvfcs - generate indices"); + // Now we generate the indices. for (t = 0; t < (mNumT-1); t++) { @@ -6771,64 +6884,6 @@ bool LLVolumeFace::createSide(LLVolume* volume, bool partial_build) mIndices[cur_index++] = s + mNumS*t; //bottom left mIndices[cur_index++] = s+1 + mNumS*t; //bottom right mIndices[cur_index++] = s+1 + mNumS*(t+1); //top right - - // bottom left/top right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1; - - if (t < mNumT-2) - { // top right/top left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1; - } - else if (mNumT <= 3 || volume->getPath().isOpen()) - { // no neighbor - mEdge[cur_edge++] = -1; - } - else - { // wrap on T - mEdge[cur_edge++] = s*2+1; - } - - if (s > 0) - { // top left/bottom left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2-1; - } - else if (flat_face || volume->getProfile().isOpen()) - { // no neighbor - mEdge[cur_edge++] = -1; - } - else - { // wrap on S - mEdge[cur_edge++] = (mNumS-1)*2*t+(mNumS-2)*2+1; - } - - if (t > 0) - { // bottom left/bottom right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*(t-1)+s*2; - } - else if (mNumT <= 3 || volume->getPath().isOpen()) - { // no neighbor - mEdge[cur_edge++] = -1; - } - else - { // wrap on T - mEdge[cur_edge++] = (mNumS-1)*2*(mNumT-2)+s*2; - } - - if (s < mNumS-2) - { // bottom right/top right neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+(s+1)*2; - } - else if (flat_face || volume->getProfile().isOpen()) - { // no neighbor - mEdge[cur_edge++] = -1; - } - else - { // wrap on S - mEdge[cur_edge++] = (mNumS-1)*2*t; - } - - // top right/bottom left neighbor face - mEdge[cur_edge++] = (mNumS-1)*2*t+s*2; } } } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index bbb2a16b0b..27c5fc5a49 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -918,6 +918,15 @@ public: // Get a reference to the octree, which may be null const LLVolumeOctree* getOctree() const; + // Part of silhouette generation (used by selection outlines) + // Populates the provided edge array with numbers corresponding to + // *partial* logic of whether a particular index should be rendered + // as a silhouette edge. -1 indicates the index should be rendered as a + // silhouette edge. See generateSilhouetteVertices for the full logic. + // Silhouette edges can only be generated for some types of prims. If a + // silhouette edge cannot be generated, the edge array will be left empty. + void generateSilhouetteEdge(const LLVolume* volume, std::vector& edge) const; + enum { SINGLE_MASK = 0x0001, @@ -963,8 +972,6 @@ public: // indexes for mPositions/mNormals/mTexCoords U16* mIndices; - std::vector mEdge; - //list of skin weights for rigged volumes // format is mWeights[vertex_index].mV[influence] = . // mWeights.size() should be empty or match mVertices.size() @@ -1113,9 +1120,9 @@ private: public: virtual void setMeshAssetLoaded(bool loaded); - virtual bool isMeshAssetLoaded(); + virtual bool isMeshAssetLoaded() const; virtual void setMeshAssetUnavaliable(bool unavaliable); - virtual bool isMeshAssetUnavaliable(); + virtual bool isMeshAssetUnavaliable() const; protected: bool mUnique; -- cgit v1.3 From 74205607b7e106f3b7566ef4a4b9c2fcdfa2f83e Mon Sep 17 00:00:00 2001 From: Ansariel Hiller Date: Fri, 13 Sep 2024 16:28:48 +0200 Subject: Clean up Windows build (#2562) * APR_DECLARE_STATIC and APU_DECLARE_STATIC gets already defined in APR.cmake * Move both _CRT_SECURE_NO_WARNINGS and _WINSOCK_DEPRECATED_NO_WARNINGS definitions to 00-Common.cmake * Always define WIN32_LEAN_AND_MEAN and include subset of Windows API by default * Remove llwin32headerslean.h and remove unnecessary WIN32_LEAN_AND_MEAN definition handling in llwin32headers.h * Clean up includes of Windows API headers * Get rid of workaround to link against IPHLPAPI.lib in lluuid.cpp - this seems to have been an issue in the past that has been fixed --- indra/cmake/00-Common.cmake | 12 +++++------ indra/llcommon/CMakeLists.txt | 1 - indra/llcommon/llapr.h | 2 +- indra/llcommon/llfile.cpp | 2 +- indra/llcommon/llpreprocessor.h | 16 -------------- indra/llcommon/llprocess.h | 3 +-- indra/llcommon/llprocessor.cpp | 2 +- indra/llcommon/llsdutil.cpp | 3 +-- indra/llcommon/llstacktrace.cpp | 2 +- indra/llcommon/llstring.cpp | 3 +-- indra/llcommon/llsys.cpp | 2 +- indra/llcommon/lltimer.cpp | 2 +- indra/llcommon/lluuid.cpp | 3 --- indra/llcommon/llwin32headers.h | 11 ++-------- indra/llcommon/llwin32headerslean.h | 40 ----------------------------------- indra/llmath/llsdutil_math.cpp | 3 +-- indra/llmessage/llhost.cpp | 3 +-- indra/llmessage/lliopipe.h | 2 +- indra/llmessage/lliosocket.h | 2 +- indra/llmessage/llmail.cpp | 1 - indra/llmessage/net.cpp | 2 +- indra/llrender/llglheaders.h | 2 +- indra/llwindow/lldragdropwin32.h | 4 ++-- indra/llwindow/llkeyboardwin32.cpp | 2 +- indra/llwindow/llwindowwin32.h | 2 +- indra/newview/lldirpicker.cpp | 2 +- indra/newview/llsecapi.h | 2 +- indra/newview/llwindebug.h | 2 +- indra/newview/llxmlrpctransaction.cpp | 2 +- 29 files changed, 31 insertions(+), 104 deletions(-) delete mode 100644 indra/llcommon/llwin32headerslean.h (limited to 'indra/llmath') diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index 5087c308ee..39f26ced5d 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -68,9 +68,12 @@ if (WINDOWS) /NODEFAULTLIB:LIBCMT /IGNORE:4099) - add_definitions( - -DNOMINMAX -# /DDOM_DYNAMIC # For shared library colladadom + add_compile_definitions( + WIN32_LEAN_AND_MEAN + NOMINMAX +# DOM_DYNAMIC # For shared library colladadom + _CRT_SECURE_NO_WARNINGS # Allow use of sprintf etc + _WINSOCK_DEPRECATED_NO_WARNINGS # Disable deprecated WinSock API warnings ) add_compile_options( /Zo @@ -106,9 +109,6 @@ if (WINDOWS) string(REPLACE "/Zi" "/Z7" CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") endif() - - # Allow use of sprintf etc - add_compile_definitions(_CRT_SECURE_NO_WARNINGS) endif (WINDOWS) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 437b8d0168..60549d9d11 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -240,7 +240,6 @@ set(llcommon_HEADER_FILES lluriparser.h lluuid.h llwin32headers.h - llwin32headerslean.h llworkerthread.h hbxxh.h lockstatic.h diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 00ff4d60b7..693cd7c01f 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -34,7 +34,7 @@ #endif #include -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include "apr_thread_proc.h" #include "apr_getopt.h" #include "apr_signal.h" diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index ed94ef21ef..d0bc8f7652 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -34,7 +34,7 @@ #include "stringize.h" #if LL_WINDOWS -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include // Windows errno #include #else diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index a528cc7fd8..b499a9ce10 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -98,15 +98,6 @@ # define LL_THREAD_LOCAL __thread #endif -// Static linking with apr on windows needs to be declared. -#if LL_WINDOWS && !LL_COMMON_LINK_SHARED -#ifndef APR_DECLARE_STATIC -#define APR_DECLARE_STATIC // For APR on Windows -#endif -#ifndef APU_DECLARE_STATIC -#define APU_DECLARE_STATIC // For APR util on Windows -#endif -#endif #if defined(LL_WINDOWS) #define BOOST_REGEX_NO_LIB 1 @@ -119,13 +110,6 @@ // Deal with VC++ problems #if LL_MSVC -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS // disable warnings for methods considered unsafe -#endif -#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS -#define _WINSOCK_DEPRECATED_NO_WARNINGS // disable deprecated WinSock API warnings -#endif - // level 4 warnings that we need to disable: #pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class #pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index 39ed29c1b4..cc2d6566fc 100644 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -29,7 +29,6 @@ #include "llinitparam.h" #include "llsdparam.h" -#include "llwin32headerslean.h" #include "llexception.h" #include "apr_thread_proc.h" #include @@ -38,7 +37,7 @@ #include // std::ostream #if LL_WINDOWS -#include "llwin32headerslean.h" // for HANDLE +#include "llwin32headers.h" // for HANDLE #elif LL_LINUX #if defined(Status) #undef Status diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 9d53b9be35..41ff369de2 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -34,7 +34,7 @@ //#include #if LL_WINDOWS -# include "llwin32headerslean.h" +# include "llwin32headers.h" # define _interlockedbittestandset _renamed_interlockedbittestandset # define _interlockedbittestandreset _renamed_interlockedbittestandreset # include diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 12f67208c1..dbd89118c9 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -32,8 +32,7 @@ #include #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include // for htonl +# include "llwin32headers.h" // for htonl #elif LL_LINUX # include #elif LL_DARWIN diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index ca8f4299d9..c223c26bb0 100644 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -32,7 +32,7 @@ #include #include -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 2c40ff3efd..07adf71d18 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -33,8 +33,7 @@ #include #if LL_WINDOWS -#include "llwin32headerslean.h" -#include // for WideCharToMultiByte +#include "llwin32headers.h" #endif std::string ll_safe_string(const char* in) diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 79625ad9f8..3f33ad61c5 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -59,7 +59,7 @@ using namespace llsd; #if LL_WINDOWS -# include "llwin32headerslean.h" +# include "llwin32headers.h" # include // GetPerformanceInfo() et al. # include #elif LL_DARWIN diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 28d6e4e4cc..f36d223100 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -34,7 +34,7 @@ #include #if LL_WINDOWS -# include "llwin32headerslean.h" +# include "llwin32headers.h" #elif LL_LINUX || LL_DARWIN # include # include diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 7aeabc3c4a..b9bd27aa17 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -25,11 +25,8 @@ #include "linden_common.h" - // We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes. #if LL_WINDOWS #include "llwin32headers.h" -// ugh, this is ugly. We need to straighten out our linking for this library -#pragma comment(lib, "IPHLPAPI.lib") #include #include #endif diff --git a/indra/llcommon/llwin32headers.h b/indra/llcommon/llwin32headers.h index f679adc200..df433deb7a 100644 --- a/indra/llcommon/llwin32headers.h +++ b/indra/llcommon/llwin32headers.h @@ -28,15 +28,8 @@ #define LL_LLWINDOWS_H #ifdef LL_WINDOWS -#ifndef NOMINMAX -#define NOMINMAX -#endif -#undef WIN32_LEAN_AND_MEAN -#include -#include -// reset to default, which is lean -#define WIN32_LEAN_AND_MEAN -#undef NOMINMAX +#include // Does not include winsock.h because WIN32_LEAN_AND_MEAN is defined +#include // Requires windows.h #endif #endif diff --git a/indra/llcommon/llwin32headerslean.h b/indra/llcommon/llwin32headerslean.h deleted file mode 100644 index 97c8edb8cf..0000000000 --- a/indra/llcommon/llwin32headerslean.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file llwin32headerslean.h - * @brief sanitized include of windows header files - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLWINDOWS_H -#define LL_LLWINDOWS_H - -#ifdef LL_WINDOWS -#ifndef NOMINMAX -#define NOMINMAX -#endif -#define WIN32_LEAN_AND_MEAN -#include -#include -#undef NOMINMAX -#endif - -#endif diff --git a/indra/llmath/llsdutil_math.cpp b/indra/llmath/llsdutil_math.cpp index 0ea1a9c77a..2d5ec7d510 100644 --- a/indra/llmath/llsdutil_math.cpp +++ b/indra/llmath/llsdutil_math.cpp @@ -38,8 +38,7 @@ #include "v4color.h" #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include // for htonl +# include "llwin32headers.h" // for htonl #elif LL_LINUX # include #elif LL_DARWIN diff --git a/indra/llmessage/llhost.cpp b/indra/llmessage/llhost.cpp index ace316512f..e7e3e27f58 100644 --- a/indra/llmessage/llhost.cpp +++ b/indra/llmessage/llhost.cpp @@ -31,8 +31,7 @@ #include "llerror.h" #if LL_WINDOWS - #define WIN32_LEAN_AND_MEAN - #include + #include #else #include #include // ntonl() diff --git a/indra/llmessage/lliopipe.h b/indra/llmessage/lliopipe.h index 1887b5cd9a..b40539f38c 100644 --- a/indra/llmessage/lliopipe.h +++ b/indra/llmessage/lliopipe.h @@ -30,7 +30,7 @@ #define LL_LLIOPIPE_H #include -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include "apr_poll.h" #include "llsd.h" diff --git a/indra/llmessage/lliosocket.h b/indra/llmessage/lliosocket.h index 0a3f2617e6..4b79c77b56 100644 --- a/indra/llmessage/lliosocket.h +++ b/indra/llmessage/lliosocket.h @@ -38,7 +38,7 @@ */ #include "lliopipe.h" -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include "apr_pools.h" #include "apr_network_io.h" #include "llchainio.h" diff --git a/indra/llmessage/llmail.cpp b/indra/llmessage/llmail.cpp index 9e10a356db..b842aeda62 100644 --- a/indra/llmessage/llmail.cpp +++ b/indra/llmessage/llmail.cpp @@ -28,7 +28,6 @@ #include "llmail.h" -// APR on Windows needs full windows headers #include "llwin32headers.h" #include #include diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp index 1c49f9be36..f153c938cf 100644 --- a/indra/llmessage/net.cpp +++ b/indra/llmessage/net.cpp @@ -32,7 +32,7 @@ #include #if LL_WINDOWS -#include "llwin32headerslean.h" +#include "llwin32headers.h" #else #include #include diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index c5e1ff3e23..3d4dc5e698 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -46,7 +46,7 @@ // LL_WINDOWS // windows gl headers depend on things like APIENTRY, so include windows. -#include "llwin32headerslean.h" +#include "llwin32headers.h" //---------------------------------------------------------------------------- #include diff --git a/indra/llwindow/lldragdropwin32.h b/indra/llwindow/lldragdropwin32.h index 1b30dced27..16d016677b 100644 --- a/indra/llwindow/lldragdropwin32.h +++ b/indra/llwindow/lldragdropwin32.h @@ -31,7 +31,7 @@ #ifndef LL_LLDRAGDROP32_H #define LL_LLDRAGDROP32_H -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include class LLDragDropWin32 @@ -54,7 +54,7 @@ class LLDragDropWin32 #ifndef LL_LLDRAGDROP32_H #define LL_LLDRAGDROP32_H -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include // impostor class that does nothing diff --git a/indra/llwindow/llkeyboardwin32.cpp b/indra/llwindow/llkeyboardwin32.cpp index ec0055fe60..8d6b8d9b93 100644 --- a/indra/llwindow/llkeyboardwin32.cpp +++ b/indra/llwindow/llkeyboardwin32.cpp @@ -28,7 +28,7 @@ #include "linden_common.h" -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include "llkeyboardwin32.h" #include "llwindowcallbacks.h" diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 287402faa0..36e89e4586 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -28,7 +28,7 @@ #define LL_LLWINDOWWIN32_H // Limit Windows API to small and manageable set. -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include "llwindow.h" #include "llwindowcallbacks.h" diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 1423ca1b9b..e967ff3df2 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -35,7 +35,7 @@ #include "lltrans.h" #include "llwindow.h" // beforeDialog() #include "llviewercontrol.h" -#include "llwin32headerslean.h" +#include "llwin32headers.h" #if LL_LINUX || LL_DARWIN # include "llfilepicker.h" diff --git a/indra/newview/llsecapi.h b/indra/newview/llsecapi.h index ceea11cc34..14dda20225 100644 --- a/indra/newview/llsecapi.h +++ b/indra/newview/llsecapi.h @@ -28,7 +28,7 @@ #ifndef LLSECAPI_H #define LLSECAPI_H #include -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include #include #include "llpointer.h" diff --git a/indra/newview/llwindebug.h b/indra/newview/llwindebug.h index 770584c88d..11b50e3327 100644 --- a/indra/newview/llwindebug.h +++ b/indra/newview/llwindebug.h @@ -28,7 +28,7 @@ #define LL_LLWINDEBUG_H #include "stdtypes.h" -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include diff --git a/indra/newview/llxmlrpctransaction.cpp b/indra/newview/llxmlrpctransaction.cpp index 48461241a2..07e2b118d3 100644 --- a/indra/newview/llxmlrpctransaction.cpp +++ b/indra/newview/llxmlrpctransaction.cpp @@ -26,7 +26,7 @@ #include "llviewerprecompiledheaders.h" // include this to get winsock2 because openssl attempts to include winsock1 -#include "llwin32headerslean.h" +#include "llwin32headers.h" #include #include #include "llsecapi.h" -- cgit v1.3 From 486613e79bb96b838121f627ef73b1293ee18c12 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 16 Sep 2024 18:49:03 -0500 Subject: Profile guided optimization pass (#2582) - Tune up LLJointRiggingInfoTab - Visualize joint bounding boxes when visualizing joints - Use LLJointRiggingInfo to caclulate desired resolution of a texture - Throttle calls to calcPixelArea - Fetch MeshSkinInfo immediately when header is received --- indra/llmath/llrigginginfo.h | 4 ++ indra/llprimitive/llmodel.cpp | 7 +++ indra/llprimitive/llmodel.h | 5 +- indra/llrender/llrendersphere.cpp | 62 ++++++++++++++++---- indra/llrender/llrendersphere.h | 1 + indra/llrender/llvertexbuffer.cpp | 2 - indra/newview/llface.cpp | 79 ++++++++++++++++++++++--- indra/newview/llface.h | 13 +++++ indra/newview/llmeshrepository.cpp | 88 ++++++++++++++++++++++------ indra/newview/llmeshrepository.h | 19 ++++-- indra/newview/llskinningutil.cpp | 43 ++------------ indra/newview/llviewerobject.cpp | 1 + indra/newview/llvoavatar.cpp | 116 +++++++++++++++++++++++++++++++++---- indra/newview/llvoavatar.h | 2 +- indra/newview/llvovolume.cpp | 6 +- 15 files changed, 345 insertions(+), 103 deletions(-) (limited to 'indra/llmath') diff --git a/indra/llmath/llrigginginfo.h b/indra/llmath/llrigginginfo.h index fb550d013f..d761af68b1 100644 --- a/indra/llmath/llrigginginfo.h +++ b/indra/llmath/llrigginginfo.h @@ -66,6 +66,10 @@ public: const LLJointRiggingInfo& operator[](S32 i) const { return mRigInfoPtr[i]; }; bool needsUpdate() { return mNeedsUpdate; } void setNeedsUpdate(bool val) { mNeedsUpdate = val; } + + LLJointRiggingInfo* begin() { return mRigInfoPtr; } + LLJointRiggingInfo* end() { return mRigInfoPtr + mSize; } + private: // Not implemented LLJointRiggingInfoTab& operator=(const LLJointRiggingInfoTab& src); diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 15087a7255..9908a155f2 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -1547,6 +1547,13 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) mLockScaleIfJointPosition = false; } + // combine mBindShapeMatrix and mInvBindMatrix into mBindPoseMatrix + mBindPoseMatrix.resize(mInvBindMatrix.size()); + for (U32 i = 0; i < mInvBindMatrix.size(); ++i) + { + matMul(mBindShapeMatrix, mInvBindMatrix[i], mBindPoseMatrix[i]); + } + updateHash(); } diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index b0cba2d655..96cfb7151e 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -56,12 +56,15 @@ public: LLUUID mMeshID; std::vector mJointNames; mutable std::vector mJointNums; - typedef std::vector> matrix_list_t; + typedef std::vector matrix_list_t; matrix_list_t mInvBindMatrix; // bones/joints position overrides matrix_list_t mAlternateBindMatrix; + // cached multiply of mBindShapeMatrix and mInvBindMatrix + matrix_list_t mBindPoseMatrix; + LL_ALIGN_16(LLMatrix4a mBindShapeMatrix); float mPelvisOffset; diff --git a/indra/llrender/llrendersphere.cpp b/indra/llrender/llrendersphere.cpp index 9570180554..cd8ef7d68e 100644 --- a/indra/llrender/llrendersphere.cpp +++ b/indra/llrender/llrendersphere.cpp @@ -34,6 +34,8 @@ #include "llerror.h" #include "llglheaders.h" +#include "llvertexbuffer.h" +#include "llglslshader.h" LLRenderSphere gSphere; @@ -53,12 +55,20 @@ inline LLVector3 polar_to_cart(F32 latitude, F32 longitude) void LLRenderSphere::renderGGL() { + LL_PROFILE_ZONE_SCOPED; S32 const LATITUDE_SLICES = 20; S32 const LONGITUDE_SLICES = 30; - if (mSpherePoints.empty()) + if (mVertexBuffer.isNull()) { mSpherePoints.resize(LATITUDE_SLICES + 1); + mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX); + + mVertexBuffer->allocateBuffer((U32)(LATITUDE_SLICES + 1) * (LONGITUDE_SLICES + 1), LATITUDE_SLICES * LONGITUDE_SLICES * 6); + + LLStrider v; + mVertexBuffer->getVertexStrider(v); + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES + 1; lat_i++) { mSpherePoints[lat_i].resize(LONGITUDE_SLICES + 1); @@ -68,24 +78,52 @@ void LLRenderSphere::renderGGL() F32 lon = (F32)lon_i / LONGITUDE_SLICES; mSpherePoints[lat_i][lon_i] = polar_to_cart(lat, lon); + v[lat_i * (LONGITUDE_SLICES + 1) + lon_i] = mSpherePoints[lat_i][lon_i]; } } + + LLStrider i; + mVertexBuffer->getIndexStrider(i); + + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++) + { + for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++) + { + i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 0] = lat_i * (LONGITUDE_SLICES + 1) + lon_i; + i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 1] = lat_i * (LONGITUDE_SLICES + 1) + lon_i + 1; + i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 2] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i; + + i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 3] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i; + i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 4] = lat_i * (LONGITUDE_SLICES + 1) + lon_i + 1; + i[(lat_i * LONGITUDE_SLICES + lon_i) * 6 + 5] = (lat_i + 1) * (LONGITUDE_SLICES + 1) + lon_i + 1; + } + } + + mVertexBuffer->unmapBuffer(); } - gGL.begin(LLRender::TRIANGLES); - for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++) - { - for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++) + if (LLGLSLShader::sCurBoundShaderPtr->mAttributeMask == LLVertexBuffer::MAP_VERTEX) + { // shader expects only vertex positions in vertex buffer, use fast path + mVertexBuffer->setBuffer(); + mVertexBuffer->drawRange(LLRender::TRIANGLES, 0, mVertexBuffer->getNumVerts(), mVertexBuffer->getNumIndices(), 0); + } + else + { //shader wants colors in the vertex stream, use slow path + gGL.begin(LLRender::TRIANGLES); + for (S32 lat_i = 0; lat_i < LATITUDE_SLICES; lat_i++) { - gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV); - gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); - gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); + for (S32 lon_i = 0; lon_i < LONGITUDE_SLICES; lon_i++) + { + gGL.vertex3fv(mSpherePoints[lat_i][lon_i].mV); + gGL.vertex3fv(mSpherePoints[lat_i][lon_i + 1].mV); + gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i].mV); - gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i].mV); - gGL.vertex3fv(mSpherePoints[lat_i][lon_i+1].mV); - gGL.vertex3fv(mSpherePoints[lat_i+1][lon_i+1].mV); + gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i].mV); + gGL.vertex3fv(mSpherePoints[lat_i][lon_i + 1].mV); + gGL.vertex3fv(mSpherePoints[lat_i + 1][lon_i + 1].mV); + } } + gGL.end(); } - gGL.end(); } diff --git a/indra/llrender/llrendersphere.h b/indra/llrender/llrendersphere.h index e2e886fa06..5b6eabecb8 100644 --- a/indra/llrender/llrendersphere.h +++ b/indra/llrender/llrendersphere.h @@ -45,6 +45,7 @@ public: private: std::vector< std::vector > mSpherePoints; + LLPointer mVertexBuffer; }; extern LLRenderSphere gSphere; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 3a18c28a62..e9fa369b0c 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1341,8 +1341,6 @@ void LLVertexBuffer::unmapBuffer() void LLVertexBuffer::_mapBuffer() { - // must only be called from main thread - llassert(LLCoros::on_main_thread_main_coro()); if (!mMapped) { mMapped = true; diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 48fddc32db..ce68474211 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -56,6 +56,7 @@ #include "llvoavatar.h" #include "llsculptidsize.h" #include "llmeshrepository.h" +#include "llskinningutil.h" #if LL_LINUX // Work-around spurious used before init warning on Vector4a @@ -2184,28 +2185,88 @@ F32 LLFace::getTextureVirtualSize() bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) { + constexpr F32 PIXEL_AREA_UPDATE_PERIOD = 0.1f; + // this is an expensive operation and the result is valid (enough) for several frames + // don't update every frame + if (gFrameTimeSeconds - mLastPixelAreaUpdate < PIXEL_AREA_UPDATE_PERIOD) + { + return true; + } + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE; //get area of circle around face - LLVector4a center; LLVector4a size; - if (isState(LLFace::RIGGED)) { - //override with avatar bounding box + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("calcPixelArea - rigged"); + //override with joint volume face joint bounding boxes LLVOAvatar* avatar = mVObjp->getAvatar(); + bool hasRiggedExtents = false; + if (avatar && avatar->mDrawable) { - center.load3(avatar->getPositionAgent().mV); - const LLVector4a* exts = avatar->mDrawable->getSpatialExtents(); - size.setSub(exts[1], exts[0]); + LLVolume* volume = mVObjp->getVolume(); + if (volume) + { + LLVolumeFace& face = volume->getVolumeFace(mTEOffset); + + auto& rigInfo = face.mJointRiggingInfoTab; + + if (rigInfo.needsUpdate()) + { + LLVOVolume* vo_volume = (LLVOVolume*)mVObjp.get(); + LLVOAvatar* avatar = mVObjp->getAvatar(); + const LLMeshSkinInfo* skin = vo_volume->getSkinInfo(); + LLSkinningUtil::updateRiggingInfo(skin, avatar, face); + } + + // calculate the world space bounding box of the face by combining the bounding boxes of all the joints + LLVector4a& minp = mRiggedExtents[0]; + LLVector4a& maxp = mRiggedExtents[1]; + minp = LLVector4a(FLT_MAX, FLT_MAX, FLT_MAX); + maxp = LLVector4a(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + for (S32 i = 0; i < rigInfo.size(); i++) + { + auto& jointInfo = rigInfo[i]; + if (jointInfo.isRiggedTo()) + { + LLJoint* joint = avatar->getJoint(i); + + if (joint) + { + LLVector4a jointPos; + + LLMatrix4a worldMat; + worldMat.loadu((F32*)&joint->getWorldMatrix().mMatrix[0][0]); + + LLVector4a extents[2]; + + matMulBoundBox(worldMat, jointInfo.getRiggedExtents(), extents); + + minp.setMin(minp, extents[0]); + maxp.setMax(maxp, extents[1]); + hasRiggedExtents = true; + } + } + } + } } - else + + if (!hasRiggedExtents) { + // no rigged extents, zero out bounding box and skip update + mRiggedExtents[0] = mRiggedExtents[1] = LLVector4a(0.f, 0.f, 0.f); + return false; } + + center.setAdd(mRiggedExtents[1], mRiggedExtents[0]); + center.mul(0.5f); + size.setSub(mRiggedExtents[1], mRiggedExtents[0]); } else { @@ -2231,6 +2292,10 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) F32 app_angle = atanf((F32) sqrt(size_squared) / dist); radius = app_angle*LLDrawable::sCurPixelAngle; mPixelArea = radius*radius * 3.14159f; + + // remember last update time, add 10% noise to avoid all faces updating at the same time + mLastPixelAreaUpdate = gFrameTimeSeconds + ll_frand() * PIXEL_AREA_UPDATE_PERIOD * 0.1f; + LLVector4a x_axis; x_axis.load3(camera->getXAxis().mV); cos_angle_to_view_dir = lookAt.dot3(x_axis).getF32(); diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 99642016f7..65637fbf85 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -234,8 +234,14 @@ public: // return true if this face is in an alpha draw pool bool isInAlphaPool() const; public: //aligned members + + // bounding box of face in drawable space LLVector4a mExtents[2]; + // cached bounding box of rigged face in world space + // calculated on-demand by LLFace::calcPixelArea and may not be up-to-date + LLVector4a mRiggedExtents[2] = { LLVector4a(0,0,0), LLVector4a(0,0,0) }; + private: friend class LLViewerTextureList; F32 adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius ); @@ -301,7 +307,14 @@ private: S32 mReferenceIndex; std::vector mRiggedIndex; + // gFrameTimeSeconds when mPixelArea was last updated + F32 mLastPixelAreaUpdate = 0.f; + + // virtual size of face in texture area (mPixelArea adjusted by texture repeats) + // used to determine desired resolution of texture F32 mVSize; + + // pixel area face covers on screen F32 mPixelArea; //importance factor, in the range [0, 1.0]. diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 26e2d8f319..532a87bbd1 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -77,6 +77,8 @@ #include "llinventorypanel.h" #include "lluploaddialog.h" #include "llfloaterreg.h" +#include "llvoavatarself.h" +#include "llskinningutil.h" #include "boost/iostreams/device/array.hpp" #include "boost/iostreams/stream.hpp" @@ -757,7 +759,7 @@ void log_upload_error(LLCore::HttpStatus status, const LLSD& content, << " (" << status.toTerseString() << ")" << LL_ENDL; std::ostringstream details; - typedef std::set mav_errors_set_t; + typedef std::unordered_set mav_errors_set_t; mav_errors_set_t mav_errors; if (content.has("error")) @@ -828,7 +830,8 @@ LLMeshRepoThread::LLMeshRepoThread() mHttpLargeOptions(), mHttpHeaders(), mHttpPolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), - mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID) + mHttpLargePolicyClass(LLCore::HttpRequest::DEFAULT_POLICY_ID), + mWorkQueue("MeshRepoThread", 1024*1024) { LLAppCoreHttp & app_core_http(LLAppViewer::instance()->getAppCoreHttp()); @@ -911,6 +914,10 @@ void LLMeshRepoThread::run() break; } + // run mWorkQueue for up to 8ms + static std::chrono::nanoseconds WorkTimeNanoSec{std::chrono::nanoseconds::rep(8 * 1000000) }; + mWorkQueue.runFor(WorkTimeNanoSec); + if (! mHttpRequestSet.empty()) { // Dispatch all HttpHandler notifications @@ -1322,7 +1329,7 @@ LLCore::HttpHandle LLMeshRepoThread::getByteRange(const std::string & url, bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry) { - + LL_PROFILE_ZONE_SCOPED; if (!mHeaderMutex) { return false; @@ -1447,6 +1454,7 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry) bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) { + LL_PROFILE_ZONE_SCOPED; if (!mHeaderMutex) { return false; @@ -1554,6 +1562,7 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) { + LL_PROFILE_ZONE_SCOPED; if (!mHeaderMutex) { return false; @@ -1693,6 +1702,7 @@ void LLMeshRepoThread::decActiveHeaderRequests() //return false if failed to get header bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool can_retry) { + LL_PROFILE_ZONE_SCOPED; ++LLMeshRepository::sMeshRequestCount; { @@ -1756,6 +1766,7 @@ bool LLMeshRepoThread::fetchMeshHeader(const LLVolumeParams& mesh_params, bool c //return false if failed to get mesh lod. bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, bool can_retry) { + LL_PROFILE_ZONE_SCOPED; if (!mHeaderMutex) { return false; @@ -1940,6 +1951,18 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes LLMeshRepository::sCacheBytesHeaders += (U32)header_size; } + // immediately request SkinInfo since we'll need it before we can render any LoD if it is present + { + LLMutexLock lock(gMeshRepo.mMeshMutex); + + if (gMeshRepo.mLoadingSkins.find(mesh_id) == gMeshRepo.mLoadingSkins.end()) + { + gMeshRepo.mLoadingSkins[mesh_id] = {}; // add an empty vector to indicate to main thread that we are loading skin info + } + } + + fetchMeshSkinInfo(mesh_id); + LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time. //check for pending requests @@ -1971,6 +1994,18 @@ EMeshProcessingResult LLMeshRepoThread::lodReceived(const LLVolumeParams& mesh_p { if (volume->getNumFaces() > 0) { + // if we have a valid SkinInfo, cache per-joint bounding boxes for this LOD + LLMeshSkinInfo* skin_info = mSkinMap[mesh_params.getSculptID()]; + if (skin_info && isAgentAvatarValid()) + { + for (S32 i = 0; i < volume->getNumFaces(); ++i) + { + // NOTE: no need to lock gAgentAvatarp as the state being checked is not changed after initialization + LLVolumeFace& face = volume->getVolumeFace(i); + LLSkinningUtil::updateRiggingInfo(skin_info, gAgentAvatarp, face); + } + } + LoadedMesh mesh(volume, mesh_params, lod); { LLMutexLock lock(mMutex); @@ -2014,18 +2049,19 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat } { - LLMeshSkinInfo* info = nullptr; - try - { - info = new LLMeshSkinInfo(mesh_id, skin); - } - catch (const std::bad_alloc& ex) - { - LL_WARNS() << "Failed to allocate skin info with exception: " << ex.what() << LL_ENDL; - return false; + LLPointer info = nullptr; + info = new LLMeshSkinInfo(mesh_id, skin); + + if (isAgentAvatarValid()) + { // joint numbers are consistent inside LLVOAvatar and animations, but inconsistent inside meshes, + // generate a map of mesh joint numbers to LLVOAvatar joint numbers + LLSkinningUtil::initJointNums(info, gAgentAvatarp); } - // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL; + // remember the skin info in the background thread so we can use it + // to calculate per-joint bounding boxes when volumes are loaded + mSkinMap[mesh_id] = info; + { LLMutexLock lock(mMutex); mSkinInfoQ.push_back(info); @@ -2265,10 +2301,10 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures) S32 mesh_num = 0; S32 texture_num = 0; - std::set textures; - std::map texture_index; + std::unordered_set textures; + std::unordered_map texture_index; - std::map mesh_index; + std::unordered_map mesh_index; std::string model_name; S32 instance_num = 0; @@ -2957,7 +2993,7 @@ void LLMeshRepoThread::notifyLoadedMeshes() { if (mMutex->trylock()) { - std::deque skin_info_q; + std::deque> skin_info_q; std::deque skin_info_unavail_q; std::list decomp_q; @@ -3080,6 +3116,7 @@ S32 LLMeshRepository::getActualMeshLOD(LLMeshHeader& header, S32 lod) // are cases far off the norm. void LLMeshHandlerBase::onCompleted(LLCore::HttpHandle handle, LLCore::HttpResponse * response) { + LL_PROFILE_ZONE_SCOPED; mProcessed = true; unsigned int retries(0U); @@ -3356,6 +3393,7 @@ void LLMeshLODHandler::processFailure(LLCore::HttpStatus status) void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, U8 * data, S32 data_size) { + LL_PROFILE_ZONE_SCOPED; if ((!MESH_LOD_PROCESS_FAILED) && ((data != NULL) == (data_size > 0))) // if we have data but no size or have size but no data, something is wrong { @@ -3421,6 +3459,7 @@ void LLMeshSkinInfoHandler::processFailure(LLCore::HttpStatus status) void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, U8 * data, S32 data_size) { + LL_PROFILE_ZONE_SCOPED; if ((!MESH_SKIN_INFO_PROCESS_FAILED) && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong && gMeshRepo.mThread->skinInfoReceived(mMeshID, data, data_size)) @@ -3470,6 +3509,7 @@ void LLMeshDecompositionHandler::processFailure(LLCore::HttpStatus status) void LLMeshDecompositionHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, U8 * data, S32 data_size) { + LL_PROFILE_ZONE_SCOPED; if ((!MESH_DECOMP_PROCESS_FAILED) && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong && gMeshRepo.mThread->decompositionReceived(mMeshID, data, data_size)) @@ -3517,6 +3557,7 @@ void LLMeshPhysicsShapeHandler::processFailure(LLCore::HttpStatus status) void LLMeshPhysicsShapeHandler::processData(LLCore::BufferArray * /* body */, S32 /* body_offset */, U8 * data, S32 data_size) { + LL_PROFILE_ZONE_SCOPED; if ((!MESH_PHYS_SHAPE_PROCESS_FAILED) && ((data != NULL) == (data_size > 0)) // if we have data but no size or have size but no data, something is wrong && gMeshRepo.mThread->physicsShapeReceived(mMeshID, data, data_size) == MESH_OK) @@ -3870,6 +3911,13 @@ void LLMeshRepository::notifyLoadedMeshes() { mSkinMap.erase(copy_iter); } + + // erase from background thread + LLUUID id = iter->first; + mThread->mWorkQueue.post([=]() + { + mThread->mSkinMap.erase(id); + }); } //LL_INFOS() << "Skin info cache elements:" << mSkinMap.size() << " Memory: " << U64Kilobytes(skinbytes) << LL_ENDL; } @@ -4206,7 +4254,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes - std::set::iterator iter = mLoadingPhysicsShapes.find(mesh_id); + std::unordered_set::iterator iter = mLoadingPhysicsShapes.find(mesh_id); if (iter == mLoadingPhysicsShapes.end()) { //no request pending for this skin info // *FIXME: Nothing ever deletes entries, can't be right @@ -4236,7 +4284,7 @@ LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id { LLMutexLock lock(mMeshMutex); //add volume to list of loading meshes - std::set::iterator iter = mLoadingDecompositions.find(mesh_id); + std::unordered_set::iterator iter = mLoadingDecompositions.find(mesh_id); if (iter == mLoadingDecompositions.end()) { //no request pending for this skin info mLoadingDecompositions.insert(mesh_id); @@ -4287,6 +4335,8 @@ bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id) bool LLMeshRepository::hasSkinInfo(const LLUUID& mesh_id) { + LL_PROFILE_ZONE_SCOPED; + if (mesh_id.isNull()) { return false; diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index b850ade0bb..b5c2424578 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -28,6 +28,7 @@ #define LL_MESH_REPOSITORY_H #include +#include #include "llassettype.h" #include "llmodel.h" #include "lluuid.h" @@ -341,7 +342,7 @@ public: std::deque mSkinRequests; // list of completed skin info requests - std::deque mSkinInfoQ; + std::deque> mSkinInfoQ; // list of skin info requests that have failed or are unavailaibe std::deque mSkinUnavailableQ; @@ -368,9 +369,17 @@ public: std::deque mLoadedQ; //map of pending header requests and currently desired LODs - typedef boost::unordered_map > pending_lod_map; + typedef std::unordered_map > pending_lod_map; pending_lod_map mPendingLOD; + // map of mesh ID to skin info (mirrors LLMeshRepository::mSkinMap) + /// NOTE: LLMeshRepository::mSkinMap is accessed very frequently, so maintain a copy here to avoid mutex overhead + typedef std::unordered_map> skin_map; + skin_map mSkinMap; + + // workqueue for processing generic requests + LL::WorkQueue mWorkQueue; + // llcorehttp library interface objects. LLCore::HttpStatus mHttpStatus; LLCore::HttpRequest * mHttpRequest; @@ -380,7 +389,7 @@ public: LLCore::HttpRequest::policy_t mHttpPolicyClass; LLCore::HttpRequest::policy_t mHttpLargePolicyClass; - typedef std::set http_request_set; + typedef std::unordered_set http_request_set; http_request_set mHttpRequestSet; // Outstanding HTTP requests std::string mGetMeshCapability; @@ -696,13 +705,13 @@ public: std::queue mPendingSkinRequests; //list of mesh ids awaiting decompositions - std::set mLoadingDecompositions; + std::unordered_set mLoadingDecompositions; //list of mesh ids that need to send decomposition fetch requests std::queue mPendingDecompositionRequests; //list of mesh ids awaiting physics shapes - std::set mLoadingPhysicsShapes; + std::unordered_set mLoadingPhysicsShapes; //list of mesh ids that need to send physics shape fetch requests std::queue mPendingPhysicsShapeRequests; diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index 1c92e06700..cee43f3cff 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -317,19 +317,16 @@ void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar) void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *avatar, LLVolumeFace& vol_face) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; - if (vol_face.mJointRiggingInfoTab.needsUpdate()) { S32 num_verts = vol_face.mNumVertices; S32 num_joints = static_cast(skin->mJointNames.size()); if (num_verts > 0 && vol_face.mWeights && num_joints > 0) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; initJointNums(const_cast(skin), avatar); if (vol_face.mJointRiggingInfoTab.size()==0) { - //std::set active_joints; - //S32 active_verts = 0; vol_face.mJointRiggingInfoTab.resize(LL_CHARACTER_MAX_ANIMATED_JOINTS); LLJointRiggingInfoTab &rig_info_tab = vol_face.mJointRiggingInfoTab; for (S32 i=0; i 0.0f) - { - for (U32 k=0; k<4; ++k) - { - wght[k] /= scale; - } } + for (U32 k=0; k<4; ++k) { S32 joint_index = idx[k]; - if (wght[k] > 0.0f && num_joints > joint_index) + if (wght[k] > 0.2f && num_joints > joint_index) { S32 joint_num = skin->mJointNums[joint_index]; if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS) { rig_info_tab[joint_num].setIsRiggedTo(true); - // FIXME could precompute these matMuls. - const LLMatrix4a& bind_shape = skin->mBindShapeMatrix; - const LLMatrix4a& inv_bind = skin->mInvBindMatrix[joint_index]; - LLMatrix4a mat; + const LLMatrix4a& mat = skin->mBindPoseMatrix[joint_index]; LLVector4a pos_joint_space; - matMul(bind_shape, inv_bind, mat); - mat.affineTransform(pos, pos_joint_space); - pos_joint_space.mul(wght[k]); LLVector4a *extents = rig_info_tab[joint_num].getRiggedExtents(); update_min_max(extents[0], extents[1], pos_joint_space); @@ -381,28 +365,9 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a } } } - //LL_DEBUGS("RigSpammish") << "built rigging info for vf " << &vol_face - // << " num_verts " << vol_face.mNumVertices - // << " active joints " << active_joints.size() - // << " active verts " << active_verts - // << LL_ENDL; vol_face.mJointRiggingInfoTab.setNeedsUpdate(false); } } - -#if DEBUG_SKINNING - if (vol_face.mJointRiggingInfoTab.size()!=0) - { - LL_DEBUGS("RigSpammish") << "we have rigging info for vf " << &vol_face - << " num_verts " << vol_face.mNumVertices << LL_ENDL; - } - else - { - LL_DEBUGS("RigSpammish") << "no rigging info for vf " << &vol_face - << " num_verts " << vol_face.mNumVertices << LL_ENDL; - } -#endif - } } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index e36a03a749..86440fca48 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -7280,6 +7280,7 @@ const std::string& LLViewerObject::getAttachmentItemName() const //virtual LLVOAvatar* LLViewerObject::getAvatar() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (getControlAvatar()) { return getControlAvatar(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 8e8cf7424f..ef0bb3b926 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1646,6 +1646,9 @@ void LLVOAvatar::renderCollisionVolumes() } } +// defined in llspatialpartition.cpp -- draw a box outline in the current GL context from given center and half-size +void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size); + void LLVOAvatar::renderBones(const std::string &selected_joint) { LLGLEnable blend(GL_BLEND); @@ -1722,6 +1725,88 @@ void LLVOAvatar::renderBones(const std::string &selected_joint) gGL.popMatrix(); } + + + // draw joint space bounding boxes of rigged attachments in yellow + gGL.color3f(1.f, 1.f, 0.f); + for (S32 joint_num = 0; joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS; joint_num++) + { + LLJoint* joint = getJoint(joint_num); + LLJointRiggingInfo* rig_info = NULL; + if (joint_num < mJointRiggingInfoTab.size()) + { + rig_info = &mJointRiggingInfoTab[joint_num]; + } + + if (joint && rig_info && rig_info->isRiggedTo()) + { + LLViewerJointAttachment* as_joint_attach = dynamic_cast(joint); + if (as_joint_attach && as_joint_attach->getIsHUDAttachment()) + { + // Ignore bounding box of HUD joints + continue; + } + gGL.pushMatrix(); + gGL.multMatrix(&joint->getXform()->getWorldMatrix().mMatrix[0][0]); + + LLVector4a pos; + LLVector4a size; + + const LLVector4a* extents = rig_info->getRiggedExtents(); + + pos.setAdd(extents[0], extents[1]); + pos.mul(0.5f); + size.setSub(extents[1], extents[0]); + size.mul(0.5f); + + drawBoxOutline(pos, size); + + gGL.popMatrix(); + } + } + + // draw world space attachment rigged bounding boxes in cyan + gGL.color3f(0.f, 1.f, 1.f); + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + + if (attachment->getValid()) + { + 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->isHUDAttachment()) + { + LLDrawable* drawable = attached_object->mDrawable; + if (drawable && drawable->isState(LLDrawable::RIGGED | LLDrawable::RIGGED_CHILD)) + { + // get face rigged extents + for (S32 i = 0; i < drawable->getNumFaces(); ++i) + { + LLFace* facep = drawable->getFace(i); + if (facep && facep->isState(LLFace::RIGGED)) + { + LLVector4a center, size; + + LLVector4a* extents = facep->mRiggedExtents; + + center.setAdd(extents[0], extents[1]); + center.mul(0.5f); + size.setSub(extents[1], extents[0]); + size.mul(0.5f); + drawBoxOutline(center, size); + } + } + } + } + } + } + } } @@ -10662,35 +10747,42 @@ void LLVOAvatar::updateRiggingInfo() LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL; - std::vector volumes; + // use a local static for scratch space to avoid reallocation here + static std::vector volumes; + volumes.resize(0); getAssociatedVolumes(volumes); - std::map curr_rigging_info_key; - { LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR("update rig info - get key") + HBXXH128 hash; // Get current rigging info key for (LLVOVolume* vol : volumes) { - if (vol->isMesh() && vol->getVolume()) + if (vol->isRiggedMesh()) { const LLUUID& mesh_id = vol->getVolume()->getParams().getSculptID(); S32 max_lod = llmax(vol->getLOD(), vol->mLastRiggingInfoLOD); - curr_rigging_info_key[mesh_id] = max_lod; + + hash.update(mesh_id.mData, sizeof(mesh_id.mData)); + hash.update(&max_lod, sizeof(max_lod)); } } - } - // Check for key change, which indicates some change in volume composition or LOD. - if (curr_rigging_info_key == mLastRiggingInfoKey) - { - return; + LLUUID curr_rigging_info_key = hash.digest(); + + // Check for key change, which indicates some change in volume composition or LOD. + if (curr_rigging_info_key == mLastRiggingInfoKey) + { + return; + } + + + // Something changed. Update. + mLastRiggingInfoKey = curr_rigging_info_key; } - // Something changed. Update. - mLastRiggingInfoKey = curr_rigging_info_key; mJointRiggingInfoTab.clear(); for (LLVOVolume* vol : volumes) { diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index a93ccf46bf..ff1cbc34fc 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -226,7 +226,7 @@ public: // virtual void updateRiggingInfo(); // This encodes mesh id and LOD, so we can see whether display is up-to-date. - std::map mLastRiggingInfoKey; + LLUUID mLastRiggingInfoKey; std::set mActiveOverrideMeshes; virtual void onActiveOverrideMeshesChanged(); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 4f48a070e3..2859f8b1c2 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -3657,7 +3657,7 @@ const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const // virtual bool LLVOVolume::isRiggedMesh() const { - return isMesh() && getSkinInfo(); + return getSkinInfo() != nullptr; } //---------------------------------------------------------------------------- @@ -3818,7 +3818,6 @@ void LLVOVolume::updateRiggingInfo() LLVolume *volume = getVolume(); if (skin && avatar && volume) { - LL_DEBUGS("RigSpammish") << "starting, vovol " << this << " lod " << getLOD() << " last " << mLastRiggingInfoLOD << LL_ENDL; if (getLOD()>mLastRiggingInfoLOD || getLOD()==3) { // Rigging info may need update @@ -3834,9 +3833,6 @@ void LLVOVolume::updateRiggingInfo() } // Keep the highest LOD info available. mLastRiggingInfoLOD = getLOD(); - LL_DEBUGS("RigSpammish") << "updated rigging info for LLVOVolume " - << this << " lod " << mLastRiggingInfoLOD - << LL_ENDL; } } } -- cgit v1.3