diff options
author | Brad Kittenbrink <brad@lindenlab.com> | 2022-04-27 10:27:48 -0700 |
---|---|---|
committer | Brad Kittenbrink <brad@lindenlab.com> | 2022-04-27 10:27:48 -0700 |
commit | a3ffa9f006b008b5faad248f700c8c2fbc6b74fd (patch) | |
tree | f674d4d4e3ab2d4ef4a7419594ea507506238232 /indra | |
parent | 030d61ac58be38f9f8aafeb68b383d88d670080b (diff) | |
parent | bafa869c21cb8b329f94be6fa930a43d11699082 (diff) |
Merge remote-tracking branch 'origin/DRTVWR-546' into DRTVWR-559
Diffstat (limited to 'indra')
411 files changed, 15888 insertions, 18967 deletions
diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index dc1c28ce5b..f93a09d232 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -38,6 +38,7 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llkdu) add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj) add_subdirectory(${LIBS_OPEN_PREFIX}llinventory) add_subdirectory(${LIBS_OPEN_PREFIX}llmath) +add_subdirectory(${LIBS_OPEN_PREFIX}llmeshoptimizer) add_subdirectory(${LIBS_OPEN_PREFIX}llmessage) add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive) add_subdirectory(${LIBS_OPEN_PREFIX}llrender) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index f4071793d5..bb5dd8f847 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -42,8 +42,8 @@ if(NON_RELEASE_CRASH_REPORTING) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DLL_SEND_CRASH_REPORTS=1") endif() -# Don't bother with a MinSizeRel build. -set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release;Debug" CACHE STRING +# Don't bother with MinSizeRel or Debug builds. +set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release" CACHE STRING "Supported build types." FORCE) @@ -66,16 +66,21 @@ if (WINDOWS) # CP changed to only append the flag for 32bit builds - on 64bit builds, # locally at least, the build output is spammed with 1000s of 'D9002' # warnings about this switch being ignored. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") if( ADDRESS_SIZE EQUAL 32 ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /p:PreferredToolArchitecture=x64") endif() + # Preserve first-pass-through versions (ie no FORCE overwrite). Prevents recursive addition of /Zo (04/2021) + set(OG_CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} CACHE STRING "OG_CXX_FLAGS_RELEASE") + set(OG_CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} CACHE STRING "OG_CXX_FLAGS_RELWITHDEBINFO") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO - "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo" + "${OG_CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Zo" CACHE STRING "C++ compiler release-with-debug options" FORCE) set(CMAKE_CXX_FLAGS_RELEASE - "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo" + "${OG_CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /Zo" CACHE STRING "C++ compiler release options" FORCE) + # zlib has assembly-language object files incompatible with SAFESEH set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /LARGEADDRESSAWARE /SAFESEH:NO /NODEFAULTLIB:LIBCMT /IGNORE:4099") diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index d7725670a2..50cd42ff57 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -40,7 +40,6 @@ set(cmake_SOURCE_FILES FreeType.cmake GLEXT.cmake GLH.cmake - GLOD.cmake ## GStreamer010Plugin.cmake GoogleMock.cmake Havok.cmake @@ -59,6 +58,7 @@ set(cmake_SOURCE_FILES LLKDU.cmake LLLogin.cmake LLMath.cmake + LLMeshOptimizer.cmake LLMessage.cmake LLPhysicsExtensions.cmake LLPlugin.cmake @@ -72,6 +72,7 @@ set(cmake_SOURCE_FILES LLXML.cmake Linking.cmake MediaPluginBase.cmake + MESHOPTIMIZER.cmake NDOF.cmake OPENAL.cmake OpenGL.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index b20d23cead..b408702f04 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -57,7 +57,6 @@ if(WINDOWS) libaprutil-1.dll libapriconv-1.dll nghttp2.dll - glod.dll libhunspell.dll uriparser.dll ) @@ -104,6 +103,8 @@ if(WINDOWS) set(MSVC_VER 120) elseif (MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS 1920) # Visual Studio 2017 set(MSVC_VER 140) + elseif (MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS 1930) # Visual Studio 2019 + set(MSVC_VER 140) else (MSVC80) MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake") endif (MSVC80) @@ -166,7 +167,6 @@ elseif(DARWIN) libaprutil-1.0.dylib libaprutil-1.dylib ${EXPAT_COPY} - libGLOD.dylib libhunspell-1.3.0.dylib libndofdev.dylib libnghttp2.dylib @@ -215,7 +215,6 @@ elseif(LINUX) ${EXPAT_COPY} libfreetype.so.6.6.2 libfreetype.so.6 - libGLOD.so libgmodule-2.0.so libgobject-2.0.so libhunspell-1.3.so.0.0.0 diff --git a/indra/cmake/GLOD.cmake b/indra/cmake/GLOD.cmake deleted file mode 100644 index 6f42b44ab8..0000000000 --- a/indra/cmake/GLOD.cmake +++ /dev/null @@ -1,11 +0,0 @@ -# -*- cmake -*- -include(Prebuilt) - -if (NOT USESYSTEMLIBS) - use_prebuilt_binary(glod) -endif (NOT USESYSTEMLIBS) - -set(GLODLIB ON CACHE BOOL "Using GLOD library") - -set(GLOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include) -set(GLOD_LIBRARIES GLOD) diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 8900419f9b..34499aaa36 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -3,12 +3,14 @@ include(APR) include(Boost) include(EXPAT) +include(Tracy) include(ZLIB) set(LLCOMMON_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llcommon ${APRUTIL_INCLUDE_DIR} ${APR_INCLUDE_DIR} + ${TRACY_INCLUDE_DIR} ) set(LLCOMMON_SYSTEM_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} @@ -30,7 +32,8 @@ else (LINUX) ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_THREAD_LIBRARY} - ${BOOST_SYSTEM_LIBRARY} ) + ${BOOST_SYSTEM_LIBRARY} + ) endif (LINUX) set(LLCOMMON_LINK_SHARED OFF CACHE BOOL "Build the llcommon target as a static library.") diff --git a/indra/cmake/LLMeshOptimizer.cmake b/indra/cmake/LLMeshOptimizer.cmake new file mode 100644 index 0000000000..b79944f618 --- /dev/null +++ b/indra/cmake/LLMeshOptimizer.cmake @@ -0,0 +1,7 @@ +# -*- cmake -*- + +set(LLMESHOPTIMIZER_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/llmeshoptimizer + ) + +set(LLMESHOPTIMIZER_LIBRARIES llmeshoptimizer) diff --git a/indra/cmake/MESHOPTIMIZER.cmake b/indra/cmake/MESHOPTIMIZER.cmake new file mode 100644 index 0000000000..1c5b47b9bd --- /dev/null +++ b/indra/cmake/MESHOPTIMIZER.cmake @@ -0,0 +1,16 @@ +# -*- cmake -*- + +include(Linking) +include(Prebuilt) + +use_prebuilt_binary(meshoptimizer) + +if (WINDOWS) + set(MESHOPTIMIZER_LIBRARIES meshoptimizer.lib) +elseif (LINUX) + set(MESHOPTIMIZER_LIBRARIES meshoptimizer.o) +elseif (DARWIN) + set(MESHOPTIMIZER_LIBRARIES libmeshoptimizer.a) +endif (WINDOWS) + +set(MESHOPTIMIZER_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include/meshoptimizer) diff --git a/indra/cmake/Tracy.cmake b/indra/cmake/Tracy.cmake new file mode 100644 index 0000000000..cfff956bcf --- /dev/null +++ b/indra/cmake/Tracy.cmake @@ -0,0 +1,29 @@ +# -*- cmake -*- +include(Prebuilt) + +set(USE_TRACY OFF CACHE BOOL "Use Tracy profiler.") + +if (USE_TRACY) + set(TRACY_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/tracy) + +# See: indra/llcommon/llprofiler.h + add_definitions(-DLL_PROFILER_CONFIGURATION=3) + use_prebuilt_binary(tracy) + + if (WINDOWS) + MESSAGE(STATUS "Including Tracy for Windows: '${TRACY_INCLUDE_DIR}'") + endif (WINDOWS) + + if (DARWIN) + MESSAGE(STATUS "Including Tracy for Darwin: '${TRACY_INCLUDE_DIR}'") + endif (DARWIN) + + if (LINUX) + MESSAGE(STATUS "Including Tracy for Linux: '${TRACY_INCLUDE_DIR}'") + endif (LINUX) +else (USE_TRACY) + # Tracy.cmake should not set LLCOMMON_INCLUDE_DIRS, let LLCommon.cmake do that + set(TRACY_INCLUDE_DIR "") + set(TRACY_LIBRARY "") +endif (USE_TRACY) + diff --git a/indra/edit-me-to-trigger-new-build.txt b/indra/edit-me-to-trigger-new-build.txt index ade83202cf..eab7c17b71 100644 --- a/indra/edit-me-to-trigger-new-build.txt +++ b/indra/edit-me-to-trigger-new-build.txt @@ -1,3 +1,4 @@ euclid 5/29/2020 euclid 7/23/2020 euclid 4/29/2021 +euclid 10/5/2021 DRTVWR-546 diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp index 90dfa04f28..2d6d2a10d2 100644 --- a/indra/llappearance/llavatarappearance.cpp +++ b/indra/llappearance/llavatarappearance.cpp @@ -1590,7 +1590,7 @@ BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num ) delete_and_clear_array(mCollisionVolumes); mNumCollisionVolumes = 0; - mCollisionVolumes = new(std::nothrow) LLAvatarJointCollisionVolume[num]; + mCollisionVolumes = new LLAvatarJointCollisionVolume[num]; if (!mCollisionVolumes) { LL_WARNS() << "Failed to allocate collision volumes" << LL_ENDL; diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h index f278dcc2e2..a6261b507b 100644 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -77,73 +77,63 @@ protected: //----------------------------------------------------------------------------- -LL_ALIGN_PREFIX(16) -class LLDriverParam : public LLViewerVisualParam +class alignas(16) LLDriverParam : public LLViewerVisualParam { + LL_ALIGN_NEW private: - // Hide the default constructor. Force construction with LLAvatarAppearance. - LLDriverParam() {} + // Hide the default constructor. Force construction with LLAvatarAppearance. + LLDriverParam() {} public: - LLDriverParam(LLAvatarAppearance *appearance, LLWearable* wearable = NULL); - ~LLDriverParam(); - - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - - // Special: These functions are overridden by child classes - LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLDriverParamInfo *info); - - LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; } - const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } - - void updateCrossDrivenParams(LLWearableType::EType driven_type); - - /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; - - // LLVisualParam Virtual functions - /*virtual*/ void apply( ESex sex ) {} // apply is called separately for each driven param. - /*virtual*/ void setWeight(F32 weight); - /*virtual*/ void setAnimationTarget( F32 target_value); - /*virtual*/ void stopAnimating(); - /*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); - /*virtual*/ void resetDrivenParams(); - - // LLViewerVisualParam Virtual functions - /*virtual*/ F32 getTotalDistortion(); - /*virtual*/ const LLVector4a& getAvgDistortion(); - /*virtual*/ F32 getMaxDistortion(); - /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh *poly_mesh); - /*virtual*/ const LLVector4a* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh); - /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh); - - S32 getDrivenParamsCount() const; - const LLViewerVisualParam* getDrivenParam(S32 index) const; - - typedef std::vector<LLDrivenEntry> entry_list_t; - entry_list_t& getDrivenList() { return mDriven; } + LLDriverParam(LLAvatarAppearance* appearance, LLWearable* wearable = NULL); + ~LLDriverParam(); + + // Special: These functions are overridden by child classes + LLDriverParamInfo* getInfo() const { return (LLDriverParamInfo*)mInfo; } + // This sets mInfo and calls initialization functions + BOOL setInfo(LLDriverParamInfo* info); + + LLAvatarAppearance* getAvatarAppearance() { return mAvatarAppearance; } + const LLAvatarAppearance* getAvatarAppearance() const { return mAvatarAppearance; } + + void updateCrossDrivenParams(LLWearableType::EType driven_type); + + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const; + + // LLVisualParam Virtual functions + /*virtual*/ void apply(ESex sex) {} // apply is called separately for each driven param. + /*virtual*/ void setWeight(F32 weight); + /*virtual*/ void setAnimationTarget(F32 target_value); + /*virtual*/ void stopAnimating(); + /*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params); + /*virtual*/ void resetDrivenParams(); + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion(); + /*virtual*/ const LLVector4a& getAvgDistortion(); + /*virtual*/ F32 getMaxDistortion(); + /*virtual*/ LLVector4a getVertexDistortion(S32 index, LLPolyMesh* poly_mesh); + /*virtual*/ const LLVector4a* getFirstDistortion(U32* index, LLPolyMesh** poly_mesh); + /*virtual*/ const LLVector4a* getNextDistortion(U32* index, LLPolyMesh** poly_mesh); + + S32 getDrivenParamsCount() const; + const LLViewerVisualParam* getDrivenParam(S32 index) const; + + typedef std::vector<LLDrivenEntry> entry_list_t; + entry_list_t& getDrivenList() { return mDriven; } void setDrivenList(entry_list_t& driven_list) { mDriven = driven_list; } protected: - LLDriverParam(const LLDriverParam& pOther); - F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); - void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight); - - - LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder - entry_list_t mDriven; - LLViewerVisualParam* mCurrentDistortionParam; - // Backlink only; don't make this an LLPointer. - LLAvatarAppearance* mAvatarAppearance; - LLWearable* mWearablep; -} LL_ALIGN_POSTFIX(16); + LLDriverParam(const LLDriverParam& pOther); + F32 getDrivenWeight(const LLDrivenEntry* driven, F32 input_weight); + void setDrivenWeight(LLDrivenEntry* driven, F32 driven_weight); + + + LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder + entry_list_t mDriven; + LLViewerVisualParam* mCurrentDistortionParam; + // Backlink only; don't make this an LLPointer. + LLAvatarAppearance* mAvatarAppearance; + LLWearable* mWearablep; +}; #endif // LL_LLDRIVERPARAM_H diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp index ce7010984a..16b5f1e204 100644 --- a/indra/llappearance/llpolymorph.cpp +++ b/indra/llappearance/llpolymorph.cpp @@ -539,8 +539,6 @@ F32 LLPolyMorphTarget::getMaxDistortion() //----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_APPLY_MORPH_TARGET("Apply Morph"); - void LLPolyMorphTarget::apply( ESex avatar_sex ) { if (!mMorphData || mNumMorphMasksPending > 0) @@ -548,7 +546,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex ) return; } - LL_RECORD_BLOCK_TIME(FTM_APPLY_MORPH_TARGET); + LL_PROFILE_ZONE_SCOPED; mLastSex = avatar_sex; diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index c6133cd831..29cd373636 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -41,24 +41,14 @@ class LLWearable; //----------------------------------------------------------------------------- // LLPolyMorphData() //----------------------------------------------------------------------------- -LL_ALIGN_PREFIX(16) -class LLPolyMorphData +class alignas(16) LLPolyMorphData { + LL_ALIGN_NEW public: LLPolyMorphData(const std::string& morph_name); ~LLPolyMorphData(); LLPolyMorphData(const LLPolyMorphData &rhs); - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - BOOL loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh); const std::string& getName() { return mName; } @@ -76,7 +66,7 @@ public: F32 mTotalDistortion; // vertex distortion summed over entire morph F32 mMaxDistortion; // maximum single vertex distortion in a given morph - LL_ALIGN_16(LLVector4a mAvgDistortion); // average vertex distortion, to infer directionality of the morph + LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph LLPolyMeshSharedData* mMesh; private: @@ -154,8 +144,9 @@ protected: // These morph targets must be topologically consistent with a given Polymesh // (share face sets) //----------------------------------------------------------------------------- -class LLPolyMorphTarget : public LLViewerVisualParam +class alignas(16) LLPolyMorphTarget : public LLViewerVisualParam { + LL_ALIGN_NEW public: LLPolyMorphTarget(LLPolyMesh *poly_mesh); ~LLPolyMorphTarget(); @@ -184,16 +175,6 @@ public: void applyVolumeChanges(F32 delta_weight); // SL-315 - for resetSkeleton() - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - protected: LLPolyMorphTarget(const LLPolyMorphTarget& pOther); diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp index ae38c25dbf..360f17508f 100644 --- a/indra/llappearance/llpolyskeletaldistortion.cpp +++ b/indra/llappearance/llpolyskeletaldistortion.cpp @@ -188,11 +188,9 @@ BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info) //----------------------------------------------------------------------------- // apply() //----------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion"); - void LLPolySkeletalDistortion::apply( ESex avatar_sex ) { - LL_RECORD_BLOCK_TIME(FTM_POLYSKELETAL_DISTORTION_APPLY); + LL_PROFILE_ZONE_SCOPED; F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight(); diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h index ab1a132d19..585d85f055 100644 --- a/indra/llappearance/llpolyskeletaldistortion.h +++ b/indra/llappearance/llpolyskeletaldistortion.h @@ -62,9 +62,9 @@ struct LLPolySkeletalBoneInfo BOOL mHasPositionDeformation; }; -LL_ALIGN_PREFIX(16) -class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo +class alignas(16) LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo { + LL_ALIGN_NEW friend class LLPolySkeletalDistortion; public: @@ -73,19 +73,6 @@ public: /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); - - - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - - protected: typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t; bone_info_list_t mBoneInfoList; @@ -95,19 +82,10 @@ protected: // LLPolySkeletalDeformation // A set of joint scale data for deforming the avatar mesh //----------------------------------------------------------------------------- -class LLPolySkeletalDistortion : public LLViewerVisualParam +class alignas(16) LLPolySkeletalDistortion : public LLViewerVisualParam { + LL_ALIGN_NEW public: - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - LLPolySkeletalDistortion(LLAvatarAppearance *avatarp); ~LLPolySkeletalDistortion(); diff --git a/indra/llappearance/lltexlayer.cpp b/indra/llappearance/lltexlayer.cpp index a4600069ce..234f5c3007 100644 --- a/indra/llappearance/lltexlayer.cpp +++ b/indra/llappearance/lltexlayer.cpp @@ -142,17 +142,8 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target) BOOL success = TRUE; - bool use_shaders = LLGLSLShader::sNoFixedFunction; - - if (use_shaders) - { - gAlphaMaskProgram.bind(); - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.00f); - } + gAlphaMaskProgram.bind(); + gAlphaMaskProgram.setMinimumAlpha(0.004f); LLVertexBuffer::unbind(); @@ -164,10 +155,7 @@ BOOL LLTexLayerSetBuffer::renderTexLayerSet(LLRenderTarget* bound_target) midRenderTexLayerSet(success); - if (use_shaders) - { - gAlphaMaskProgram.unbind(); - } + gAlphaMaskProgram.unbind(); LLVertexBuffer::unbind(); @@ -390,8 +378,6 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget* } } - bool use_shaders = LLGLSLShader::sNoFixedFunction; - LLGLSUIDefault gls_ui; LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE); gGL.setColorMask(true, true); @@ -400,20 +386,14 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget* { gGL.flush(); LLGLDisable no_alpha(GL_ALPHA_TEST); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.0f); - } + gAlphaMaskProgram.setMinimumAlpha(0.0f); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 1.f ); gl_rect_2d_simple( width, height ); gGL.flush(); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.004f); } if (mIsVisible) @@ -440,10 +420,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget* gGL.setSceneBlendType(LLRender::BT_REPLACE); LLGLDisable no_alpha(GL_ALPHA_TEST); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } + gAlphaMaskProgram.setMinimumAlpha(0.f); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 0.f ); @@ -452,10 +429,7 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height, LLRenderTarget* gGL.setSceneBlendType(LLRender::BT_ALPHA); gGL.flush(); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.004f); } return success; @@ -520,10 +494,9 @@ const LLTexLayerSetBuffer* LLTexLayerSet::getComposite() const return mComposite; } -static LLTrace::BlockTimerStatHandle FTM_GATHER_MORPH_MASK_ALPHA("gatherMorphMaskAlpha"); void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S32 width, S32 height, LLRenderTarget* bound_target) { - LL_RECORD_BLOCK_TIME(FTM_GATHER_MORPH_MASK_ALPHA); + LL_PROFILE_ZONE_SCOPED; memset(data, 255, width * height); for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) @@ -536,14 +509,11 @@ void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 origin_x, S32 origin_y, S renderAlphaMaskTextures(origin_x, origin_y, width, height, bound_target, true); } -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_TEXTURES("renderAlphaMaskTextures"); void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bound_target, bool forceClear) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_TEXTURES); + LL_PROFILE_ZONE_SCOPED; const LLTexLayerSetInfo *info = getInfo(); - bool use_shaders = LLGLSLShader::sNoFixedFunction; - gGL.setColorMask(false, true); gGL.setSceneBlendType(LLRender::BT_REPLACE); @@ -557,7 +527,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, { LLGLSUIDefault gls_ui; gGL.getTexUnit(0)->bind(tex); - gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); gl_rect_2d_simple_tex( width, height ); } } @@ -568,20 +537,14 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, // Set the alpha channel to one (clean up after previous blending) gGL.flush(); LLGLDisable no_alpha(GL_ALPHA_TEST); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } + gAlphaMaskProgram.setMinimumAlpha(0.f); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f( 0.f, 0.f, 0.f, 1.f ); gl_rect_2d_simple( width, height ); gGL.flush(); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.004f); } // (Optional) Mask out part of the baked texture with alpha masks @@ -589,7 +552,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, if (mMaskLayerList.size() > 0) { gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA); - gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) { LLTexLayerInterface* layer = *iter; @@ -602,7 +564,6 @@ void LLTexLayerSet::renderAlphaMaskTextures(S32 x, S32 y, S32 width, S32 height, gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); gGL.setColorMask(true, true); gGL.setSceneBlendType(LLRender::BT_ALPHA); } @@ -1128,13 +1089,6 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou // *TODO: Is this correct? //gPipeline.disableLights(); stop_glerror(); - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHTING); - } - stop_glerror(); - - bool use_shaders = LLGLSLShader::sNoFixedFunction; LLColor4 net_color; BOOL color_specified = findNetColor(&net_color); @@ -1221,10 +1175,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou LLGLDisable alpha_test(no_alpha_test ? GL_ALPHA_TEST : 0); if (no_alpha_test) { - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } + gAlphaMaskProgram.setMinimumAlpha(0.f); } LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); @@ -1238,10 +1189,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); if (no_alpha_test) { - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.004f); } } } @@ -1275,18 +1223,12 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, LLRenderTarget* bou color_specified ) { LLGLDisable no_alpha(GL_ALPHA_TEST); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.000f); - } + gAlphaMaskProgram.setMinimumAlpha(0.000f); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4fv( net_color.mV ); gl_rect_2d_simple( width, height ); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.004f); } if( alpha_mask_specified || getInfo()->mWriteAllChannels ) @@ -1374,25 +1316,17 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) gGL.flush(); - bool use_shaders = LLGLSLShader::sNoFixedFunction; - if( !getInfo()->mStaticImageFileName.empty() ) { LLGLTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); if( tex ) { LLGLSNoAlphaTest gls_no_alpha_test; - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } + gAlphaMaskProgram.setMinimumAlpha(0.f); gGL.getTexUnit(0)->bind(tex, TRUE); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.004f); } else { @@ -1407,18 +1341,11 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) if (tex) { LLGLSNoAlphaTest gls_no_alpha_test; - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } + gAlphaMaskProgram.setMinimumAlpha(0.f); gGL.getTexUnit(0)->bind(tex); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - success = TRUE; - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.004f); } } } @@ -1431,7 +1358,6 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height) addAlphaMask(data, originX, originY, width, height, bound_target); } -static LLTrace::BlockTimerStatHandle FTM_RENDER_MORPH_MASKS("renderMorphMasks"); void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, LLRenderTarget* bound_target, bool force_render) { if (!force_render && !hasMorph()) @@ -1439,18 +1365,12 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC LL_DEBUGS() << "skipping renderMorphMasks for " << getUUID() << LL_ENDL; return; } - LL_RECORD_BLOCK_TIME(FTM_RENDER_MORPH_MASKS); + LL_PROFILE_ZONE_SCOPED; BOOL success = TRUE; llassert( !mParamAlphaList.empty() ); - bool use_shaders = LLGLSLShader::sNoFixedFunction; - - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.f); - } - + gAlphaMaskProgram.setMinimumAlpha(0.f); gGL.setColorMask(false, true); LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin(); @@ -1535,10 +1455,7 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC gl_rect_2d_simple( width, height ); } - if (use_shaders) - { - gAlphaMaskProgram.setMinimumAlpha(0.004f); - } + gAlphaMaskProgram.setMinimumAlpha(0.004f); LLGLSUIDefault gls_ui; @@ -1637,10 +1554,9 @@ void LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC } } -static LLTrace::BlockTimerStatHandle FTM_ADD_ALPHA_MASK("addAlphaMask"); void LLTexLayer::addAlphaMask(U8 *data, S32 originX, S32 originY, S32 width, S32 height, LLRenderTarget* bound_target) { - LL_RECORD_BLOCK_TIME(FTM_ADD_ALPHA_MASK); + LL_PROFILE_ZONE_SCOPED; S32 size = width * height; const U8* alphaData = getAlphaData(); if (!alphaData && hasAlphaParams()) @@ -1981,10 +1897,9 @@ void LLTexLayerStaticImageList::deleteCachedImages() // Returns an LLImageTGA that contains the encoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TGA("getImageTGA"); LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) { - LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TGA); + LL_PROFILE_ZONE_SCOPED; const char *namekey = mImageNames.addString(file_name); image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey); if( iter != mStaticImageListTGA.end() ) @@ -2011,10 +1926,9 @@ LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) // Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -static LLTrace::BlockTimerStatHandle FTM_LOAD_STATIC_TEXTURE("getTexture"); LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) { - LL_RECORD_BLOCK_TIME(FTM_LOAD_STATIC_TEXTURE); + LL_PROFILE_ZONE_SCOPED; LLPointer<LLGLTexture> tex; const char *namekey = mImageNames.addString(file_name); @@ -2061,10 +1975,9 @@ LLGLTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, // Reads a .tga file, decodes it, and puts the decoded data in image_raw. // Returns TRUE if successful. -static LLTrace::BlockTimerStatHandle FTM_LOAD_IMAGE_RAW("loadImageRaw"); BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw) { - LL_RECORD_BLOCK_TIME(FTM_LOAD_IMAGE_RAW); + LL_PROFILE_ZONE_SCOPED; BOOL success = FALSE; std::string path; path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,file_name); diff --git a/indra/llappearance/lltexlayerparams.cpp b/indra/llappearance/lltexlayerparams.cpp index ff682d6906..ce5c7142d5 100644 --- a/indra/llappearance/lltexlayerparams.cpp +++ b/indra/llappearance/lltexlayerparams.cpp @@ -261,10 +261,9 @@ BOOL LLTexLayerParamAlpha::getSkip() const } -static LLTrace::BlockTimerStatHandle FTM_TEX_LAYER_PARAM_ALPHA("alpha render"); BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) { - LL_RECORD_BLOCK_TIME(FTM_TEX_LAYER_PARAM_ALPHA); + LL_PROFILE_ZONE_SCOPED; BOOL success = TRUE; if (!mTexLayer) diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h index 0cb2dedbff..e2440998b3 100644 --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -63,23 +63,14 @@ protected: // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL_ALIGN_PREFIX(16) -class LLTexLayerParamAlpha : public LLTexLayerParam +class alignas(16) LLTexLayerParamAlpha : public LLTexLayerParam { + LL_ALIGN_NEW public: LLTexLayerParamAlpha( LLTexLayerInterface* layer ); LLTexLayerParamAlpha( LLAvatarAppearance* appearance ); /*virtual*/ ~LLTexLayerParamAlpha(); - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; // LLVisualParam Virtual functions @@ -146,9 +137,9 @@ private: // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL_ALIGN_PREFIX(16) -class LLTexLayerParamColor : public LLTexLayerParam +class alignas(16) LLTexLayerParamColor : public LLTexLayerParam { + LL_ALIGN_NEW public: enum EColorOperation { @@ -161,16 +152,6 @@ public: LLTexLayerParamColor( LLTexLayerInterface* layer ); LLTexLayerParamColor( LLAvatarAppearance* appearance ); - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - /* virtual */ ~LLTexLayerParamColor(); /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; @@ -198,8 +179,8 @@ protected: virtual void onGlobalColorChanged() {} private: - LL_ALIGN_16(LLVector4a mAvgDistortionVec); -} LL_ALIGN_POSTFIX(16); + LLVector4a mAvgDistortionVec; +}; class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo { diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index b764ef0c7e..376f096642 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -188,20 +188,15 @@ void LLCharacter::requestStopMotion( LLMotion* motion) //----------------------------------------------------------------------------- // updateMotions() //----------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_UPDATE_ANIMATION("Update Animation"); -static LLTrace::BlockTimerStatHandle FTM_UPDATE_HIDDEN_ANIMATION("Update Hidden Anim"); -static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOTIONS("Update Motions"); - void LLCharacter::updateMotions(e_update_t update_type) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (update_type == HIDDEN_UPDATE) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_HIDDEN_ANIMATION); mMotionController.updateMotionsMinimal(); } else { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_ANIMATION); // unpause if the number of outstanding pause requests has dropped to the initial one if (mMotionController.isPaused() && mPauseRequest->getNumRefs() == 1) { @@ -209,7 +204,6 @@ void LLCharacter::updateMotions(e_update_t update_type) } bool force_update = (update_type == FORCE_UPDATE); { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOTIONS); mMotionController.updateMotions(force_update); } } diff --git a/indra/llcharacter/lleditingmotion.cpp b/indra/llcharacter/lleditingmotion.cpp index ddf89f30f2..c5757163d9 100644 --- a/indra/llcharacter/lleditingmotion.cpp +++ b/indra/llcharacter/lleditingmotion.cpp @@ -163,6 +163,7 @@ BOOL LLEditingMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED; LLVector3 focus_pt; LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint"); diff --git a/indra/llcharacter/lleditingmotion.h b/indra/llcharacter/lleditingmotion.h index 7b1c8bb059..80c1717a70 100644 --- a/indra/llcharacter/lleditingmotion.h +++ b/indra/llcharacter/lleditingmotion.h @@ -42,9 +42,11 @@ //----------------------------------------------------------------------------- // class LLEditingMotion //----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) class LLEditingMotion : public LLMotion { + LL_ALIGN_NEW public: // Constructor LLEditingMotion(const LLUUID &id); @@ -108,6 +110,13 @@ public: //------------------------------------------------------------------------- // joint states to be animated //------------------------------------------------------------------------- + LL_ALIGN_16(LLJoint mParentJoint); + LL_ALIGN_16(LLJoint mShoulderJoint); + LL_ALIGN_16(LLJoint mElbowJoint); + LL_ALIGN_16(LLJoint mWristJoint); + LL_ALIGN_16(LLJoint mTarget); + LLJointSolverRP3 mIKSolver; + LLCharacter *mCharacter; LLVector3 mWristOffset; @@ -117,17 +126,10 @@ public: LLPointer<LLJointState> mWristState; LLPointer<LLJointState> mTorsoState; - LLJoint mParentJoint; - LLJoint mShoulderJoint; - LLJoint mElbowJoint; - LLJoint mWristJoint; - LLJoint mTarget; - LLJointSolverRP3 mIKSolver; - static S32 sHandPose; static S32 sHandPosePriority; LLVector3 mLastSelectPt; -}; +} LL_ALIGN_POSTFIX(16); #endif // LL_LLKEYFRAMEMOTION_H diff --git a/indra/llcharacter/llhandmotion.cpp b/indra/llcharacter/llhandmotion.cpp index b3bf5a9a91..ceba956214 100644 --- a/indra/llcharacter/llhandmotion.cpp +++ b/indra/llcharacter/llhandmotion.cpp @@ -121,6 +121,7 @@ BOOL LLHandMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLHandMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED; eHandPose *requestedHandPose; F32 timeDelta = time - mLastTime; diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp index e91de7a11d..07a3aaebb6 100644 --- a/indra/llcharacter/llheadrotmotion.cpp +++ b/indra/llcharacter/llheadrotmotion.cpp @@ -175,6 +175,7 @@ BOOL LLHeadRotMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; LLQuaternion targetHeadRotWorld; LLQuaternion currentRootRotWorld = mRootJoint->getWorldRotation(); LLQuaternion currentInvRootRotWorld = ~currentRootRotWorld; @@ -458,6 +459,7 @@ void LLEyeMotion::adjustEyeTarget(LLVector3* targetPos, LLJointState& left_eye_s //----------------------------------------------------------------------------- BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; //calculate jitter if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime) { diff --git a/indra/llcharacter/lljoint.cpp b/indra/llcharacter/lljoint.cpp index dee642310e..d72282ab42 100644 --- a/indra/llcharacter/lljoint.cpp +++ b/indra/llcharacter/lljoint.cpp @@ -922,6 +922,13 @@ const LLMatrix4 &LLJoint::getWorldMatrix() return mXform.getWorldMatrix(); } +const LLMatrix4a& LLJoint::getWorldMatrix4a() +{ + updateWorldMatrixParent(); + + return mWorldMatrix; +} + //-------------------------------------------------------------------- // setWorldMatrix() @@ -1003,6 +1010,7 @@ void LLJoint::updateWorldMatrix() { sNumUpdates++; mXform.updateMatrix(FALSE); + mWorldMatrix.loadu(mXform.getWorldMatrix()); mDirtyFlags = 0x0; } } diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index 1b646b641f..63d99b9209 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -38,6 +38,7 @@ #include "m4math.h" #include "llquaternion.h" #include "xform.h" +#include "llmatrix4a.h" const S32 LL_CHARACTER_MAX_JOINTS_PER_MESH = 15; // Need to set this to count of animate-able joints, @@ -85,8 +86,10 @@ inline bool operator!=(const LLVector3OverrideMap& a, const LLVector3OverrideMap //----------------------------------------------------------------------------- // class LLJoint //----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) class LLJoint { + LL_ALIGN_NEW public: // priority levels, from highest to lowest enum JointPriority @@ -114,16 +117,17 @@ public: SUPPORT_EXTENDED }; protected: - std::string mName; + // explicit transformation members + LL_ALIGN_16(LLMatrix4a mWorldMatrix); + LLXformMatrix mXform; + + std::string mName; SupportCategory mSupport; // parent joint LLJoint *mParent; - // explicit transformation members - LLXformMatrix mXform; - LLVector3 mDefaultPosition; LLVector3 mDefaultScale; @@ -259,6 +263,8 @@ public: const LLMatrix4 &getWorldMatrix(); void setWorldMatrix( const LLMatrix4& mat ); + const LLMatrix4a& getWorldMatrix4a(); + void updateWorldMatrixChildren(); void updateWorldMatrixParent(); @@ -296,6 +302,6 @@ public: // These are used in checks of whether a pos/scale override is considered significant. bool aboveJointPosThreshold(const LLVector3& pos) const; bool aboveJointScaleThreshold(const LLVector3& scale) const; -}; +} LL_ALIGN_POSTFIX(16); #endif // LL_LLJOINT_H diff --git a/indra/llcharacter/lljointsolverrp3.cpp b/indra/llcharacter/lljointsolverrp3.cpp index 69a7e3dc6e..f3d5e2e324 100644 --- a/indra/llcharacter/lljointsolverrp3.cpp +++ b/indra/llcharacter/lljointsolverrp3.cpp @@ -1,6 +1,6 @@ /** * @file lljointsolverrp3.cpp - * @brief Implementation of LLJointSolverRP3 class. + * @brief Implementation of Joint Solver in 3D Real Projective space (RP3). See: https://en.wikipedia.org/wiki/Real_projective_space * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code @@ -35,6 +35,11 @@ #define F_EPSILON 0.00001f +#if LL_RELEASE + #define DEBUG_JOINT_SOLVER 0 +#else + #define DEBUG_JOINT_SOLVER 1 +#endif //----------------------------------------------------------------------------- // Constructor @@ -150,6 +155,7 @@ void LLJointSolverRP3::solve() LLVector3 cPos = mJointC->getWorldPosition(); LLVector3 gPos = mJointGoal->getWorldPosition(); +#if DEBUG_JOINT_SOLVER LL_DEBUGS("JointSolver") << "LLJointSolverRP3::solve()" << LL_NEWLINE << "bPosLocal = " << mJointB->getPosition() << LL_NEWLINE << "cPosLocal = " << mJointC->getPosition() << LL_NEWLINE @@ -159,6 +165,7 @@ void LLJointSolverRP3::solve() << "bPos : " << bPos << LL_NEWLINE << "cPos : " << cPos << LL_NEWLINE << "gPos : " << gPos << LL_ENDL; +#endif //------------------------------------------------------------------------- // get the poleVector in world space @@ -194,6 +201,7 @@ void LLJointSolverRP3::solve() //------------------------------------------------------------------------- LLVector3 abacCompOrthoVec = abVec - acVec * ((abVec * acVec)/(acVec * acVec)); +#if DEBUG_JOINT_SOLVER LL_DEBUGS("JointSolver") << "abVec : " << abVec << LL_NEWLINE << "bcVec : " << bcVec << LL_NEWLINE << "acVec : " << acVec << LL_NEWLINE @@ -202,6 +210,7 @@ void LLJointSolverRP3::solve() << "bcLen : " << bcLen << LL_NEWLINE << "agLen : " << agLen << LL_NEWLINE << "abacCompOrthoVec : " << abacCompOrthoVec << LL_ENDL; +#endif //------------------------------------------------------------------------- // compute the normal of the original ABC plane (and store for later) @@ -269,6 +278,7 @@ void LLJointSolverRP3::solve() LLQuaternion bRot(theta - abbcAng, abbcOrthoVec); +#if DEBUG_JOINT_SOLVER LL_DEBUGS("JointSolver") << "abbcAng : " << abbcAng << LL_NEWLINE << "abbcOrthoVec : " << abbcOrthoVec << LL_NEWLINE << "agLenSq : " << agLenSq << LL_NEWLINE @@ -280,6 +290,7 @@ void LLJointSolverRP3::solve() << abbcAng*180.0f/F_PI << " " << (theta - abbcAng)*180.0f/F_PI << LL_ENDL; +#endif //------------------------------------------------------------------------- // compute rotation that rotates new A->C to A->G @@ -293,9 +304,11 @@ void LLJointSolverRP3::solve() LLQuaternion cgRot; cgRot.shortestArc( acVec, agVec ); +#if DEBUG_JOINT_SOLVER LL_DEBUGS("JointSolver") << "bcVec : " << bcVec << LL_NEWLINE << "acVec : " << acVec << LL_NEWLINE << "cgRot : " << cgRot << LL_ENDL; +#endif // update A->B and B->C with rotation from C to G abVec = abVec * cgRot; @@ -358,11 +371,13 @@ void LLJointSolverRP3::solve() //------------------------------------------------------------------------- LLQuaternion twistRot( mTwist, agVec ); +#if DEBUG_JOINT_SOLVER LL_DEBUGS("JointSolver") << "abcNorm = " << abcNorm << LL_NEWLINE << "apgNorm = " << apgNorm << LL_NEWLINE << "pRot = " << pRot << LL_NEWLINE << "twist : " << mTwist*180.0/F_PI << LL_NEWLINE << "twistRot : " << twistRot << LL_ENDL; +#endif //------------------------------------------------------------------------- // compute rotation of A diff --git a/indra/llcharacter/llkeyframefallmotion.cpp b/indra/llcharacter/llkeyframefallmotion.cpp index 7842f0e5fb..e8bb2bf95d 100644 --- a/indra/llcharacter/llkeyframefallmotion.cpp +++ b/indra/llcharacter/llkeyframefallmotion.cpp @@ -121,6 +121,7 @@ BOOL LLKeyframeFallMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; BOOL result = LLKeyframeMotion::onUpdate(activeTime, joint_mask); F32 slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f); diff --git a/indra/llcharacter/llkeyframemotion.cpp b/indra/llcharacter/llkeyframemotion.cpp index fe9de30f0a..a25ff16786 100644 --- a/indra/llcharacter/llkeyframemotion.cpp +++ b/indra/llcharacter/llkeyframemotion.cpp @@ -677,6 +677,7 @@ BOOL LLKeyframeMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLKeyframeMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // llassert(time >= 0.f); // This will fire time = llmax(0.f, time); diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp index 6ed18bc445..aba1c5db39 100644 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ b/indra/llcharacter/llkeyframemotionparam.cpp @@ -158,6 +158,7 @@ BOOL LLKeyframeMotionParam::onActivate() //----------------------------------------------------------------------------- BOOL LLKeyframeMotionParam::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED; F32 weightFactor = 1.f / (F32)mParameterizedMotions.size(); // zero out all pose weights diff --git a/indra/llcharacter/llkeyframestandmotion.h b/indra/llcharacter/llkeyframestandmotion.h index c2634ecd6d..1aa5b187ba 100644 --- a/indra/llcharacter/llkeyframestandmotion.h +++ b/indra/llcharacter/llkeyframestandmotion.h @@ -37,9 +37,11 @@ //----------------------------------------------------------------------------- // class LLKeyframeStandMotion //----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) class LLKeyframeStandMotion : public LLKeyframeMotion { + LL_ALIGN_NEW public: // Constructor LLKeyframeStandMotion(const LLUUID &id); @@ -69,6 +71,18 @@ public: //------------------------------------------------------------------------- // Member Data //------------------------------------------------------------------------- + LLJoint mPelvisJoint; + + LLJoint mHipLeftJoint; + LLJoint mKneeLeftJoint; + LLJoint mAnkleLeftJoint; + LLJoint mTargetLeft; + + LLJoint mHipRightJoint; + LLJoint mKneeRightJoint; + LLJoint mAnkleRightJoint; + LLJoint mTargetRight; + LLCharacter *mCharacter; BOOL mFlipFeet; @@ -83,18 +97,6 @@ public: LLPointer<LLJointState> mKneeRightState; LLPointer<LLJointState> mAnkleRightState; - LLJoint mPelvisJoint; - - LLJoint mHipLeftJoint; - LLJoint mKneeLeftJoint; - LLJoint mAnkleLeftJoint; - LLJoint mTargetLeft; - - LLJoint mHipRightJoint; - LLJoint mKneeRightJoint; - LLJoint mAnkleRightJoint; - LLJoint mTargetRight; - LLJointSolverRP3 mIKLeft; LLJointSolverRP3 mIKRight; @@ -110,7 +112,7 @@ public: BOOL mTrackAnkles; S32 mFrameNum; -}; +} LL_ALIGN_POSTFIX(16); #endif // LL_LLKEYFRAMESTANDMOTION_H diff --git a/indra/llcharacter/llkeyframewalkmotion.cpp b/indra/llcharacter/llkeyframewalkmotion.cpp index f180702385..298b37e60c 100644 --- a/indra/llcharacter/llkeyframewalkmotion.cpp +++ b/indra/llcharacter/llkeyframewalkmotion.cpp @@ -105,6 +105,7 @@ void LLKeyframeWalkMotion::onDeactivate() //----------------------------------------------------------------------------- BOOL LLKeyframeWalkMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED; // compute time since last update F32 deltaTime = time - mRealTimeLast; @@ -198,6 +199,7 @@ BOOL LLWalkAdjustMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED; // delta_time is guaranteed to be non zero F32 delta_time = llclamp(time - mLastTime, TIME_EPSILON, MAX_TIME_DELTA); mLastTime = time; @@ -373,6 +375,7 @@ BOOL LLFlyAdjustMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED; LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation(); F32 speed = mCharacter->getCharacterVelocity().magVec(); diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index c48d02b652..e66714388a 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -503,6 +503,7 @@ void LLMotionController::resetJointSignatures() //----------------------------------------------------------------------------- void LLMotionController::updateIdleMotion(LLMotion* motionp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (motionp->isStopped() && mAnimTime > motionp->getStopTime() + motionp->getEaseOutDuration()) { deactivateMotionInstance(motionp); @@ -541,6 +542,7 @@ void LLMotionController::updateIdleMotion(LLMotion* motionp) //----------------------------------------------------------------------------- void LLMotionController::updateIdleActiveMotions() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; for (motion_list_t::iterator iter = mActiveMotions.begin(); iter != mActiveMotions.end(); ) { @@ -553,10 +555,9 @@ void LLMotionController::updateIdleActiveMotions() //----------------------------------------------------------------------------- // updateMotionsByType() //----------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_MOTION_ON_UPDATE("Motion onUpdate"); - void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_type) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; BOOL update_result = TRUE; U8 last_joint_signature[LL_CHARACTER_MAX_ANIMATED_JOINTS]; @@ -712,7 +713,6 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty // perform motion update { - LL_RECORD_BLOCK_TIME(FTM_MOTION_ON_UPDATE); update_result = motionp->onUpdate(mAnimTime - motionp->mActivationTimestamp, last_joint_signature); } } @@ -768,6 +768,7 @@ void LLMotionController::updateMotionsByType(LLMotion::LLMotionBlendType anim_ty //----------------------------------------------------------------------------- void LLMotionController::updateLoadingMotions() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // query pending motions for completion for (motion_set_t::iterator iter = mLoadingMotions.begin(); iter != mLoadingMotions.end(); ) @@ -815,6 +816,7 @@ void LLMotionController::updateLoadingMotions() //----------------------------------------------------------------------------- void LLMotionController::updateMotions(bool force_update) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // SL-763: "Distant animated objects run at super fast speed" // The use_quantum optimization or possibly the associated code in setTimeStamp() // does not work as implemented. @@ -907,6 +909,7 @@ void LLMotionController::updateMotions(bool force_update) //----------------------------------------------------------------------------- void LLMotionController::updateMotionsMinimal() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // Always update mPrevTimerElapsed mPrevTimerElapsed = mTimer.getElapsedTimeF32(); @@ -924,6 +927,7 @@ void LLMotionController::updateMotionsMinimal() //----------------------------------------------------------------------------- BOOL LLMotionController::activateMotionInstance(LLMotion *motion, F32 time) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // It's not clear why the getWeight() line seems to be crashing this, but // hopefully this fixes it. if (motion == NULL || motion->getPose() == NULL) diff --git a/indra/llcharacter/llpose.h b/indra/llcharacter/llpose.h index c004a0f3b7..1405f1e053 100644 --- a/indra/llcharacter/llpose.h +++ b/indra/llcharacter/llpose.h @@ -80,8 +80,10 @@ public: const S32 JSB_NUM_JOINT_STATES = 6; +LL_ALIGN_PREFIX(16) class LLJointStateBlender { + LL_ALIGN_NEW protected: LLPointer<LLJointState> mJointStates[JSB_NUM_JOINT_STATES]; S32 mPriorities[JSB_NUM_JOINT_STATES]; @@ -96,8 +98,8 @@ public: void resetCachedJoint(); public: - LLJoint mJointCache; -}; + LL_ALIGN_16(LLJoint mJointCache); +} LL_ALIGN_POSTFIX(16); class LLMotion; diff --git a/indra/llcharacter/lltargetingmotion.cpp b/indra/llcharacter/lltargetingmotion.cpp index 69681e4197..ec75212a40 100644 --- a/indra/llcharacter/lltargetingmotion.cpp +++ b/indra/llcharacter/lltargetingmotion.cpp @@ -103,6 +103,7 @@ BOOL LLTargetingMotion::onActivate() //----------------------------------------------------------------------------- BOOL LLTargetingMotion::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED; F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TORSO_TARGET_HALF_LIFE); LLVector3 target; diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 766a1849f9..ca8b5e946f 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -12,6 +12,7 @@ include(JsonCpp) include(Copy3rdPartyLibs) include(ZLIB) include(URIPARSER) +include(Tracy) include_directories( ${EXPAT_INCLUDE_DIRS} @@ -19,6 +20,7 @@ include_directories( ${JSONCPP_INCLUDE_DIR} ${ZLIB_INCLUDE_DIRS} ${URIPARSER_INCLUDE_DIRS} + ${TRACY_INCLUDE_DIR} ) # add_executable(lltreeiterators lltreeiterators.cpp) @@ -117,14 +119,16 @@ set(llcommon_SOURCE_FILES lluriparser.cpp lluuid.cpp llworkerthread.cpp - timing.cpp u64.cpp + threadpool.cpp + workqueue.cpp StackWalker.cpp ) set(llcommon_HEADER_FILES CMakeLists.txt + chrono.h ctype_workaround.h fix_macros.h indra_constants.h @@ -197,6 +201,8 @@ set(llcommon_HEADER_FILES llmortician.h llnametable.h llpointer.h + llprofiler.h + llprofilercategories.h llpounceable.h llpredicate.h llpreprocessor.h @@ -251,8 +257,12 @@ set(llcommon_HEADER_FILES lockstatic.h stdtypes.h stringize.h + threadpool.h + threadsafeschedule.h timer.h + tuple.h u64.h + workqueue.h StackWalker.h ) @@ -299,6 +309,7 @@ target_link_libraries( ${BOOST_SYSTEM_LIBRARY} ${GOOGLE_PERFTOOLS_LIBRARIES} ${URIPARSER_LIBRARIES} + ${TRACY_LIBRARY} ) if (DARWIN) @@ -355,6 +366,9 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}") LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(threadsafeschedule "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(tuple "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(workqueue "" "${test_libs}") ## llexception_test.cpp isn't a regression test, and doesn't need to be run ## every build. It's to help a developer make implementation choices about diff --git a/indra/llcommon/chrono.h b/indra/llcommon/chrono.h new file mode 100644 index 0000000000..806e871892 --- /dev/null +++ b/indra/llcommon/chrono.h @@ -0,0 +1,65 @@ +/** + * @file chrono.h + * @author Nat Goodspeed + * @date 2021-10-05 + * @brief supplement <chrono> with utility functions + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_CHRONO_H) +#define LL_CHRONO_H + +#include <chrono> +#include <type_traits> // std::enable_if + +namespace LL +{ + +// time_point_cast() is derived from https://stackoverflow.com/a/35293183 +// without the iteration: we think errors in the ~1 microsecond range are +// probably acceptable. + +// This variant is for the optimal case when the source and dest use the same +// clock: that case is handled by std::chrono. +template <typename DestTimePoint, typename SrcTimePoint, + typename std::enable_if<std::is_same<typename DestTimePoint::clock, + typename SrcTimePoint::clock>::value, + bool>::type = true> +DestTimePoint time_point_cast(const SrcTimePoint& time) +{ + return std::chrono::time_point_cast<typename DestTimePoint::duration>(time); +} + +// This variant is for when the source and dest use different clocks -- see +// the linked StackOverflow answer, also Howard Hinnant's, for more context. +template <typename DestTimePoint, typename SrcTimePoint, + typename std::enable_if<! std::is_same<typename DestTimePoint::clock, + typename SrcTimePoint::clock>::value, + bool>::type = true> +DestTimePoint time_point_cast(const SrcTimePoint& time) +{ + // The basic idea is that we must adjust the passed time_point by the + // difference between the clocks' epochs. But since time_point doesn't + // expose its epoch, we fall back on what each of them thinks is now(). + // However, since we necessarily make sequential calls to those now() + // functions, the answers differ not only by the cycles spent executing + // those calls, but by potential OS interruptions between them. Try to + // reduce that error by capturing the source clock time both before and + // after the dest clock, and splitting the difference. Of course an + // interruption between two of these now() calls without a comparable + // interruption between the other two will skew the result, but better is + // more expensive. + const auto src_before = typename SrcTimePoint::clock::now(); + const auto dest_now = typename DestTimePoint::clock::now(); + const auto src_after = typename SrcTimePoint::clock::now(); + const auto src_diff = src_after - src_before; + const auto src_now = src_before + src_diff / 2; + return dest_now + (time - src_now); +} + +} // namespace LL + +#endif /* ! defined(LL_CHRONO_H) */ diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index e5a913a6a9..a228fd22be 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -27,6 +27,14 @@ #ifndef LL_LINDEN_COMMON_H #define LL_LINDEN_COMMON_H +#include "llprofiler.h" +#if TRACY_ENABLE && !defined(LL_PROFILER_ENABLE_TRACY_OPENGL) // hooks for memory profiling +void *tracy_aligned_malloc(size_t size, size_t alignment); +void tracy_aligned_free(void *memblock); +#define _aligned_malloc(X, Y) tracy_aligned_malloc((X), (Y)) +#define _aligned_free(X) tracy_aligned_free((X)) +#endif + // *NOTE: Please keep includes here to a minimum! // // Files included here are included in every library .cpp file and diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 96be913d17..d2c4e66160 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -33,6 +33,66 @@ #include "lltracethreadrecorder.h" #include "llcleanup.h" +thread_local bool gProfilerEnabled = false; + +#if (TRACY_ENABLE) +// Override new/delete for tracy memory profiling +void *operator new(size_t size) +{ + void* ptr; + if (gProfilerEnabled) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; + ptr = (malloc)(size); + } + else + { + ptr = (malloc)(size); + } + if (!ptr) + { + throw std::bad_alloc(); + } + TracyAlloc(ptr, size); + return ptr; +} + +void operator delete(void *ptr) noexcept +{ + TracyFree(ptr); + if (gProfilerEnabled) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; + (free)(ptr); + } + else + { + (free)(ptr); + } +} + +// C-style malloc/free can't be so easily overridden, so we define tracy versions and use +// a pre-processor #define in linden_common.h to redirect to them. The parens around the native +// functions below prevents recursive substitution by the preprocessor. +// +// Unaligned mallocs are rare in LL code but hooking them causes problems in 3p lib code (looking at +// you, Havok), so we'll only capture the aligned version. + +void *tracy_aligned_malloc(size_t size, size_t alignment) +{ + auto ptr = ll_aligned_malloc_fallback(size, alignment); + if (ptr) TracyAlloc(ptr, size); + return ptr; +} + +void tracy_aligned_free(void *memblock) +{ + TracyFree(memblock); + ll_aligned_free_fallback(memblock); +} + +#endif + //static BOOL LLCommon::sAprInitialized = FALSE; diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h index e31b67d893..da6e6affe1 100644 --- a/indra/llcommon/llcond.h +++ b/indra/llcommon/llcond.h @@ -53,6 +53,8 @@ private: LLCoros::Mutex mMutex; // Use LLCoros::ConditionVariable for the same reason. LLCoros::ConditionVariable mCond; + using LockType = LLCoros::LockType; + using cv_status = LLCoros::cv_status; public: /// LLCond can be explicitly initialized with a specific value for mData if @@ -65,10 +67,29 @@ public: LLCond(const LLCond&) = delete; LLCond& operator=(const LLCond&) = delete; - /// get() returns a const reference to the stored DATA. The only way to - /// get a non-const reference -- to modify the stored DATA -- is via - /// update_one() or update_all(). - const value_type& get() const { return mData; } + /** + * get() returns the stored DATA by value -- so to use get(), DATA must + * be copyable. The only way to get a non-const reference -- to modify + * the stored DATA -- is via update_one() or update_all(). + */ + value_type get() + { + LockType lk(mMutex); + return mData; + } + + /** + * get(functor) returns whatever the functor returns. It allows us to peek + * at the stored DATA without copying the whole thing. The functor must + * accept a const reference to DATA. If you want to modify DATA, call + * update_one() or update_all() instead. + */ + template <typename FUNC> + auto get(FUNC&& func) + { + LockType lk(mMutex); + return std::forward<FUNC>(func)(const_data()); + } /** * Pass update_one() an invocable accepting non-const (DATA&). The @@ -80,11 +101,11 @@ public: * update_one() when DATA is a struct or class. */ template <typename MODIFY> - void update_one(MODIFY modify) + void update_one(MODIFY&& modify) { { // scope of lock can/should end before notify_one() - LLCoros::LockType lk(mMutex); - modify(mData); + LockType lk(mMutex); + std::forward<MODIFY>(modify)(mData); } mCond.notify_one(); } @@ -99,11 +120,11 @@ public: * update_all() when DATA is a struct or class. */ template <typename MODIFY> - void update_all(MODIFY modify) + void update_all(MODIFY&& modify) { { // scope of lock can/should end before notify_all() - LLCoros::LockType lk(mMutex); - modify(mData); + LockType lk(mMutex); + std::forward<MODIFY>(modify)(mData); } mCond.notify_all(); } @@ -116,9 +137,9 @@ public: * wait() on the condition_variable. */ template <typename Pred> - void wait(Pred pred) + void wait(Pred&& pred) { - LLCoros::LockType lk(mMutex); + LockType lk(mMutex); // We must iterate explicitly since the predicate accepted by // condition_variable::wait() requires a different signature: // condition_variable::wait() calls its predicate with no arguments. @@ -127,7 +148,7 @@ public: // But what if they instead pass a predicate accepting non-const // (DATA&)? Such a predicate could modify mData, which would be Bad. // Forbid that. - while (! pred(const_cast<const value_type&>(mData))) + while (! std::forward<Pred>(pred)(const_data())) { mCond.wait(lk); } @@ -144,7 +165,7 @@ public: * returning true. */ template <typename Rep, typename Period, typename Pred> - bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred pred) + bool wait_for(const std::chrono::duration<Rep, Period>& timeout_duration, Pred&& pred) { // Instead of replicating wait_until() logic, convert duration to // time_point and just call wait_until(). @@ -153,7 +174,8 @@ public: // wrong! We'd keep pushing the timeout time farther and farther into // the future. This way, we establish a definite timeout time and // stick to it. - return wait_until(std::chrono::steady_clock::now() + timeout_duration, pred); + return wait_until(std::chrono::steady_clock::now() + timeout_duration, + std::forward<Pred>(pred)); } /** @@ -163,9 +185,9 @@ public: * generic wait_for() method. */ template <typename Pred> - bool wait_for(F32Milliseconds timeout_duration, Pred pred) + bool wait_for(F32Milliseconds timeout_duration, Pred&& pred) { - return wait_for(convert(timeout_duration), pred); + return wait_for(convert(timeout_duration), std::forward<Pred>(pred)); } protected: @@ -183,6 +205,10 @@ protected: } private: + // It's important to pass a const ref to certain user-specified functors + // that aren't supposed to be able to modify mData. + const value_type& const_data() const { return mData; } + /** * Pass wait_until() a chrono::time_point, indicating the time at which we * should stop waiting, and a predicate accepting (const DATA&), returning @@ -203,21 +229,21 @@ private: * honoring a fixed timeout. */ template <typename Clock, typename Duration, typename Pred> - bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred pred) + bool wait_until(const std::chrono::time_point<Clock, Duration>& timeout_time, Pred&& pred) { - LLCoros::LockType lk(mMutex); + LockType lk(mMutex); // We advise the caller to pass a predicate accepting (const DATA&). // But what if they instead pass a predicate accepting non-const // (DATA&)? Such a predicate could modify mData, which would be Bad. // Forbid that. - while (! pred(const_cast<const value_type&>(mData))) + while (! std::forward<Pred>(pred)(const_data())) { - if (LLCoros::cv_status::timeout == mCond.wait_until(lk, timeout_time)) + if (cv_status::timeout == mCond.wait_until(lk, timeout_time)) { // It's possible that wait_until() timed out AND the predicate // became true more or less simultaneously. Even though // wait_until() timed out, check the predicate one more time. - return pred(const_cast<const value_type&>(mData)); + return std::forward<Pred>(pred)(const_data()); } } return true; diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 7a2a0869f4..2ddcf40895 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -86,11 +86,9 @@ std::string LLDate::asRFC1123() const return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } -LLTrace::BlockTimerStatHandle FT_DATE_FORMAT("Date Format"); - std::string LLDate::toHTTPDateString (std::string fmt) const { - LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT); + LL_PROFILE_ZONE_SCOPED; time_t locSeconds = (time_t) mSecondsSinceEpoch; struct tm * gmt = gmtime (&locSeconds); @@ -99,7 +97,7 @@ std::string LLDate::toHTTPDateString (std::string fmt) const std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) { - LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT); + LL_PROFILE_ZONE_SCOPED; // avoid calling setlocale() unnecessarily - it's expensive. static std::string prev_locale = ""; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 55a06f8326..919d2dabc4 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -109,6 +109,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING int syslogPriority = LOG_CRIT; switch (level) { case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break; @@ -166,6 +167,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING if (LLError::getAlwaysFlush()) { mFile << message << std::endl; @@ -194,7 +196,7 @@ namespace { { return LLError::getEnabledLogTypesMask() & 0x04; } - + LL_FORCE_INLINE std::string createBoldANSI() { std::string ansi_code; @@ -220,10 +222,10 @@ namespace { LL_FORCE_INLINE std::string createANSI(const std::string& color) { std::string ansi_code; - ansi_code += '\033'; - ansi_code += "["; + ansi_code += '\033'; + ansi_code += "["; ansi_code += "38;5;"; - ansi_code += color; + ansi_code += color; ansi_code += "m"; return ansi_code; @@ -232,6 +234,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING // The default colors for error, warn and debug are now a bit more pastel // and easier to read on the default (black) terminal background but you // now have the option to set the color of each via an environment variables: @@ -261,6 +264,7 @@ namespace { } else { + LL_PROFILE_ZONE_NAMED("fprintf"); fprintf(stderr, "%s\n", message.c_str()); } } @@ -270,6 +274,7 @@ namespace { LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING static std::string s_ansi_bold = createBoldANSI(); // bold text static std::string s_ansi_reset = createResetANSI(); // reset // ANSI color code escape sequence, message, and reset in one fprintf call @@ -306,6 +311,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING mBuffer->addLine(message); } @@ -332,6 +338,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING debugger_print(message); } }; @@ -1210,6 +1217,7 @@ namespace void writeToRecorders(const LLError::CallSite& site, const std::string& message) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING LLError::ELevel level = site.mLevel; SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); @@ -1344,6 +1352,7 @@ namespace LLError bool Log::shouldLog(CallSite& site) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5); if (!lock.isLocked()) { @@ -1388,6 +1397,7 @@ namespace LLError void Log::flush(const std::ostringstream& out, const CallSite& site) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5); if (!lock.isLocked()) { diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index d439136ca8..d06c0e2132 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -35,7 +35,9 @@ #include "stdtypes.h" +#include "llprofiler.h" #include "llpreprocessor.h" + #include <boost/static_assert.hpp> const int LL_ERR_NOERR = 0; @@ -348,7 +350,8 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL; #define lllog(level, once, ...) \ - do { \ + do { \ + LL_PROFILE_ZONE_NAMED("lllog"); \ const char* tags[] = {"", ##__VA_ARGS__}; \ static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \ lllog_test_() diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index e87bb7bf35..57f10b7895 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -190,6 +190,7 @@ namespace LLError {} void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED mCallable(level, message); } private: diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index 48c2570732..7613850fb2 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -429,6 +429,8 @@ public: // path, then stores it to mTarget. virtual bool post(const LLSD& event) { + LL_PROFILE_ZONE_SCOPED + // Extract the element specified by 'mPath' from 'event'. To perform a // generic type-appropriate store through mTarget, construct an // LLSDParam<T> and store that, thus engaging LLSDParam's custom diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index b584b0ff8b..46560b5e4c 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -97,6 +97,11 @@ static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) { + const auto stack = to_string(boost::stacktrace::stacktrace()); + LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code + << "\n Stack trace: \n" + << stack << LL_ENDL; + if (code == STATUS_MSC_EXCEPTION) { // C++ exception, go on diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 5b6a7b82f8..2612d0f07c 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -191,29 +191,30 @@ TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const } + void BlockTimer::bootstrapTimerTree() { - for (auto& base : BlockTimerStatHandle::instance_snapshot()) - { - // because of indirect derivation from LLInstanceTracker, have to downcast - BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); - if (&timer == &BlockTimer::getRootTimeBlock()) continue; - - // bootstrap tree construction by attaching to last timer to be on stack - // when this timer was called - if (timer.getParent() == &BlockTimer::getRootTimeBlock()) - { - TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); - - if (accumulator.mLastCaller) - { - timer.setParent(accumulator.mLastCaller); - accumulator.mParent = accumulator.mLastCaller; - } - // no need to push up tree on first use, flag can be set spuriously - accumulator.mMoveUpTree = false; - } - } + for (auto& base : BlockTimerStatHandle::instance_snapshot()) + { + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(base); + if (&timer == &BlockTimer::getRootTimeBlock()) continue; + + // bootstrap tree construction by attaching to last timer to be on stack + // when this timer was called + if (timer.getParent() == &BlockTimer::getRootTimeBlock()) + { + TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); + + if (accumulator.mLastCaller) + { + timer.setParent(accumulator.mLastCaller); + accumulator.mParent = accumulator.mLastCaller; + } + // no need to push up tree on first use, flag can be set spuriously + accumulator.mMoveUpTree = false; + } + } } // bump timers up tree if they have been flagged as being in the wrong place @@ -221,6 +222,7 @@ void BlockTimer::bootstrapTimerTree() // this preserves partial order derived from current frame's observations void BlockTimer::incrementalUpdateTimerTree() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock()); it != end_block_timer_tree_df_post(); ++it) @@ -260,7 +262,8 @@ void BlockTimer::incrementalUpdateTimerTree() void BlockTimer::updateTimes() - { +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; // walk up stack of active timers and accumulate current time while leaving timing structures active BlockTimerStackRecord* stack_record = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); if (!stack_record) return; @@ -271,7 +274,7 @@ void BlockTimer::updateTimes() while(cur_timer && cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self - { + { U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; cur_timer->mStartTime = cur_time; diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index dfc63d08a2..9bd93d7240 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -38,7 +38,10 @@ #define LL_FAST_TIMER_ON 1 #define LL_FASTTIMER_USE_RDTSC 1 +// NOTE: Also see llprofiler.h +#if !defined(LL_PROFILER_CONFIGURATION) #define LL_RECORD_BLOCK_TIME(timer_stat) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__); +#endif // LL_PROFILER_CONFIGURATION namespace LLTrace { diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp index 1e9920746b..c54029e8b4 100644 --- a/indra/llcommon/llframetimer.cpp +++ b/indra/llcommon/llframetimer.cpp @@ -29,6 +29,11 @@ #include "llframetimer.h" +// We don't bother building a stand alone lib; we just need to include the one source file for Tracy support +#if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER + #include "TracyClient.cpp" +#endif // LL_PROFILER_CONFIGURATION + // Static members //LLTimer LLFrameTimer::sInternalTimer; U64 LLFrameTimer::sStartTotalTime = totalTime(); diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 402333cca7..02535a59e7 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -83,13 +83,34 @@ class LLInstanceTracker typedef llthread::LockStatic<StaticData> LockStatic; public: + using ptr_t = std::shared_ptr<T>; + using weak_t = std::weak_ptr<T>; + + /** + * Storing a dumb T* somewhere external is a bad idea, since + * LLInstanceTracker subclasses are explicitly destroyed rather than + * managed by smart pointers. It's legal to declare stack instances of an + * LLInstanceTracker subclass. But it's reasonable to store a + * std::weak_ptr<T>, which will become invalid when the T instance is + * destroyed. + */ + weak_t getWeak() + { + return mSelf; + } + + static S32 instanceCount() + { + return LockStatic()->mMap.size(); + } + // snapshot of std::pair<const KEY, std::shared_ptr<T>> pairs class snapshot { // It's very important that what we store in this snapshot are // weak_ptrs, NOT shared_ptrs. That's how we discover whether any // instance has been deleted during the lifespan of a snapshot. - typedef std::vector<std::pair<const KEY, std::weak_ptr<T>>> VectorType; + typedef std::vector<std::pair<const KEY, weak_t>> VectorType; // Dereferencing our iterator produces a std::shared_ptr for each // instance that still exists. Since we store weak_ptrs, that involves // two chained transformations: @@ -98,7 +119,7 @@ public: // It is very important that we filter lazily, that is, during // traversal. Any one of our stored weak_ptrs might expire during // traversal. - typedef std::pair<const KEY, std::shared_ptr<T>> strong_pair; + typedef std::pair<const KEY, ptr_t> strong_pair; // Note for future reference: nat has not yet had any luck (up to // Boost 1.67) trying to use boost::transform_iterator with a hand- // coded functor, only with actual functions. In my experience, an @@ -202,17 +223,12 @@ public: iterator end() { return iterator(snapshot::end(), key_getter); } }; - static T* getInstance(const KEY& k) + static ptr_t getInstance(const KEY& k) { LockStatic lock; const InstanceMap& map(lock->mMap); typename InstanceMap::const_iterator found = map.find(k); - return (found == map.end()) ? NULL : found->second.get(); - } - - static S32 instanceCount() - { - return LockStatic()->mMap.size(); + return (found == map.end()) ? NULL : found->second; } protected: @@ -222,7 +238,9 @@ protected: // shared_ptr, so give it a no-op deleter. We store shared_ptrs in our // InstanceMap specifically so snapshot can store weak_ptrs so we can // detect deletions during traversals. - std::shared_ptr<T> ptr(static_cast<T*>(this), [](T*){}); + ptr_t ptr(static_cast<T*>(this), [](T*){}); + // save corresponding weak_ptr for future reference + mSelf = ptr; LockStatic lock; add_(lock, key, ptr); } @@ -257,7 +275,7 @@ private: static std::string report(const char* key) { return report(std::string(key)); } // caller must instantiate LockStatic - void add_(LockStatic& lock, const KEY& key, const std::shared_ptr<T>& ptr) + void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr) { mInstanceKey = key; InstanceMap& map = lock->mMap; @@ -281,7 +299,7 @@ private: break; } } - std::shared_ptr<T> remove_(LockStatic& lock) + ptr_t remove_(LockStatic& lock) { InstanceMap& map = lock->mMap; typename InstanceMap::iterator iter = map.find(mInstanceKey); @@ -295,6 +313,9 @@ private: } private: + // Storing a weak_ptr to self is a bit like deriving from + // std::enable_shared_from_this(), except more explicit. + weak_t mSelf; KEY mInstanceKey; }; @@ -326,6 +347,9 @@ class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> typedef llthread::LockStatic<StaticData> LockStatic; public: + using ptr_t = std::shared_ptr<T>; + using weak_t = std::weak_ptr<T>; + /** * Storing a dumb T* somewhere external is a bad idea, since * LLInstanceTracker subclasses are explicitly destroyed rather than @@ -334,12 +358,15 @@ public: * std::weak_ptr<T>, which will become invalid when the T instance is * destroyed. */ - std::weak_ptr<T> getWeak() + weak_t getWeak() { return mSelf; } - static S32 instanceCount() { return LockStatic()->mSet.size(); } + static S32 instanceCount() + { + return LockStatic()->mSet.size(); + } // snapshot of std::shared_ptr<T> pointers class snapshot @@ -347,7 +374,7 @@ public: // It's very important that what we store in this snapshot are // weak_ptrs, NOT shared_ptrs. That's how we discover whether any // instance has been deleted during the lifespan of a snapshot. - typedef std::vector<std::weak_ptr<T>> VectorType; + typedef std::vector<weak_t> VectorType; // Dereferencing our iterator produces a std::shared_ptr for each // instance that still exists. Since we store weak_ptrs, that involves // two chained transformations: @@ -453,7 +480,7 @@ protected: private: // Storing a weak_ptr to self is a bit like deriving from // std::enable_shared_from_this(), except more explicit. - std::weak_ptr<T> mSelf; + weak_t mSelf; }; #endif diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp index 3e6ce9092c..11bfec1b31 100644 --- a/indra/llcommon/llleaplistener.cpp +++ b/indra/llcommon/llleaplistener.cpp @@ -220,7 +220,7 @@ void LLLeapListener::getAPI(const LLSD& request) const { Response reply(LLSD(), request); - LLEventAPI* found = LLEventAPI::getInstance(request["api"]); + auto found = LLEventAPI::getInstance(request["api"]); if (found) { reply["name"] = found->getName(); diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index ea84e4c1ea..849867586a 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -82,6 +82,7 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size) //static void LLMemory::updateMemoryInfo() { + LL_PROFILE_ZONE_SCOPED #if LL_WINDOWS PROCESS_MEMORY_COUNTERS counters; @@ -145,6 +146,7 @@ void* LLMemory::tryToAlloc(void* address, U32 size) //static void LLMemory::logMemoryInfo(BOOL update) { + LL_PROFILE_ZONE_SCOPED if(update) { updateMemoryInfo() ; diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 24f86cc11e..ac6c969d70 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -101,6 +101,29 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) #define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16) +#define LL_ALIGN_NEW \ +public: \ + void* operator new(size_t size) \ + { \ + return ll_aligned_malloc_16(size); \ + } \ + \ + void operator delete(void* ptr) \ + { \ + ll_aligned_free_16(ptr); \ + } \ + \ + void* operator new[](size_t size) \ + { \ + return ll_aligned_malloc_16(size); \ + } \ + \ + void operator delete[](void* ptr) \ + { \ + ll_aligned_free_16(ptr); \ + } + + //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ // for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library @@ -113,8 +136,9 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) #else inline void* ll_aligned_malloc_fallback( size_t size, int align ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #if defined(LL_WINDOWS) - return _aligned_malloc(size, align); + void* ret = _aligned_malloc(size, align); #else char* aligned = NULL; void* mem = malloc( size + (align - 1) + sizeof(void*) ); @@ -125,12 +149,16 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) ((void**)aligned)[-1] = mem; } - return aligned; + void* ret = aligned; #endif + LL_PROFILE_ALLOC(ret, size); + return ret; } inline void ll_aligned_free_fallback( void* ptr ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; + LL_PROFILE_FREE(ptr); #if defined(LL_WINDOWS) _aligned_free(ptr); #else @@ -146,21 +174,24 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16(). { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #if defined(LL_WINDOWS) - return _aligned_malloc(size, 16); + void* ret = _aligned_malloc(size, 16); #elif defined(LL_DARWIN) - return malloc(size); // default osx malloc is 16 byte aligned. + void* ret = malloc(size); // default osx malloc is 16 byte aligned. #else - void *rtn; - if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size))) - return rtn; - else // bad alignment requested, or out of memory - return NULL; + void *ret; + if (0 != posix_memalign(&ret, 16, size)) + return nullptr; #endif + LL_PROFILE_ALLOC(ret, size); + return ret; } inline void ll_aligned_free_16(void *p) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; + LL_PROFILE_FREE(p); #if defined(LL_WINDOWS) _aligned_free(p); #elif defined(LL_DARWIN) @@ -172,10 +203,12 @@ inline void ll_aligned_free_16(void *p) inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // returned hunk MUST be freed with ll_aligned_free_16(). { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; + LL_PROFILE_FREE(ptr); #if defined(LL_WINDOWS) - return _aligned_realloc(ptr, size, 16); + void* ret = _aligned_realloc(ptr, size, 16); #elif defined(LL_DARWIN) - return realloc(ptr,size); // default osx malloc is 16 byte aligned. + void* ret = realloc(ptr,size); // default osx malloc is 16 byte aligned. #else //FIXME: memcpy is SLOW void* ret = ll_aligned_malloc_16(size); @@ -188,27 +221,31 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r } ll_aligned_free_16(ptr); } - return ret; #endif + LL_PROFILE_ALLOC(ptr, size); + return ret; } inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32(). { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #if defined(LL_WINDOWS) - return _aligned_malloc(size, 32); + void* ret = _aligned_malloc(size, 32); #elif defined(LL_DARWIN) - return ll_aligned_malloc_fallback( size, 32 ); + void* ret = ll_aligned_malloc_fallback( size, 32 ); #else - void *rtn; - if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size))) - return rtn; - else // bad alignment requested, or out of memory - return NULL; + void *ret; + if (0 != posix_memalign(&ret, 32, size)) + return nullptr; #endif + LL_PROFILE_ALLOC(ret, size); + return ret; } inline void ll_aligned_free_32(void *p) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; + LL_PROFILE_FREE(p); #if defined(LL_WINDOWS) _aligned_free(p); #elif defined(LL_DARWIN) @@ -222,29 +259,35 @@ inline void ll_aligned_free_32(void *p) template<size_t ALIGNMENT> LL_FORCE_INLINE void* ll_aligned_malloc(size_t size) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; + void* ret; if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0) { - return malloc(size); + ret = malloc(size); + LL_PROFILE_ALLOC(ret, size); } else if (ALIGNMENT == 16) { - return ll_aligned_malloc_16(size); + ret = ll_aligned_malloc_16(size); } else if (ALIGNMENT == 32) { - return ll_aligned_malloc_32(size); + ret = ll_aligned_malloc_32(size); } else { - return ll_aligned_malloc_fallback(size, ALIGNMENT); + ret = ll_aligned_malloc_fallback(size, ALIGNMENT); } + return ret; } template<size_t ALIGNMENT> LL_FORCE_INLINE void ll_aligned_free(void* ptr) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN) { + LL_PROFILE_FREE(ptr); free(ptr); } else if (ALIGNMENT == 16) @@ -266,6 +309,7 @@ LL_FORCE_INLINE void ll_aligned_free(void* ptr) // inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; assert(src != NULL); assert(dst != NULL); assert(bytes > 0); diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 4d73c04d07..0273dd5970 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -44,6 +44,7 @@ LLMutex::~LLMutex() void LLMutex::lock() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if(isSelfLocked()) { //redundant lock mCount++; @@ -65,6 +66,7 @@ void LLMutex::lock() void LLMutex::unlock() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if (mCount > 0) { //not the root unlock mCount--; @@ -85,6 +87,7 @@ void LLMutex::unlock() bool LLMutex::isLocked() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if (!mMutex.try_lock()) { return true; @@ -108,6 +111,7 @@ LLThread::id_t LLMutex::lockingThread() const bool LLMutex::trylock() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if(isSelfLocked()) { //redundant lock mCount++; @@ -146,17 +150,20 @@ LLCondition::~LLCondition() void LLCondition::wait() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD std::unique_lock< std::mutex > lock(mMutex); mCond.wait(lock); } void LLCondition::signal() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD mCond.notify_one(); } void LLCondition::broadcast() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD mCond.notify_all(); } @@ -166,6 +173,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex) : mMutex(mutex), mLocked(false) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if (mMutex) mLocked = mMutex->trylock(); } @@ -174,6 +182,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms) : mMutex(mutex), mLocked(false) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if (!mMutex) return; @@ -188,6 +197,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms) LLMutexTrylock::~LLMutexTrylock() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if (mMutex && mLocked) mMutex->unlock(); } @@ -199,6 +209,7 @@ LLMutexTrylock::~LLMutexTrylock() // LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if(mutex) { mutex->lock(); @@ -217,6 +228,7 @@ LLScopedLock::~LLScopedLock() void LLScopedLock::unlock() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if(mLocked) { mMutex->unlock(); diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index b17a8e761a..dc586b0008 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -171,7 +171,9 @@ #define LL_DLLIMPORT #endif // LL_WINDOWS -#if ! defined(LL_WINDOWS) +#if __clang__ || ! defined(LL_WINDOWS) +// Only on Windows, and only with the Microsoft compiler (vs. clang) is +// wchar_t potentially not a distinct type. #define LL_WCHAR_T_NATIVE 1 #else // LL_WINDOWS // https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 5d16a4b74d..818df07bb2 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -44,20 +44,6 @@ #include "llsd.h" -#if LL_MSVC && _M_X64 -# define LL_X86_64 1 -# define LL_X86 1 -#elif LL_MSVC && _M_IX86 -# define LL_X86 1 -#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) ) -# define LL_X86_64 1 -# define LL_X86 1 -#elif LL_GNUC && ( defined(__i386__) ) -# define LL_X86 1 -#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) ) -# define LL_PPC 1 -#endif - class LLProcessorInfoImpl; // foward declaration for the mImpl; namespace diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index 90e5bc59ee..b77eb22c3a 100644 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -29,6 +29,20 @@ #define LLPROCESSOR_H #include "llunits.h" +#if LL_MSVC && _M_X64 +# define LL_X86_64 1 +# define LL_X86 1 +#elif LL_MSVC && _M_IX86 +# define LL_X86 1 +#elif LL_GNUC && ( defined(__amd64__) || defined(__x86_64__) ) +# define LL_X86_64 1 +# define LL_X86 1 +#elif LL_GNUC && ( defined(__i386__) ) +# define LL_X86 1 +#elif LL_GNUC && ( defined(__powerpc__) || defined(__ppc__) ) +# define LL_PPC 1 +#endif + class LLProcessorInfoImpl; class LL_COMMON_API LLProcessorInfo diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h new file mode 100644 index 0000000000..f9d7ae7ce4 --- /dev/null +++ b/indra/llcommon/llprofiler.h @@ -0,0 +1,151 @@ +/** + * @file llprofiler.h + * @brief Wrapper for Tracy and/or other profilers + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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_PROFILER_H +#define LL_PROFILER_H + +// If you use the default macros LL_PROFILE_ZONE_SCOPED and LL_PROFILE_ZONE_NAMED to profile code ... +// +// void foo() +// { +// LL_PROFILE_ZONE_SCOPED; +// : +// +// { +// LL_PROFILE_ZONE_NAMED("widget bar"); +// : +// } +// { +// LL_PROFILE_ZONE_NAMED("widget qux"); +// : +// } +// } +// +// ... please be aware that ALL these will show up in a Tracy capture which can quickly exhaust memory. +// Instead, use LL_PROFILE_ZONE_SCOPED_CATEGORY_* and LL_PROFILE_ZONE_NAMED_CATEGORY_* to profile code ... +// +// void foo() +// { +// LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; +// : +// +// { +// LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget bar"); +// : +// } +// { +// LL_PROFILE_ZONE_NAMED_CATEGORY_UI("widget qux"); +// : +// } +// } +// +// ... as these can be selectively turned on/off. This will minimize memory usage and visual clutter in a Tracy capture. +// See llprofiler_categories.h for more details on profiling categories. + +#define LL_PROFILER_CONFIG_NONE 0 // No profiling +#define LL_PROFILER_CONFIG_FAST_TIMER 1 // Profiling on: Only Fast Timers +#define LL_PROFILER_CONFIG_TRACY 2 // Profiling on: Only Tracy +#define LL_PROFILER_CONFIG_TRACY_FAST_TIMER 3 // Profiling on: Fast Timers + Tracy + +#ifndef LL_PROFILER_CONFIGURATION +#define LL_PROFILER_CONFIGURATION LL_PROFILER_CONFIG_FAST_TIMER +#endif + +extern thread_local bool gProfilerEnabled; + +#if defined(LL_PROFILER_CONFIGURATION) && (LL_PROFILER_CONFIGURATION > LL_PROFILER_CONFIG_NONE) + #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY || LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER + #define TRACY_ENABLE 1 +// Normally these would be enabled but we want to be able to build any viewer with Tracy enabled and run the Tracy server on another machine +// They must be undefined in order to work across multiple machines +// #define TRACY_NO_BROADCAST 1 +// #define TRACY_ONLY_LOCALHOST 1 + #define TRACY_ONLY_IPV4 1 + #include "Tracy.hpp" + + // Mutually exclusive with detailed memory tracing + #define LL_PROFILER_ENABLE_TRACY_OPENGL 0 + #endif + + #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY + #define LL_PROFILER_FRAME_END FrameMark + #define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name ); gProfilerEnabled = true; + #define LL_RECORD_BLOCK_TIME(name) ZoneScoped // Want descriptive names; was: ZoneNamedN( ___tracy_scoped_zone, #name, true ); + #define LL_PROFILE_ZONE_NAMED(name) ZoneNamedN( ___tracy_scoped_zone, name, true ); + #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB + #define LL_PROFILE_ZONE_SCOPED ZoneScoped + + #define LL_PROFILE_ZONE_NUM( val ) ZoneValue( val ) + #define LL_PROFILE_ZONE_TEXT( text, size ) ZoneText( text, size ) + + #define LL_PROFILE_ZONE_ERR(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000 ) // RGB yellow + #define LL_PROFILE_ZONE_INFO(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF ) // RGB cyan + #define LL_PROFILE_ZONE_WARN(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 ) // RGB red + #define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size) + #define LL_PROFILE_FREE(ptr) TracyFree(ptr) + #endif + #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_FAST_TIMER + #define LL_PROFILER_FRAME_END + #define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name) + #define LL_RECORD_BLOCK_TIME(name) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__); + #define LL_PROFILE_ZONE_NAMED(name) // LL_PROFILE_ZONE_NAMED is a no-op when Tracy is disabled + #define LL_PROFILE_ZONE_SCOPED // LL_PROFILE_ZONE_SCOPED is a no-op when Tracy is disabled + #define LL_PROFILE_ZONE_COLOR(name,color) // LL_RECORD_BLOCK_TIME(name) + + #define LL_PROFILE_ZONE_NUM( val ) (void)( val ); // Not supported + #define LL_PROFILE_ZONE_TEXT( text, size ) (void)( text ); void( size ); // Not supported + + #define LL_PROFILE_ZONE_ERR(name) (void)(name); // Not supported + #define LL_PROFILE_ZONE_INFO(name) (void)(name); // Not supported + #define LL_PROFILE_ZONE_WARN(name) (void)(name); // Not supported + #define LL_PROFILE_ALLOC(ptr, size) (void)(ptr); (void)(size); + #define LL_PROFILE_FREE(ptr) (void)(ptr); + #endif + #if LL_PROFILER_CONFIGURATION == LL_PROFILER_CONFIG_TRACY_FAST_TIMER + #define LL_PROFILER_FRAME_END FrameMark + #define LL_PROFILER_SET_THREAD_NAME( name ) tracy::SetThreadName( name ); gProfilerEnabled = true; + #define LL_RECORD_BLOCK_TIME(name) ZoneNamedN(___tracy_scoped_zone, #name, true); const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(name)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__); + #define LL_PROFILE_ZONE_NAMED(name) ZoneNamedN( ___tracy_scoped_zone, #name, true ); + #define LL_PROFILE_ZONE_NAMED_COLOR(name,color) ZoneNamedNC( ___tracy_scopped_zone, name, color, true ) // RGB + #define LL_PROFILE_ZONE_SCOPED ZoneScoped + + #define LL_PROFILE_ZONE_NUM( val ) ZoneValue( val ) + #define LL_PROFILE_ZONE_TEXT( text, size ) ZoneText( text, size ) + + #define LL_PROFILE_ZONE_ERR(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0XFF0000 ) // RGB yellow + #define LL_PROFILE_ZONE_INFO(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0X00FFFF ) // RGB cyan + #define LL_PROFILE_ZONE_WARN(name) LL_PROFILE_ZONE_NAMED_COLOR( name, 0x0FFFF00 ) // RGB red + #define LL_PROFILE_ALLOC(ptr, size) TracyAlloc(ptr, size) + #define LL_PROFILE_FREE(ptr) TracyFree(ptr) + #endif +#else + #define LL_PROFILER_FRAME_END + #define LL_PROFILER_SET_THREAD_NAME( name ) (void)(name) +#endif // LL_PROFILER + +#include "llprofilercategories.h" + +#endif // LL_PROFILER_H diff --git a/indra/llcommon/llprofilercategories.h b/indra/llcommon/llprofilercategories.h new file mode 100644 index 0000000000..8db29468cc --- /dev/null +++ b/indra/llcommon/llprofilercategories.h @@ -0,0 +1,280 @@ +/** + * @file llprofiler_ategories.h + * @brief Profiling categories to minimize Tracy memory usage when viewing captures. + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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_PROFILER_CATEGORIES_H +#define LL_PROFILER_CATEGORIES_H + +// A Tracy capture can quickly consume memory. Use these defines to selectively turn on/off Tracy profiling for these categories. +// The biggest memory usage ones are: +// +// LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL +// LL_PROFILER_CATEGORY_ENABLE_LLSD +// LL_PROFILER_CATEGORY_ENABLE_MEMORY +// LL_PROFILER_CATEGORY_ENABLE_SHADERS +// +// NOTE: You can still manually use: +// LL_PROFILE_ZONE_SCOPED(); +// LL_PROFILE_ZONE_NAMED("name"); +// but just be aware that those will ALWAYS show up in a Tracy capture +// a) using more memory, and +// b) adding visual clutter. +#define LL_PROFILER_CATEGORY_ENABLE_APP 1 +#define LL_PROFILER_CATEGORY_ENABLE_AVATAR 1 +#define LL_PROFILER_CATEGORY_ENABLE_DISPLAY 1 +#define LL_PROFILER_CATEGORY_ENABLE_DRAWABLE 1 +#define LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL 1 +#define LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT 1 +#define LL_PROFILER_CATEGORY_ENABLE_FACE 1 +#define LL_PROFILER_CATEGORY_ENABLE_LLSD 1 +#define LL_PROFILER_CATEGORY_ENABLE_LOGGING 1 +#define LL_PROFILER_CATEGORY_ENABLE_MATERIAL 1 +#define LL_PROFILER_CATEGORY_ENABLE_MEDIA 1 +#define LL_PROFILER_CATEGORY_ENABLE_MEMORY 1 +#define LL_PROFILER_CATEGORY_ENABLE_NETWORK 1 +#define LL_PROFILER_CATEGORY_ENABLE_OCTREE 1 +#define LL_PROFILER_CATEGORY_ENABLE_PIPELINE 1 +#define LL_PROFILER_CATEGORY_ENABLE_SHADER 1 +#define LL_PROFILER_CATEGORY_ENABLE_SPATIAL 1 +#define LL_PROFILER_CATEGORY_ENABLE_STATS 1 +#define LL_PROFILER_CATEGORY_ENABLE_STRING 1 +#define LL_PROFILER_CATEGORY_ENABLE_TEXTURE 1 +#define LL_PROFILER_CATEGORY_ENABLE_THREAD 1 +#define LL_PROFILER_CATEGORY_ENABLE_UI 1 +#define LL_PROFILER_CATEGORY_ENABLE_VIEWER 1 +#define LL_PROFILER_CATEGORY_ENABLE_VERTEX 1 +#define LL_PROFILER_CATEGORY_ENABLE_VOLUME 1 +#define LL_PROFILER_CATEGORY_ENABLE_WIN32 1 + +#if LL_PROFILER_CATEGORY_ENABLE_APP + #define LL_PROFILE_ZONE_NAMED_CATEGORY_APP LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_APP(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_APP +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_AVATAR + #define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_AVATAR(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_DISPLAY + #define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_DRAWABLE + #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL + #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_ENVIRONMENT + #define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_FACE + #define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_FACE(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_LLSD + #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_LLSD(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_LOGGING + #define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_LOGGING(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_MATERIAL + #define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_MATERIAL(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_MEDIA + #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_MEMORY + #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_MEMORY(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_NETWORK + #define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_OCTREE + #define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_PIPELINE + #define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_SHADER + #define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_SHADER(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_SPATIAL + #define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_SPATIAL(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_STATS + #define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_STATS(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_STRING + #define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_STRING(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_TEXTURE + #define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_THREAD + #define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_UI + #define LL_PROFILE_ZONE_NAMED_CATEGORY_UI LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_UI(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_UI +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_VERTEX + #define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_VIEWER + #define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_VIEWER(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_VOLUME + #define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME +#endif + +#if LL_PROFILER_CATEGORY_ENABLE_WIN32 + #define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32 LL_PROFILE_ZONE_NAMED + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 LL_PROFILE_ZONE_SCOPED +#else + #define LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32(name) + #define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 +#endif + +#endif // LL_PROFILER_CATEGORIES_H + diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 29a5ca6f24..5cbd346411 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -29,6 +29,9 @@ #include "llerror.h" +// maximum reference count before sounding memory leak alarm +const S32 gMaxRefCount = 65536; + LLRefCount::LLRefCount(const LLRefCount& other) : mRef(0) { @@ -47,7 +50,7 @@ LLRefCount::LLRefCount() : LLRefCount::~LLRefCount() { - if (mRef != 0) + if (mRef != LL_REFCOUNT_FREE && mRef != 0) { LL_ERRS() << "deleting non-zero reference" << LL_ENDL; } diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 7e4af6ea66..2080da1565 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -37,6 +37,10 @@ class LLMutex; // see llthread.h for LLThreadSafeRefCount //---------------------------------------------------------------------------- +//nonsense but recognizable value for freed LLRefCount (aids in debugging) +#define LL_REFCOUNT_FREE 1234567890 +extern const S32 gMaxRefCount; + class LL_COMMON_API LLRefCount { protected: @@ -47,17 +51,25 @@ protected: public: LLRefCount(); + inline void validateRefCount() const + { + llassert(mRef > 0); // ref count below 0, likely corrupted + llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak + } + inline void ref() const { mRef++; + validateRefCount(); } inline S32 unref() const { - llassert(mRef >= 1); + validateRefCount(); if (0 == --mRef) { - delete this; + mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging + delete this; return 0; } return mRef; diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 57b746889d..807b3d13f8 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -400,6 +400,7 @@ namespace ImplMap& ImplMap::makeMap(LLSD::Impl*& var) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; if (shared()) { ImplMap* i = new ImplMap(mData); @@ -414,18 +415,21 @@ namespace bool ImplMap::has(const LLSD::String& k) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; DataMap::const_iterator i = mData.find(k); return i != mData.end(); } LLSD ImplMap::get(const LLSD::String& k) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; DataMap::const_iterator i = mData.find(k); return (i != mData.end()) ? i->second : LLSD(); } LLSD ImplMap::getKeys() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; LLSD keys = LLSD::emptyArray(); DataMap::const_iterator iter = mData.begin(); while (iter != mData.end()) @@ -438,11 +442,13 @@ namespace void ImplMap::insert(const LLSD::String& k, const LLSD& v) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; mData.insert(DataMap::value_type(k, v)); } void ImplMap::erase(const LLSD::String& k) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; mData.erase(k); } @@ -684,6 +690,7 @@ const LLSD::Impl& LLSD::Impl::safe(const Impl* impl) ImplMap& LLSD::Impl::makeMap(Impl*& var) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; ImplMap* im = new ImplMap; reset(var, im); return *im; @@ -887,11 +894,16 @@ LLSD& LLSD::with(const String& k, const LLSD& v) } void LLSD::erase(const String& k) { makeMap(impl).erase(k); } -LLSD& LLSD::operator[](const String& k) - { return makeMap(impl).ref(k); } +LLSD& LLSD::operator[](const String& k) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + return makeMap(impl).ref(k); +} const LLSD& LLSD::operator[](const String& k) const - { return safe(impl).ref(k); } - +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + return safe(impl).ref(k); +} LLSD LLSD::emptyArray() { @@ -914,10 +926,16 @@ LLSD& LLSD::with(Integer i, const LLSD& v) LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); } void LLSD::erase(Integer i) { makeArray(impl).erase(i); } -LLSD& LLSD::operator[](Integer i) - { return makeArray(impl).ref(i); } +LLSD& LLSD::operator[](Integer i) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + return makeArray(impl).ref(i); +} const LLSD& LLSD::operator[](Integer i) const - { return safe(impl).ref(i); } +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + return safe(impl).ref(i); +} static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat) { diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 5b6d5545af..24cb9bbce1 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -290,9 +290,17 @@ public: LLSD& with(const String&, const LLSD&); LLSD& operator[](const String&); - LLSD& operator[](const char* c) { return (*this)[String(c)]; } + LLSD& operator[](const char* c) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + return (*this)[String(c)]; + } const LLSD& operator[](const String&) const; - const LLSD& operator[](const char* c) const { return (*this)[String(c)]; } + const LLSD& operator[](const char* c) const + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; + return (*this)[String(c)]; + } //@} /** @name Array Values */ diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index 2e7b46f885..af4ccf25fd 100644 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -37,8 +37,6 @@ static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; static const LLSD NO_VALUE_MARKER; -LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); - // // LLParamSDParser // diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h index 93910b70ae..82a623a8a0 100644 --- a/indra/llcommon/llsdparam.h +++ b/indra/llcommon/llsdparam.h @@ -110,7 +110,6 @@ private: }; -extern LL_COMMON_API LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR; template<typename T> class LLSDParamAdapter : public T { @@ -118,7 +117,7 @@ public: LLSDParamAdapter() {} LLSDParamAdapter(const LLSD& sd) { - LL_RECORD_BLOCK_TIME(FTM_SD_PARAM_ADAPTOR); + LL_PROFILE_ZONE_SCOPED; LLParamSDParser parser; // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it bool parse_silently = true; diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index fc10fcece3..8e90d1e8b8 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -215,6 +215,8 @@ BOOL compare_llsd_with_template( const LLSD& template_llsd, LLSD& resultant_llsd) { + LL_PROFILE_ZONE_SCOPED + if ( llsd_to_test.isUndefined() && template_llsd.isDefined() ) @@ -336,6 +338,8 @@ bool filter_llsd_with_template( const LLSD & template_llsd, LLSD & resultant_llsd) { + LL_PROFILE_ZONE_SCOPED + if (llsd_to_test.isUndefined() && template_llsd.isDefined()) { resultant_llsd = template_llsd; @@ -530,6 +534,8 @@ class TypeLookup public: TypeLookup() { + LL_PROFILE_ZONE_SCOPED + for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di) { mMap[di->type] = di->name; @@ -538,6 +544,8 @@ public: std::string lookup(LLSD::Type type) const { + LL_PROFILE_ZONE_SCOPED + MapType::const_iterator found = mMap.find(type); if (found != mMap.end()) { @@ -588,6 +596,8 @@ static std::string match_types(LLSD::Type expect, // prototype.type() LLSD::Type actual, // type we're checking const std::string& pfx) // as for llsd_matches { + LL_PROFILE_ZONE_SCOPED + // Trivial case: if the actual type is exactly what we expect, we're good. if (actual == expect) return ""; @@ -625,6 +635,8 @@ static std::string match_types(LLSD::Type expect, // prototype.type() // see docstring in .h file std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx) { + LL_PROFILE_ZONE_SCOPED + // An undefined prototype means that any data is valid. // An undefined slot in an array or map prototype means that any data // may fill that slot. @@ -757,6 +769,8 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits) { + LL_PROFILE_ZONE_SCOPED + // We're comparing strict equality of LLSD representation rather than // performing any conversions. So if the types aren't equal, the LLSD // values aren't equal. @@ -865,6 +879,8 @@ namespace llsd LLSD& drill_ref(LLSD& blob, const LLSD& rawPath) { + LL_PROFILE_ZONE_SCOPED + // Treat rawPath uniformly as an array. If it's not already an array, // store it as the only entry in one. (But let's say Undefined means an // empty array.) @@ -890,6 +906,8 @@ LLSD& drill_ref(LLSD& blob, const LLSD& rawPath) // path entry that's bad. for (LLSD::Integer i = 0; i < path.size(); ++i) { + LL_PROFILE_ZONE_NUM( i ) + const LLSD& key{path[i]}; if (key.isString()) { @@ -918,6 +936,8 @@ LLSD& drill_ref(LLSD& blob, const LLSD& rawPath) LLSD drill(const LLSD& blob, const LLSD& path) { + LL_PROFILE_ZONE_SCOPED + // drill_ref() does exactly what we want. Temporarily cast away // const-ness and use that. return drill_ref(const_cast<LLSD&>(blob), path); @@ -930,6 +950,8 @@ LLSD drill(const LLSD& blob, const LLSD& path) // filter may be include to exclude/include keys in a map. LLSD llsd_clone(LLSD value, LLSD filter) { + LL_PROFILE_ZONE_SCOPED + LLSD clone; bool has_filter(filter.isMap()); diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 7c81d65a8b..51ef514cf7 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -455,6 +455,7 @@ public: static DERIVED_TYPE* getInstance() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; // We know the viewer has LLSingleton dependency circularities. If you // feel strongly motivated to eliminate them, cheers and good luck. // (At that point we could consider a much simpler locking mechanism.) @@ -838,4 +839,36 @@ private: \ /* LLSINGLETON() is carefully implemented to permit exactly this */ \ LLSINGLETON_C11(DERIVED_CLASS) {} +// Relatively unsafe singleton implementation that is much faster +// and simpler than LLSingleton, but has no dependency tracking +// or inherent thread safety and requires manual invocation of +// createInstance before first use. +template<class T> +class LLSimpleton +{ +public: + template <typename... ARGS> + static void createInstance(ARGS&&... args) + { + llassert(sInstance == nullptr); + sInstance = new T(std::forward<ARGS>(args)...); + } + + static inline T* getInstance() { return sInstance; } + static inline T& instance() { return *getInstance(); } + static inline bool instanceExists() { return sInstance != nullptr; } + + static void deleteSingleton() + { + delete sInstance; + sInstance = nullptr; + } + +private: + static T* sInstance; +}; + +template <class T> +T* LLSimpleton<T>::sInstance{ nullptr }; + #endif diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 0290eea143..7f501f2e77 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -37,9 +37,6 @@ #include <winnls.h> // for WideCharToMultiByte #endif -LLTrace::BlockTimerStatHandle FT_STRING_FORMAT("String Format"); - - std::string ll_safe_string(const char* in) { if(in) return std::string(in); @@ -215,7 +212,7 @@ S32 utf16chars_to_wchar(const U16* inchars, llwchar* outchar) return inchars - base; } -llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len) +llutf16string wstring_to_utf16str(const llwchar* utf32str, size_t len) { llutf16string out; @@ -237,27 +234,19 @@ llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len) return out; } -llutf16string wstring_to_utf16str(const LLWString &utf32str) -{ - const S32 len = (S32)utf32str.length(); - return wstring_to_utf16str(utf32str, len); -} - -llutf16string utf8str_to_utf16str ( const std::string& utf8str ) +llutf16string utf8str_to_utf16str( const char* utf8str, size_t len ) { - LLWString wstr = utf8str_to_wstring ( utf8str ); + LLWString wstr = utf8str_to_wstring ( utf8str, len ); return wstring_to_utf16str ( wstr ); } - -LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len) +LLWString utf16str_to_wstring(const U16* utf16str, size_t len) { LLWString wout; - if((len <= 0) || utf16str.empty()) return wout; + if (len == 0) return wout; S32 i = 0; - // craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): - const U16* chars16 = &(*(utf16str.begin())); + const U16* chars16 = utf16str; while (i < len) { llwchar cur_char; @@ -267,12 +256,6 @@ LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len) return wout; } -LLWString utf16str_to_wstring(const llutf16string &utf16str) -{ - const S32 len = (S32)utf16str.length(); - return utf16str_to_wstring(utf16str, len); -} - // Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. S32 utf16str_wstring_length(const llutf16string &utf16str, const S32 utf16_len) { @@ -392,8 +375,7 @@ S32 wstring_utf8_length(const LLWString& wstr) return len; } - -LLWString utf8str_to_wstring(const std::string& utf8str, S32 len) +LLWString utf8str_to_wstring(const char* utf8str, size_t len) { LLWString wout; @@ -481,13 +463,7 @@ LLWString utf8str_to_wstring(const std::string& utf8str, S32 len) return wout; } -LLWString utf8str_to_wstring(const std::string& utf8str) -{ - const S32 len = (S32)utf8str.length(); - return utf8str_to_wstring(utf8str, len); -} - -std::string wstring_to_utf8str(const LLWString& utf32str, S32 len) +std::string wstring_to_utf8str(const llwchar* utf32str, size_t len) { std::string out; @@ -503,20 +479,9 @@ std::string wstring_to_utf8str(const LLWString& utf32str, S32 len) return out; } -std::string wstring_to_utf8str(const LLWString& utf32str) -{ - const S32 len = (S32)utf32str.length(); - return wstring_to_utf8str(utf32str, len); -} - -std::string utf16str_to_utf8str(const llutf16string& utf16str) -{ - return wstring_to_utf8str(utf16str_to_wstring(utf16str)); -} - -std::string utf16str_to_utf8str(const llutf16string& utf16str, S32 len) +std::string utf16str_to_utf8str(const U16* utf16str, size_t len) { - return wstring_to_utf8str(utf16str_to_wstring(utf16str, len), len); + return wstring_to_utf8str(utf16str_to_wstring(utf16str, len)); } std::string utf8str_trim(const std::string& utf8str) @@ -657,17 +622,16 @@ std::string utf8str_removeCRLF(const std::string& utf8str) } #if LL_WINDOWS -std::string ll_convert_wide_to_string(const wchar_t* in) +unsigned int ll_wstring_default_code_page() { - return ll_convert_wide_to_string(in, CP_UTF8); + return CP_UTF8; } -std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page) +std::string ll_convert_wide_to_string(const wchar_t* in, size_t len_in, unsigned int code_page) { std::string out; if(in) { - int len_in = wcslen(in); int len_out = WideCharToMultiByte( code_page, 0, @@ -699,12 +663,7 @@ std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page) return out; } -std::wstring ll_convert_string_to_wide(const std::string& in) -{ - return ll_convert_string_to_wide(in, CP_UTF8); -} - -std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_page) +std::wstring ll_convert_string_to_wide(const char* in, size_t len, unsigned int code_page) { // From review: // We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input, @@ -716,10 +675,10 @@ std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_ // reserve an output buffer that will be destroyed on exit, with a place // to put NULL terminator - std::vector<wchar_t> w_out(in.length() + 1); + std::vector<wchar_t> w_out(len + 1); memset(&w_out[0], 0, w_out.size()); - int real_output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), + int real_output_str_len = MultiByteToWideChar(code_page, 0, in, len, &w_out[0], w_out.size() - 1); //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858. @@ -729,30 +688,32 @@ std::wstring ll_convert_string_to_wide(const std::string& in, unsigned int code_ return {&w_out[0]}; } -LLWString ll_convert_wide_to_wstring(const std::wstring& in) +LLWString ll_convert_wide_to_wstring(const wchar_t* in, size_t len) { - // This function, like its converse, is a placeholder, encapsulating a - // guilty little hack: the only "official" way nat has found to convert - // between std::wstring (16 bits on Windows) and LLWString (UTF-32) is - // by using iconv, which we've avoided so far. It kinda sorta works to - // just copy individual characters... - // The point is that if/when we DO introduce some more official way to - // perform such conversions, we should only have to call it here. - return { in.begin(), in.end() }; + // Whether or not std::wstring and llutf16string are distinct types, they + // both hold UTF-16LE characters. (See header file comments.) Pretend this + // wchar_t* sequence is really a U16* sequence and use the conversion we + // define above. + return utf16str_to_wstring(reinterpret_cast<const U16*>(in), len); } -std::wstring ll_convert_wstring_to_wide(const LLWString& in) +std::wstring ll_convert_wstring_to_wide(const llwchar* in, size_t len) { - // See comments in ll_convert_wide_to_wstring() - return { in.begin(), in.end() }; + // first, convert to llutf16string, for which we have a real implementation + auto utf16str{ wstring_to_utf16str(in, len) }; + // then, because each U16 char must be UTF-16LE encoded, pretend the U16* + // string pointer is a wchar_t* and instantiate a std::wstring of the same + // length. + return { reinterpret_cast<const wchar_t*>(utf16str.c_str()), utf16str.length() }; } std::string ll_convert_string_to_utf8_string(const std::string& in) { - auto w_mesg = ll_convert_string_to_wide(in, CP_ACP); - std::string out_utf8(ll_convert_wide_to_string(w_mesg.c_str(), CP_UTF8)); - - return out_utf8; + // If you pass code_page, you must also pass length, otherwise the code + // page parameter will be mistaken for length. + auto w_mesg = ll_convert_string_to_wide(in, in.length(), CP_ACP); + // CP_UTF8 is default -- see ll_wstring_default_code_page() above. + return ll_convert_wide_to_string(w_mesg); } namespace @@ -1356,7 +1317,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) { - LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING; S32 res = 0; std::string output; @@ -1429,7 +1390,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) template<> S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) { - LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING; S32 res = 0; if (!substitutions.isMap()) diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 4263122f36..d94f549480 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -27,9 +27,11 @@ #ifndef LL_LLSTRING_H #define LL_LLSTRING_H +#include <boost/call_traits.hpp> #include <boost/optional/optional.hpp> #include <string> #include <cstdio> +#include <cwchar> // std::wcslen() //#include <locale> #include <iomanip> #include <algorithm> @@ -527,14 +529,71 @@ struct ll_convert_impl<T, T> T operator()(const T& in) const { return in; } }; +// simple construction from char* +template<typename T> +struct ll_convert_impl<T, const typename T::value_type*> +{ + T operator()(const typename T::value_type* in) const { return { in }; } +}; + // specialize ll_convert_impl<TO, FROM> to return EXPR #define ll_convert_alias(TO, FROM, EXPR) \ template<> \ struct ll_convert_impl<TO, FROM> \ { \ - TO operator()(const FROM& in) const { return EXPR; } \ + /* param_type optimally passes both char* and string */ \ + TO operator()(typename boost::call_traits<FROM>::param_type in) const { return EXPR; } \ +} + +// If all we're doing is copying characters, pass this to ll_convert_alias as +// EXPR. Since it expands into the 'return EXPR' slot in the ll_convert_impl +// specialization above, it implies TO{ in.begin(), in.end() }. +#define LL_CONVERT_COPY_CHARS { in.begin(), in.end() } + +// Generic name for strlen() / wcslen() - the default implementation should +// (!) work with U16 and llwchar, but we don't intend to engage it. +template <typename CHARTYPE> +size_t ll_convert_length(const CHARTYPE* zstr) +{ + const CHARTYPE* zp; + // classic C string scan + for (zp = zstr; *zp; ++zp) + ; + return (zp - zstr); } +// specialize where we have a library function; may use intrinsic operations +template <> +inline size_t ll_convert_length<wchar_t>(const wchar_t* zstr) { return std::wcslen(zstr); } +template <> +inline size_t ll_convert_length<char> (const char* zstr) { return std::strlen(zstr); } + +// ll_convert_forms() is short for a bunch of boilerplate. It defines +// longname(const char*, len), longname(const char*), longname(const string&) +// and longname(const string&, len) so calls written pre-ll_convert() will +// work. Most of these overloads will be unified once we turn on C++17 and can +// use std::string_view. +// It also uses aliasmacro to ensure that both ll_convert<OUTSTR>(const char*) +// and ll_convert<OUTSTR>(const string&) will work. +#define ll_convert_forms(aliasmacro, OUTSTR, INSTR, longname) \ +LL_COMMON_API OUTSTR longname(const INSTR::value_type* in, size_t len); \ +inline auto longname(const INSTR& in, size_t len) \ +{ \ + return longname(in.c_str(), len); \ +} \ +inline auto longname(const INSTR::value_type* in) \ +{ \ + return longname(in, ll_convert_length(in)); \ +} \ +inline auto longname(const INSTR& in) \ +{ \ + return longname(in.c_str(), in.length()); \ +} \ +/* string param */ \ +aliasmacro(OUTSTR, INSTR, longname(in)); \ +/* char* param */ \ +aliasmacro(OUTSTR, const INSTR::value_type*, longname(in)) + // Make the incoming string a utf8 string. Replaces any unknown glyph // with the UNKNOWN_CHARACTER. Once any unknown glyph is found, the rest // of the data may not be recovered. @@ -571,63 +630,47 @@ LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); // LL_WCHAR_T_NATIVE. typedef std::basic_string<U16> llutf16string; -#if ! defined(LL_WCHAR_T_NATIVE) -// wchar_t is identical to U16, and std::wstring is identical to llutf16string. -// Defining an ll_convert alias involving llutf16string would collide with the -// comparable preferred alias involving std::wstring. (In this scenario, if -// you pass llutf16string, it will engage the std::wstring specialization.) -#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing -#else // defined(LL_WCHAR_T_NATIVE) -// wchar_t is a distinct native type, so llutf16string is also a distinct -// type, and there IS a point to converting separately to/from llutf16string. -// (But why? Windows APIs are still defined in terms of wchar_t, and -// in this scenario llutf16string won't work for them!) -#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR) +// Considering wchar_t, llwchar and U16, there are three relevant cases: +#if LLWCHAR_IS_WCHAR_T // every which way but Windows +// llwchar is identical to wchar_t, LLWString is identical to std::wstring. +// U16 is distinct, llutf16string is distinct (though pretty useless). +// Given conversions to/from LLWString and to/from llutf16string, conversions +// involving std::wstring would collide. +#define ll_convert_wstr_alias(TO, FROM, EXPR) // nothing +// but we can define conversions involving llutf16string without collisions +#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR) + +#elif defined(LL_WCHAR_T_NATIVE) // Windows, either clang or MS /Zc:wchar_t +// llwchar (32-bit), wchar_t (16-bit) and U16 are all different types. +// Conversions to/from LLWString, to/from std::wstring and to/from llutf16string +// can all be defined. +#define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR) +#define ll_convert_u16_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR) + +#else // ! LL_WCHAR_T_NATIVE: Windows with MS /Zc:wchar_t- +// wchar_t is identical to U16, std::wstring is identical to llutf16string. +// Given conversions to/from LLWString and to/from std::wstring, conversions +// involving llutf16string would collide. +#define ll_convert_u16_alias(TO, FROM, EXPR) // nothing +// but we can define conversions involving std::wstring without collisions +#define ll_convert_wstr_alias(TO, FROM, EXPR) ll_convert_alias(TO, FROM, EXPR) +#endif + +ll_convert_forms(ll_convert_u16_alias, LLWString, llutf16string, utf16str_to_wstring); +ll_convert_forms(ll_convert_u16_alias, llutf16string, LLWString, wstring_to_utf16str); +ll_convert_forms(ll_convert_u16_alias, llutf16string, std::string, utf8str_to_utf16str); +ll_convert_forms(ll_convert_alias, LLWString, std::string, utf8str_to_wstring); -#if LL_WINDOWS -// LL_WCHAR_T_NATIVE is defined on non-Windows systems because, in fact, -// wchar_t is native. Everywhere but Windows, we use it for llwchar (see -// stdtypes.h). That makes LLWString identical to std::wstring, so these -// aliases for std::wstring would collide with those for LLWString. Only -// define on Windows, where converting between std::wstring and llutf16string -// means copying chars. -ll_convert_alias(llutf16string, std::wstring, llutf16string(in.begin(), in.end())); -ll_convert_alias(std::wstring, llutf16string, std::wstring(in.begin(), in.end())); -#endif // LL_WINDOWS -#endif // defined(LL_WCHAR_T_NATIVE) - -LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); -LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); -ll_convert_u16_alias(LLWString, llutf16string, utf16str_to_wstring(in)); - -LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); -LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); -ll_convert_u16_alias(llutf16string, LLWString, wstring_to_utf16str(in)); - -LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); -LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); -ll_convert_u16_alias(llutf16string, std::string, utf8str_to_utf16str(in)); - -LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); -LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); // Same function, better name. JC inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } -// best name of all -ll_convert_alias(LLWString, std::string, utf8string_to_wstring(in)); -// LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); -LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); -LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); -ll_convert_alias(std::string, LLWString, wstring_to_utf8str(in)); -LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); -LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); -ll_convert_u16_alias(std::string, llutf16string, utf16str_to_utf8str(in)); +ll_convert_forms(ll_convert_alias, std::string, LLWString, wstring_to_utf8str); +ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_utf8str); -#if LL_WINDOWS +// an older alias for utf16str_to_utf8str(llutf16string) inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);} -#endif // Length of this UTF32 string in bytes when transformed to UTF8 LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); @@ -701,42 +744,48 @@ LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); //@{ /** - * @brief Convert a wide string to std::string + * @brief Convert a wide string to/from std::string + * Convert a Windows wide string to/from our LLWString * * This replaces the unsafe W2A macro from ATL. */ -LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in, unsigned int code_page); -LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); // default CP_UTF8 -inline std::string ll_convert_wide_to_string(const std::wstring& in, unsigned int code_page) -{ - return ll_convert_wide_to_string(in.c_str(), code_page); -} -inline std::string ll_convert_wide_to_string(const std::wstring& in) -{ - return ll_convert_wide_to_string(in.c_str()); -} -ll_convert_alias(std::string, std::wstring, ll_convert_wide_to_string(in)); - -/** - * Converts a string to wide string. - */ -LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in, - unsigned int code_page); -LL_COMMON_API std::wstring ll_convert_string_to_wide(const std::string& in); - // default CP_UTF8 -ll_convert_alias(std::wstring, std::string, ll_convert_string_to_wide(in)); - -/** - * Convert a Windows wide string to our LLWString - */ -LL_COMMON_API LLWString ll_convert_wide_to_wstring(const std::wstring& in); -ll_convert_alias(LLWString, std::wstring, ll_convert_wide_to_wstring(in)); - -/** - * Convert LLWString to Windows wide string - */ -LL_COMMON_API std::wstring ll_convert_wstring_to_wide(const LLWString& in); -ll_convert_alias(std::wstring, LLWString, ll_convert_wstring_to_wide(in)); +// Avoid requiring this header to #include the Windows header file declaring +// our actual default code_page by delegating this function to our .cpp file. +LL_COMMON_API unsigned int ll_wstring_default_code_page(); + +// This is like ll_convert_forms(), with the added complexity of a code page +// parameter that may or may not be passed. +#define ll_convert_cp_forms(aliasmacro, OUTSTR, INSTR, longname) \ +/* declare the only nontrivial implementation (in .cpp file) */ \ +LL_COMMON_API OUTSTR longname( \ + const INSTR::value_type* in, \ + size_t len, \ + unsigned int code_page=ll_wstring_default_code_page()); \ +/* if passed only a char pointer, scan for nul terminator */ \ +inline auto longname(const INSTR::value_type* in) \ +{ \ + return longname(in, ll_convert_length(in)); \ +} \ +/* if passed string and length, extract its char pointer */ \ +inline auto longname( \ + const INSTR& in, \ + size_t len, \ + unsigned int code_page=ll_wstring_default_code_page()) \ +{ \ + return longname(in.c_str(), len, code_page); \ +} \ +/* if passed only a string object, no scan, pass known length */ \ +inline auto longname(const INSTR& in) \ +{ \ + return longname(in.c_str(), in.length()); \ +} \ +aliasmacro(OUTSTR, INSTR, longname(in)); \ +aliasmacro(OUTSTR, const INSTR::value_type*, longname(in)) + +ll_convert_cp_forms(ll_convert_wstr_alias, std::string, std::wstring, ll_convert_wide_to_string); +ll_convert_cp_forms(ll_convert_wstr_alias, std::wstring, std::string, ll_convert_string_to_wide); + ll_convert_forms(ll_convert_wstr_alias, LLWString, std::wstring, ll_convert_wide_to_wstring); + ll_convert_forms(ll_convert_wstr_alias, std::wstring, LLWString, ll_convert_wstring_to_wide); /** * Converts incoming string into utf8 string @@ -1937,4 +1986,14 @@ void LLStringUtilBase<T>::truncate(string_type& string, size_type count) string.resize(count < cur_size ? count : cur_size); } +// The good thing about *declaration* macros, vs. usage macros, is that now +// we're done with them: we don't need them to bleed into the consuming source +// file. +#undef ll_convert_alias +#undef ll_convert_u16_alias +#undef ll_convert_wstr_alias +#undef LL_CONVERT_COPY_CHARS +#undef ll_convert_forms +#undef ll_convert_cp_forms + #endif // LL_STRING_H diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index cdc1d83b59..f717b2cf34 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -843,6 +843,7 @@ LLSD LLMemoryInfo::getStatsMap() const LLMemoryInfo& LLMemoryInfo::refresh() { + LL_PROFILE_ZONE_SCOPED mStatsMap = loadStatsMap(); LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n"; @@ -852,11 +853,9 @@ LLMemoryInfo& LLMemoryInfo::refresh() return *this; } -static LLTrace::BlockTimerStatHandle FTM_MEMINFO_LOAD_STATS("MemInfo Load Stats"); - LLSD LLMemoryInfo::loadStatsMap() { - LL_RECORD_BLOCK_TIME(FTM_MEMINFO_LOAD_STATS); + LL_PROFILE_ZONE_SCOPED; // This implementation is derived from stream() code (as of 2011-06-29). Stats stats; diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index 6d531d842d..a807acc56e 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -135,6 +135,8 @@ void LLThread::threadRun() set_thread_name(-1, mName.c_str()); #endif + LL_PROFILER_SET_THREAD_NAME( mName.c_str() ); + // this is the first point at which we're actually running in the new thread mID = currentID(); @@ -331,6 +333,7 @@ bool LLThread::runCondition(void) // Stop thread execution if requested until unpaused. void LLThread::checkPause() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD mDataLock->lock(); // This is in a while loop because the pthread API allows for spurious wakeups. @@ -362,17 +365,20 @@ void LLThread::setQuitting() // static LLThread::id_t LLThread::currentID() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD return std::this_thread::get_id(); } // static void LLThread::yield() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD std::this_thread::yield(); } void LLThread::wake() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD mDataLock->lock(); if(!shouldSleep()) { @@ -383,6 +389,7 @@ void LLThread::wake() void LLThread::wakeLocked() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD if(!shouldSleep()) { mRunCondition->signal(); @@ -391,11 +398,13 @@ void LLThread::wakeLocked() void LLThread::lockData() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD mDataLock->lock(); } void LLThread::unlockData() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD mDataLock->unlock(); } diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 26e0d71d31..68d79cdd12 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -1,6 +1,6 @@ /** * @file llthreadsafequeue.h - * @brief Base classes for thread, mutex and condition handling. + * @brief Queue protected with mutexes for cross-thread use * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code @@ -27,16 +27,19 @@ #ifndef LL_LLTHREADSAFEQUEUE_H #define LL_LLTHREADSAFEQUEUE_H -#include "llexception.h" -#include <deque> -#include <string> -#include <chrono> -#include "mutex.h" #include "llcoros.h" #include LLCOROS_MUTEX_HEADER #include <boost/fiber/timed_mutex.hpp> #include LLCOROS_CONDVAR_HEADER +#include "llexception.h" +#include "mutex.h" +#include <chrono> +#include <queue> +#include <string> +/***************************************************************************** +* LLThreadSafeQueue +*****************************************************************************/ // // A general queue exception. // @@ -66,70 +69,116 @@ public: } }; -// -// Implements a thread safe FIFO. -// -template<typename ElementT> +/** + * Implements a thread safe FIFO. + */ +// Let the default std::queue default to underlying std::deque. Override if +// desired. +template<typename ElementT, typename QueueT=std::queue<ElementT>> class LLThreadSafeQueue { public: typedef ElementT value_type; - - // If the pool is set to NULL one will be allocated and managed by this - // queue. + + // Limiting the number of pending items prevents unbounded growth of the + // underlying queue. LLThreadSafeQueue(U32 capacity = 1024); - - // Add an element to the front of queue (will block if the queue has - // reached capacity). + virtual ~LLThreadSafeQueue() {} + + // Add an element to the queue (will block if the queue has reached + // capacity). // // This call will raise an interrupt error if the queue is closed while // the caller is blocked. - void pushFront(ElementT const & element); - - // Try to add an element to the front of queue without blocking. Returns + template <typename T> + void push(T&& element); + // legacy name + void pushFront(ElementT const & element) { return push(element); } + + // Add an element to the queue (will block if the queue has reached + // capacity). Return false if the queue is closed before push is possible. + template <typename T> + bool pushIfOpen(T&& element); + + // Try to add an element to the queue without blocking. Returns // true only if the element was actually added. - bool tryPushFront(ElementT const & element); + template <typename T> + bool tryPush(T&& element); + // legacy name + bool tryPushFront(ElementT const & element) { return tryPush(element); } - // Try to add an element to the front of queue, blocking if full but with - // timeout. Returns true if the element was added. + // Try to add an element to the queue, blocking if full but with timeout + // after specified duration. Returns true if the element was added. // There are potentially two different timeouts involved: how long to try // to lock the mutex, versus how long to wait for the queue to stop being // full. Careful settings for each timeout might be orders of magnitude // apart. However, this method conflates them. + template <typename Rep, typename Period, typename T> + bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout, + T&& element); + // legacy name template <typename Rep, typename Period> bool tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout, - ElementT const & element); + ElementT const & element) { return tryPushFor(timeout, element); } + + // Try to add an element to the queue, blocking if full but with + // timeout at specified time_point. Returns true if the element was added. + template <typename Clock, typename Duration, typename T> + bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until, + T&& element); + // no legacy name because this is a newer method - // Pop the element at the end of the queue (will block if the queue is + // Pop the element at the head of the queue (will block if the queue is // empty). // // This call will raise an interrupt error if the queue is closed while // the caller is blocked. - ElementT popBack(void); - - // Pop an element from the end of the queue if there is one available. + ElementT pop(void); + // legacy name + ElementT popBack(void) { return pop(); } + + // Pop an element from the head of the queue if there is one available. // Returns true only if an element was popped. - bool tryPopBack(ElementT & element); - + bool tryPop(ElementT & element); + // legacy name + bool tryPopBack(ElementT & element) { return tryPop(element); } + + // Pop the element at the head of the queue, blocking if empty, with + // timeout after specified duration. Returns true if an element was popped. + template <typename Rep, typename Period> + bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, ElementT& element); + // no legacy name because this is a newer method + + // Pop the element at the head of the queue, blocking if empty, with + // timeout at specified time_point. Returns true if an element was popped. + template <typename Clock, typename Duration> + bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until, + ElementT& element); + // no legacy name because this is a newer method + // Returns the size of the queue. size_t size(); + //Returns the capacity of the queue. + U32 capacity() { return mCapacity; } + // closes the queue: - // - every subsequent pushFront() call will throw LLThreadSafeQueueInterrupt - // - every subsequent tryPushFront() call will return false - // - popBack() calls will return normally until the queue is drained, then - // every subsequent popBack() will throw LLThreadSafeQueueInterrupt - // - tryPopBack() calls will return normally until the queue is drained, - // then every subsequent tryPopBack() call will return false + // - every subsequent push() call will throw LLThreadSafeQueueInterrupt + // - every subsequent tryPush() call will return false + // - pop() calls will return normally until the queue is drained, then + // every subsequent pop() will throw LLThreadSafeQueueInterrupt + // - tryPop() calls will return normally until the queue is drained, + // then every subsequent tryPop() call will return false void close(); - // detect closed state + // producer end: are we prevented from pushing any additional items? bool isClosed(); - // inverse of isClosed() - explicit operator bool(); + // consumer end: are we done, is the queue entirely drained? + bool done(); -private: - std::deque< ElementT > mStorage; +protected: + typedef QueueT queue_type; + QueueT mStorage; U32 mCapacity; bool mClosed; @@ -137,37 +186,154 @@ private: typedef std::unique_lock<decltype(mLock)> lock_t; boost::fibers::condition_variable_any mCapacityCond; boost::fibers::condition_variable_any mEmptyCond; -}; -// LLThreadSafeQueue -//----------------------------------------------------------------------------- + enum pop_result { EMPTY, DONE, WAITING, POPPED }; + // implementation logic, suitable for passing to tryLockUntil() + template <typename Clock, typename Duration> + pop_result tryPopUntil_(lock_t& lock, + const std::chrono::time_point<Clock, Duration>& until, + ElementT& element); + // if we're able to lock immediately, do so and run the passed callable, + // which must accept lock_t& and return bool + template <typename CALLABLE> + bool tryLock(CALLABLE&& callable); + // if we're able to lock before the passed time_point, do so and run the + // passed callable, which must accept lock_t& and return bool + template <typename Clock, typename Duration, typename CALLABLE> + bool tryLockUntil(const std::chrono::time_point<Clock, Duration>& until, + CALLABLE&& callable); + // while lock is locked, really push the passed element, if we can + template <typename T> + bool push_(lock_t& lock, T&& element); + // while lock is locked, really pop the head element, if we can + pop_result pop_(lock_t& lock, ElementT& element); + // Is the current head element ready to pop? We say yes; subclass can + // override as needed. + virtual bool canPop(const ElementT& head) const { return true; } +}; -template<typename ElementT> -LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(U32 capacity) : +/***************************************************************************** +* PriorityQueueAdapter +*****************************************************************************/ +namespace LL +{ + /** + * std::priority_queue's API is almost like std::queue, intentionally of + * course, but you must access the element about to pop() as top() rather + * than as front(). Make an adapter for use with LLThreadSafeQueue. + */ + template <typename T, typename Container=std::vector<T>, + typename Compare=std::less<typename Container::value_type>> + class PriorityQueueAdapter + { + public: + // publish all the same types + typedef std::priority_queue<T, Container, Compare> queue_type; + typedef typename queue_type::container_type container_type; + typedef typename queue_type::value_compare value_compare; + typedef typename queue_type::value_type value_type; + typedef typename queue_type::size_type size_type; + typedef typename queue_type::reference reference; + typedef typename queue_type::const_reference const_reference; + + // Although std::queue defines both const and non-const front() + // methods, std::priority_queue defines only const top(). + const_reference front() const { return mQ.top(); } + // std::priority_queue has no equivalent to back(), so it's good that + // LLThreadSafeQueue doesn't use it. + + // All the rest of these merely forward to the corresponding + // queue_type methods. + bool empty() const { return mQ.empty(); } + size_type size() const { return mQ.size(); } + void push(const value_type& value) { mQ.push(value); } + void push(value_type&& value) { mQ.push(std::move(value)); } + template <typename... Args> + void emplace(Args&&... args) { mQ.emplace(std::forward<Args>(args)...); } + void pop() { mQ.pop(); } + + private: + queue_type mQ; + }; +} // namespace LL + + +/***************************************************************************** +* LLThreadSafeQueue implementation +*****************************************************************************/ +template<typename ElementT, typename QueueT> +LLThreadSafeQueue<ElementT, QueueT>::LLThreadSafeQueue(U32 capacity) : mCapacity(capacity), mClosed(false) { } -template<typename ElementT> -void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element) +// if we're able to lock immediately, do so and run the passed callable, which +// must accept lock_t& and return bool +template <typename ElementT, typename QueueT> +template <typename CALLABLE> +bool LLThreadSafeQueue<ElementT, QueueT>::tryLock(CALLABLE&& callable) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + lock_t lock1(mLock, std::defer_lock); + if (!lock1.try_lock()) + return false; + + return std::forward<CALLABLE>(callable)(lock1); +} + + +// if we're able to lock before the passed time_point, do so and run the +// passed callable, which must accept lock_t& and return bool +template <typename ElementT, typename QueueT> +template <typename Clock, typename Duration, typename CALLABLE> +bool LLThreadSafeQueue<ElementT, QueueT>::tryLockUntil( + const std::chrono::time_point<Clock, Duration>& until, + CALLABLE&& callable) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + lock_t lock1(mLock, std::defer_lock); + if (!lock1.try_lock_until(until)) + return false; + + return std::forward<CALLABLE>(callable)(lock1); +} + + +// while lock is locked, really push the passed element, if we can +template <typename ElementT, typename QueueT> +template <typename T> +bool LLThreadSafeQueue<ElementT, QueueT>::push_(lock_t& lock, T&& element) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + if (mStorage.size() >= mCapacity) + return false; + + mStorage.push(std::forward<T>(element)); + lock.unlock(); + // now that we've pushed, if somebody's been waiting to pop, signal them + mEmptyCond.notify_one(); + return true; +} + + +template <typename ElementT, typename QueueT> +template <typename T> +bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; lock_t lock1(mLock); while (true) { + // On the producer side, it doesn't matter whether the queue has been + // drained or not: the moment either end calls close(), further push() + // operations will fail. if (mClosed) - { - LLTHROW(LLThreadSafeQueueInterrupt()); - } + return false; - if (mStorage.size() < mCapacity) - { - mStorage.push_front(element); - lock1.unlock(); - mEmptyCond.notify_one(); - return; - } + if (push_(lock1, std::forward<T>(element))) + return true; // Storage Full. Wait for signal. mCapacityCond.wait(lock1); @@ -175,142 +341,250 @@ void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element) } -template <typename ElementT> -template <typename Rep, typename Period> -bool LLThreadSafeQueue<ElementT>::tryPushFrontFor(const std::chrono::duration<Rep, Period>& timeout, - ElementT const & element) +template <typename ElementT, typename QueueT> +template<typename T> +void LLThreadSafeQueue<ElementT, QueueT>::push(T&& element) { - // Convert duration to time_point: passing the same timeout duration to - // each of multiple calls is wrong. - auto endpoint = std::chrono::steady_clock::now() + timeout; + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + if (! pushIfOpen(std::forward<T>(element))) + { + LLTHROW(LLThreadSafeQueueInterrupt()); + } +} - lock_t lock1(mLock, std::defer_lock); - if (!lock1.try_lock_until(endpoint)) - return false; - while (true) - { - if (mClosed) +template<typename ElementT, typename QueueT> +template<typename T> +bool LLThreadSafeQueue<ElementT, QueueT>::tryPush(T&& element) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryLock( + [this, element=std::move(element)](lock_t& lock) { - return false; - } + if (mClosed) + return false; + return push_(lock, std::move(element)); + }); +} - if (mStorage.size() < mCapacity) - { - mStorage.push_front(element); - lock1.unlock(); - mEmptyCond.notify_one(); - return true; - } - // Storage Full. Wait for signal. - if (LLCoros::cv_status::timeout == mCapacityCond.wait_until(lock1, endpoint)) - { - // timed out -- formally we might recheck both conditions above - return false; - } - // If we didn't time out, we were notified for some reason. Loop back - // to check. - } +template <typename ElementT, typename QueueT> +template <typename Rep, typename Period, typename T> +bool LLThreadSafeQueue<ElementT, QueueT>::tryPushFor( + const std::chrono::duration<Rep, Period>& timeout, + T&& element) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + // Convert duration to time_point: passing the same timeout duration to + // each of multiple calls is wrong. + return tryPushUntil(std::chrono::steady_clock::now() + timeout, + std::forward<T>(element)); } -template<typename ElementT> -bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element) +template <typename ElementT, typename QueueT> +template <typename Clock, typename Duration, typename T> +bool LLThreadSafeQueue<ElementT, QueueT>::tryPushUntil( + const std::chrono::time_point<Clock, Duration>& until, + T&& element) { - lock_t lock1(mLock, std::defer_lock); - if (!lock1.try_lock()) - return false; + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryLockUntil( + until, + [this, until, element=std::move(element)](lock_t& lock) + { + while (true) + { + if (mClosed) + { + return false; + } + + if (push_(lock, std::move(element))) + return true; + + // Storage Full. Wait for signal. + if (LLCoros::cv_status::timeout == mCapacityCond.wait_until(lock, until)) + { + // timed out -- formally we might recheck both conditions above + return false; + } + // If we didn't time out, we were notified for some reason. Loop back + // to check. + } + }); +} - if (mClosed) - return false; - if (mStorage.size() >= mCapacity) - return false; +// while lock is locked, really pop the head element, if we can +template <typename ElementT, typename QueueT> +typename LLThreadSafeQueue<ElementT, QueueT>::pop_result +LLThreadSafeQueue<ElementT, QueueT>::pop_(lock_t& lock, ElementT& element) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + // If mStorage is empty, there's no head element. + if (mStorage.empty()) + return mClosed? DONE : EMPTY; - mStorage.push_front(element); - lock1.unlock(); - mEmptyCond.notify_one(); - return true; + // If there's a head element, pass it to canPop() to see if it's ready to pop. + if (! canPop(mStorage.front())) + return WAITING; + + // std::queue::front() is the element about to pop() + element = mStorage.front(); + mStorage.pop(); + lock.unlock(); + // now that we've popped, if somebody's been waiting to push, signal them + mCapacityCond.notify_one(); + return POPPED; } -template<typename ElementT> -ElementT LLThreadSafeQueue<ElementT>::popBack(void) +template<typename ElementT, typename QueueT> +ElementT LLThreadSafeQueue<ElementT, QueueT>::pop(void) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; lock_t lock1(mLock); + ElementT value; while (true) { - if (!mStorage.empty()) - { - ElementT value = mStorage.back(); - mStorage.pop_back(); - lock1.unlock(); - mCapacityCond.notify_one(); - return value; - } - - if (mClosed) + // On the consumer side, we always try to pop before checking mClosed + // so we can finish draining the queue. + pop_result popped = pop_(lock1, value); + if (popped == POPPED) + return std::move(value); + + // Once the queue is DONE, there will never be any more coming. + if (popped == DONE) { LLTHROW(LLThreadSafeQueueInterrupt()); } - // Storage empty. Wait for signal. + // If we didn't pop because WAITING, i.e. canPop() returned false, + // then even if the producer end has been closed, there's still at + // least one item to drain: wait for it. Or we might be EMPTY, with + // the queue still open. Either way, wait for signal. mEmptyCond.wait(lock1); } } -template<typename ElementT> -bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element) +template<typename ElementT, typename QueueT> +bool LLThreadSafeQueue<ElementT, QueueT>::tryPop(ElementT & element) { - lock_t lock1(mLock, std::defer_lock); - if (!lock1.try_lock()) - return false; + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryLock( + [this, &element](lock_t& lock) + { + // conflate EMPTY, DONE, WAITING: tryPop() behavior when the queue + // is closed is implemented by simple inability to push any new + // elements + return pop_(lock, element) == POPPED; + }); +} - // no need to check mClosed: tryPopBack() behavior when the queue is - // closed is implemented by simple inability to push any new elements - if (mStorage.empty()) - return false; - element = mStorage.back(); - mStorage.pop_back(); - lock1.unlock(); - mCapacityCond.notify_one(); - return true; +template <typename ElementT, typename QueueT> +template <typename Rep, typename Period> +bool LLThreadSafeQueue<ElementT, QueueT>::tryPopFor( + const std::chrono::duration<Rep, Period>& timeout, + ElementT& element) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + // Convert duration to time_point: passing the same timeout duration to + // each of multiple calls is wrong. + return tryPopUntil(std::chrono::steady_clock::now() + timeout, element); } -template<typename ElementT> -size_t LLThreadSafeQueue<ElementT>::size(void) +template <typename ElementT, typename QueueT> +template <typename Clock, typename Duration> +bool LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil( + const std::chrono::time_point<Clock, Duration>& until, + ElementT& element) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryLockUntil( + until, + [this, until, &element](lock_t& lock) + { + // conflate EMPTY, DONE, WAITING + return tryPopUntil_(lock, until, element) == POPPED; + }); +} + + +// body of tryPopUntil(), called once we have the lock +template <typename ElementT, typename QueueT> +template <typename Clock, typename Duration> +typename LLThreadSafeQueue<ElementT, QueueT>::pop_result +LLThreadSafeQueue<ElementT, QueueT>::tryPopUntil_( + lock_t& lock, + const std::chrono::time_point<Clock, Duration>& until, + ElementT& element) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + while (true) + { + pop_result popped = pop_(lock, element); + if (popped == POPPED || popped == DONE) + { + // If we succeeded, great! If we've drained the last item, so be + // it. Either way, break the loop and tell caller. + return popped; + } + + // EMPTY or WAITING: wait for signal. + if (LLCoros::cv_status::timeout == mEmptyCond.wait_until(lock, until)) + { + // timed out -- formally we might recheck + // as it is, break loop + return popped; + } + // If we didn't time out, we were notified for some reason. Loop back + // to check. + } +} + + +template<typename ElementT, typename QueueT> +size_t LLThreadSafeQueue<ElementT, QueueT>::size(void) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; lock_t lock(mLock); return mStorage.size(); } -template<typename ElementT> -void LLThreadSafeQueue<ElementT>::close() + +template<typename ElementT, typename QueueT> +void LLThreadSafeQueue<ElementT, QueueT>::close() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; lock_t lock(mLock); mClosed = true; lock.unlock(); - // wake up any blocked popBack() calls + // wake up any blocked pop() calls mEmptyCond.notify_all(); - // wake up any blocked pushFront() calls + // wake up any blocked push() calls mCapacityCond.notify_all(); } -template<typename ElementT> -bool LLThreadSafeQueue<ElementT>::isClosed() + +template<typename ElementT, typename QueueT> +bool LLThreadSafeQueue<ElementT, QueueT>::isClosed() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; lock_t lock(mLock); - return mClosed && mStorage.size() == 0; + return mClosed; } -template<typename ElementT> -LLThreadSafeQueue<ElementT>::operator bool() + +template<typename ElementT, typename QueueT> +bool LLThreadSafeQueue<ElementT, QueueT>::done() { - return ! isClosed(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + lock_t lock(mLock); + return mClosed && mStorage.empty(); } #endif diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index 54079a4689..f59b207ded 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -61,6 +61,7 @@ TimeBlockTreeNode::TimeBlockTreeNode() void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent ) { + LL_PROFILE_ZONE_SCOPED; llassert_always(parent != mBlock); llassert_always(parent != NULL); diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index 0d0cd6f581..fcd8753f75 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -227,6 +227,7 @@ public: void setName(const char* name) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mName = name; setKey(name); } @@ -234,12 +235,14 @@ public: /*virtual*/ const char* getUnitLabel() const { return "KB"; } StatType<MemAccumulator::AllocationFacet>& allocations() - { + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return static_cast<StatType<MemAccumulator::AllocationFacet>&>(*(StatType<MemAccumulator>*)this); } StatType<MemAccumulator::DeallocationFacet>& deallocations() - { + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return static_cast<StatType<MemAccumulator::DeallocationFacet>&>(*(StatType<MemAccumulator>*)this); } }; @@ -261,6 +264,7 @@ struct MeasureMem<T, typename T::mem_trackable_tag_t, IS_BYTES> { static size_t measureFootprint(const T& value) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return sizeof(T) + value.getMemFootprint(); } }; @@ -270,6 +274,7 @@ struct MeasureMem<T, IS_MEM_TRACKABLE, typename T::is_unit_t> { static size_t measureFootprint(const T& value) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return U32Bytes(value).value(); } }; @@ -279,6 +284,7 @@ struct MeasureMem<T*, IS_MEM_TRACKABLE, IS_BYTES> { static size_t measureFootprint(const T* value) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (!value) { return 0; @@ -323,6 +329,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES> { static size_t measureFootprint(const std::basic_string<T>& value) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return value.capacity() * sizeof(T); } }; @@ -331,6 +338,7 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES> template<typename T> inline void claim_alloc(MemStatHandle& measurement, const T& value) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED S32 size = MeasureMem<T>::measureFootprint(value); if(size == 0) return; @@ -343,6 +351,7 @@ inline void claim_alloc(MemStatHandle& measurement, const T& value) template<typename T> inline void disclaim_alloc(MemStatHandle& measurement, const T& value) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED S32 size = MeasureMem<T>::measureFootprint(value); if(size == 0) return; @@ -352,141 +361,6 @@ inline void disclaim_alloc(MemStatHandle& measurement, const T& value) #endif } -template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN> -class MemTrackableNonVirtual -{ -public: - typedef void mem_trackable_tag_t; - - MemTrackableNonVirtual(const char* name) -#if LL_TRACE_ENABLED - : mMemFootprint(0) -#endif - { -#if LL_TRACE_ENABLED - static bool name_initialized = false; - if (!name_initialized) - { - name_initialized = true; - sMemStat.setName(name); - } -#endif - } - -#if LL_TRACE_ENABLED - ~MemTrackableNonVirtual() - { - disclaimMem(mMemFootprint); - } - - static MemStatHandle& getMemStatHandle() - { - return sMemStat; - } - - S32 getMemFootprint() const { return mMemFootprint; } -#endif - - void* operator new(size_t size) - { -#if LL_TRACE_ENABLED - claim_alloc(sMemStat, size); -#endif - return ll_aligned_malloc<ALIGNMENT>(size); - } - - template<int CUSTOM_ALIGNMENT> - static void* aligned_new(size_t size) - { -#if LL_TRACE_ENABLED - claim_alloc(sMemStat, size); -#endif - return ll_aligned_malloc<CUSTOM_ALIGNMENT>(size); - } - - void operator delete(void* ptr, size_t size) - { -#if LL_TRACE_ENABLED - disclaim_alloc(sMemStat, size); -#endif - ll_aligned_free<ALIGNMENT>(ptr); - } - - template<int CUSTOM_ALIGNMENT> - static void aligned_delete(void* ptr, size_t size) - { -#if LL_TRACE_ENABLED - disclaim_alloc(sMemStat, size); -#endif - ll_aligned_free<CUSTOM_ALIGNMENT>(ptr); - } - - void* operator new [](size_t size) - { -#if LL_TRACE_ENABLED - claim_alloc(sMemStat, size); -#endif - return ll_aligned_malloc<ALIGNMENT>(size); - } - - void operator delete[](void* ptr, size_t size) - { -#if LL_TRACE_ENABLED - disclaim_alloc(sMemStat, size); -#endif - ll_aligned_free<ALIGNMENT>(ptr); - } - - // claim memory associated with other objects/data as our own, adding to our calculated footprint - template<typename CLAIM_T> - void claimMem(const CLAIM_T& value) const - { -#if LL_TRACE_ENABLED - S32 size = MeasureMem<CLAIM_T>::measureFootprint(value); - claim_alloc(sMemStat, size); - mMemFootprint += size; -#endif - } - - // remove memory we had claimed from our calculated footprint - template<typename CLAIM_T> - void disclaimMem(const CLAIM_T& value) const - { -#if LL_TRACE_ENABLED - S32 size = MeasureMem<CLAIM_T>::measureFootprint(value); - disclaim_alloc(sMemStat, size); - mMemFootprint -= size; -#endif - } - -private: -#if LL_TRACE_ENABLED - // use signed values so that we can temporarily go negative - // and reconcile in destructor - // NB: this assumes that no single class is responsible for > 2GB of allocations - mutable S32 mMemFootprint; - - static MemStatHandle sMemStat; -#endif - -}; - -#if LL_TRACE_ENABLED -template<typename DERIVED, size_t ALIGNMENT> -MemStatHandle MemTrackableNonVirtual<DERIVED, ALIGNMENT>::sMemStat(typeid(MemTrackableNonVirtual<DERIVED, ALIGNMENT>).name()); -#endif - -template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN> -class MemTrackable : public MemTrackableNonVirtual<DERIVED, ALIGNMENT> -{ -public: - MemTrackable(const char* name) - : MemTrackableNonVirtual<DERIVED, ALIGNMENT>(name) - {} - - virtual ~MemTrackable() - {} -}; } #endif // LL_LLTRACE_H diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index b1c23c6fb7..34299f5a29 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -41,6 +41,7 @@ extern MemStatHandle gTraceMemStat; AccumulatorBufferGroup::AccumulatorBufferGroup() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); @@ -55,6 +56,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth mStackTimers(other.mStackTimers), mMemStats(other.mMemStats) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); @@ -64,6 +66,7 @@ AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& oth AccumulatorBufferGroup::~AccumulatorBufferGroup() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); @@ -73,6 +76,7 @@ AccumulatorBufferGroup::~AccumulatorBufferGroup() void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; other.mCounts.reset(&mCounts); other.mSamples.reset(&mSamples); other.mEvents.reset(&mEvents); @@ -82,6 +86,7 @@ void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other) void AccumulatorBufferGroup::makeCurrent() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.makeCurrent(); mSamples.makeCurrent(); mEvents.makeCurrent(); @@ -104,6 +109,7 @@ void AccumulatorBufferGroup::makeCurrent() //static void AccumulatorBufferGroup::clearCurrent() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; AccumulatorBuffer<CountAccumulator>::clearCurrent(); AccumulatorBuffer<SampleAccumulator>::clearCurrent(); AccumulatorBuffer<EventAccumulator>::clearCurrent(); @@ -118,6 +124,7 @@ bool AccumulatorBufferGroup::isCurrent() const void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.addSamples(other.mCounts, SEQUENTIAL); mSamples.addSamples(other.mSamples, SEQUENTIAL); mEvents.addSamples(other.mEvents, SEQUENTIAL); @@ -127,6 +134,7 @@ void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.addSamples(other.mCounts, NON_SEQUENTIAL); mSamples.addSamples(other.mSamples, NON_SEQUENTIAL); mEvents.addSamples(other.mEvents, NON_SEQUENTIAL); @@ -137,6 +145,7 @@ void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other) void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.reset(other ? &other->mCounts : NULL); mSamples.reset(other ? &other->mSamples : NULL); mEvents.reset(other ? &other->mEvents : NULL); @@ -146,6 +155,7 @@ void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other) void AccumulatorBufferGroup::sync() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (isCurrent()) { F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); @@ -190,7 +200,7 @@ F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const Samp void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type ) { - if (append_type == NON_SEQUENTIAL) + if (append_type == NON_SEQUENTIAL) { return; } @@ -289,7 +299,7 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT void EventAccumulator::reset( const EventAccumulator* other ) { - mNumSamples = 0; + mNumSamples = 0; mSum = 0; mMin = F32(NaN); mMax = F32(NaN); diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index 8eb5338a2a..7267a44300 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -66,6 +66,7 @@ namespace LLTrace : mStorageSize(0), mStorage(NULL) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; const AccumulatorBuffer& other = *getDefaultBuffer(); resize(sNextStorageSlot); for (S32 i = 0; i < sNextStorageSlot; i++) @@ -76,6 +77,7 @@ namespace LLTrace ~AccumulatorBuffer() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (isCurrent()) { LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); @@ -98,6 +100,7 @@ namespace LLTrace : mStorageSize(0), mStorage(NULL) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; resize(sNextStorageSlot); for (S32 i = 0; i < sNextStorageSlot; i++) { @@ -107,6 +110,7 @@ namespace LLTrace void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); for (size_t i = 0; i < sNextStorageSlot; i++) { @@ -116,6 +120,7 @@ namespace LLTrace void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); for (size_t i = 0; i < sNextStorageSlot; i++) { @@ -125,6 +130,7 @@ namespace LLTrace void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; llassert(mStorageSize >= sNextStorageSlot); for (size_t i = 0; i < sNextStorageSlot; i++) { @@ -134,6 +140,7 @@ namespace LLTrace void sync(F64SecondsImplicit time_stamp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; llassert(mStorageSize >= sNextStorageSlot); for (size_t i = 0; i < sNextStorageSlot; i++) { @@ -153,12 +160,13 @@ namespace LLTrace static void clearCurrent() { - LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); } // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned size_t reserveSlot() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; size_t next_slot = sNextStorageSlot++; if (next_slot >= mStorageSize) { @@ -172,6 +180,7 @@ namespace LLTrace void resize(size_t new_size) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (new_size <= mStorageSize) return; ACCUMULATOR* old_storage = mStorage; @@ -212,6 +221,7 @@ namespace LLTrace static self_t* getDefaultBuffer() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; static bool sInitialized = false; if (!sInitialized) { @@ -326,6 +336,7 @@ namespace LLTrace void sample(F64 value) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); // store effect of last value @@ -444,9 +455,9 @@ namespace LLTrace S32 mNumSamples; }; - class TimeBlockAccumulator + class alignas(32) TimeBlockAccumulator { - public: + public: typedef F64Seconds value_t; static F64Seconds getDefaultValue() { return F64Seconds(0); } @@ -539,6 +550,7 @@ namespace LLTrace void addSamples(const MemAccumulator& other, EBufferAppendType append_type) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mAllocations.addSamples(other.mAllocations, append_type); mDeallocations.addSamples(other.mDeallocations, append_type); @@ -557,6 +569,7 @@ namespace LLTrace void reset(const MemAccumulator* other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mSize.reset(other ? &other->mSize : NULL); mAllocations.reset(other ? &other->mAllocations : NULL); mDeallocations.reset(other ? &other->mDeallocations : NULL); diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index 3094b627a2..1613af1dcf 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -50,6 +50,7 @@ Recording::Recording(EPlayState state) : mElapsedSeconds(0), mActiveBuffers(NULL) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; claim_alloc(gTraceMemStat, this); mBuffers = new AccumulatorBufferGroup(); claim_alloc(gTraceMemStat, mBuffers); @@ -59,12 +60,14 @@ Recording::Recording(EPlayState state) Recording::Recording( const Recording& other ) : mActiveBuffers(NULL) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; claim_alloc(gTraceMemStat, this); *this = other; } Recording& Recording::operator = (const Recording& other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; // this will allow us to seamlessly start without affecting any data we've acquired from other setPlayState(PAUSED); @@ -85,6 +88,7 @@ Recording& Recording::operator = (const Recording& other) Recording::~Recording() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; disclaim_alloc(gTraceMemStat, this); disclaim_alloc(gTraceMemStat, mBuffers); @@ -103,6 +107,7 @@ void Recording::update() #if LL_TRACE_ENABLED if (isStarted()) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); // must have @@ -123,6 +128,7 @@ void Recording::update() void Recording::handleReset() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED mBuffers.write()->reset(); @@ -133,6 +139,7 @@ void Recording::handleReset() void Recording::handleStart() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED mSamplingTimer.reset(); mBuffers.setStayUnique(true); @@ -144,6 +151,7 @@ void Recording::handleStart() void Recording::handleStop() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); // must have thread recorder running on this thread @@ -273,7 +281,7 @@ F64Kilobytes Recording::getMean(const StatType<MemAccumulator>& stat) F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return F64Bytes(llmax(accumulator.mSize.getMax(), active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMax() : F32_MIN)); @@ -281,7 +289,7 @@ F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat) F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) @@ -297,7 +305,7 @@ F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& sta F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return F64Bytes(active_accumulator ? active_accumulator->mSize.getLastValue() : accumulator.mSize.getLastValue()); @@ -305,7 +313,7 @@ F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat) bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return accumulator.mAllocations.hasValue() || (active_accumulator ? active_accumulator->mAllocations.hasValue() : false); @@ -313,7 +321,7 @@ bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat) F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return F64Bytes(accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)); @@ -321,7 +329,7 @@ F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>& F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return F64Bytes((accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)) / mElapsedSeconds.value()); @@ -329,7 +337,7 @@ F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return accumulator.mAllocations.getSampleCount() + (active_accumulator ? active_accumulator->mAllocations.getSampleCount() : 0); @@ -337,7 +345,7 @@ S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& s bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return accumulator.mDeallocations.hasValue() || (active_accumulator ? active_accumulator->mDeallocations.hasValue() : false); @@ -346,7 +354,7 @@ bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return F64Bytes(accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)); @@ -354,7 +362,7 @@ F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet> F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFacet>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return F64Bytes((accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)) / mElapsedSeconds.value()); @@ -362,7 +370,7 @@ F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFac S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& stat) { - update(); + update(); const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; return accumulator.mDeallocations.getSampleCount() + (active_accumulator ? active_accumulator->mDeallocations.getSampleCount() : 0); @@ -370,7 +378,7 @@ S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& bool Recording::hasValue(const StatType<CountAccumulator>& stat) { - update(); + update(); const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false); @@ -378,7 +386,7 @@ bool Recording::hasValue(const StatType<CountAccumulator>& stat) F64 Recording::getSum(const StatType<CountAccumulator>& stat) { - update(); + update(); const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); @@ -386,7 +394,7 @@ F64 Recording::getSum(const StatType<CountAccumulator>& stat) F64 Recording::getPerSec( const StatType<CountAccumulator>& stat ) { - update(); + update(); const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); @@ -395,7 +403,7 @@ F64 Recording::getPerSec( const StatType<CountAccumulator>& stat ) S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat ) { - update(); + update(); const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); @@ -403,7 +411,7 @@ S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat ) bool Recording::hasValue(const StatType<SampleAccumulator>& stat) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); @@ -411,7 +419,7 @@ bool Recording::hasValue(const StatType<SampleAccumulator>& stat) F64 Recording::getMin( const StatType<SampleAccumulator>& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); @@ -419,7 +427,7 @@ F64 Recording::getMin( const StatType<SampleAccumulator>& stat ) F64 Recording::getMax( const StatType<SampleAccumulator>& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); @@ -427,7 +435,7 @@ F64 Recording::getMax( const StatType<SampleAccumulator>& stat ) F64 Recording::getMean( const StatType<SampleAccumulator>& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) @@ -448,7 +456,7 @@ F64 Recording::getMean( const StatType<SampleAccumulator>& stat ) F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; @@ -465,7 +473,7 @@ F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat ) F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue()); @@ -473,7 +481,7 @@ F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat ) S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat ) { - update(); + update(); const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0); @@ -481,7 +489,7 @@ S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat ) bool Recording::hasValue(const StatType<EventAccumulator>& stat) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); @@ -489,7 +497,7 @@ bool Recording::hasValue(const StatType<EventAccumulator>& stat) F64 Recording::getSum( const StatType<EventAccumulator>& stat) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0)); @@ -497,7 +505,7 @@ F64 Recording::getSum( const StatType<EventAccumulator>& stat) F64 Recording::getMin( const StatType<EventAccumulator>& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); @@ -505,7 +513,7 @@ F64 Recording::getMin( const StatType<EventAccumulator>& stat ) F64 Recording::getMax( const StatType<EventAccumulator>& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); @@ -513,7 +521,7 @@ F64 Recording::getMax( const StatType<EventAccumulator>& stat ) F64 Recording::getMean( const StatType<EventAccumulator>& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) @@ -534,7 +542,7 @@ F64 Recording::getMean( const StatType<EventAccumulator>& stat ) F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; @@ -551,7 +559,7 @@ F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat ) F64 Recording::getLastValue( const StatType<EventAccumulator>& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue(); @@ -559,7 +567,7 @@ F64 Recording::getLastValue( const StatType<EventAccumulator>& stat ) S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat ) { - update(); + update(); const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); @@ -575,17 +583,20 @@ PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state) mNumRecordedPeriods(0), mRecordingPeriods(num_periods ? num_periods : 1) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; setPlayState(state); claim_alloc(gTraceMemStat, this); } PeriodicRecording::~PeriodicRecording() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; disclaim_alloc(gTraceMemStat, this); } void PeriodicRecording::nextPeriod() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (mAutoResize) { mRecordingPeriods.push_back(Recording()); @@ -600,6 +611,7 @@ void PeriodicRecording::nextPeriod() void PeriodicRecording::appendRecording(Recording& recording) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().appendRecording(recording); nextPeriod(); } @@ -607,6 +619,7 @@ void PeriodicRecording::appendRecording(Recording& recording) void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (other.mRecordingPeriods.empty()) return; getCurRecording().update(); @@ -680,6 +693,7 @@ void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) F64Seconds PeriodicRecording::getDuration() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; F64Seconds duration; S32 num_periods = mRecordingPeriods.size(); for (S32 i = 1; i <= num_periods; i++) @@ -693,6 +707,7 @@ F64Seconds PeriodicRecording::getDuration() const LLTrace::Recording PeriodicRecording::snapshotCurRecording() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; Recording recording_copy(getCurRecording()); recording_copy.stop(); return recording_copy; @@ -735,16 +750,19 @@ const Recording& PeriodicRecording::getPrevRecording( S32 offset ) const void PeriodicRecording::handleStart() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().start(); } void PeriodicRecording::handleStop() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().pause(); } void PeriodicRecording::handleReset() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().stop(); if (mAutoResize) @@ -768,11 +786,13 @@ void PeriodicRecording::handleReset() void PeriodicRecording::handleSplitTo(PeriodicRecording& other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; getCurRecording().splitTo(other.getCurRecording()); } F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -794,6 +814,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32 F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -816,6 +837,7 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32 // calculates means using aggregates per period F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 mean = 0; @@ -836,9 +858,9 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S3 : NaN; } - F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 period_mean = getPeriodMean(stat, num_periods); @@ -863,6 +885,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -884,6 +907,7 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S3 F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -906,6 +930,7 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32 F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); S32 valid_period_count = 0; @@ -926,8 +951,35 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S : NaN; } +F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector<F64> buf; + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + if (recording.hasValue(stat)) + { + buf.push_back(recording.getMean(stat)); + } + } + } + if (buf.size()==0) + { + return 0.0f; + } + std::sort(buf.begin(), buf.end()); + + return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); +} + F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 period_mean = getPeriodMean(stat, num_periods); @@ -953,6 +1005,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64Kilobytes min_val(std::numeric_limits<F64>::max()); @@ -972,6 +1025,7 @@ F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, S32 num_ F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64Kilobytes max_val(0.0); @@ -991,6 +1045,7 @@ F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, S32 num_ F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64Kilobytes mean(0); @@ -1011,6 +1066,7 @@ F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, S32 num F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64Kilobytes period_mean = getPeriodMean(stat, num_periods); @@ -1044,6 +1100,7 @@ F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle& void ExtendableRecording::extend() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; // push the data back to accepted recording mAcceptedRecording.appendRecording(mPotentialRecording); // flush data, so we can start from scratch @@ -1052,22 +1109,26 @@ void ExtendableRecording::extend() void ExtendableRecording::handleStart() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.start(); } void ExtendableRecording::handleStop() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.pause(); } void ExtendableRecording::handleReset() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mAcceptedRecording.reset(); mPotentialRecording.reset(); } void ExtendableRecording::handleSplitTo(ExtendableRecording& other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.splitTo(other.mPotentialRecording); } @@ -1084,6 +1145,7 @@ ExtendablePeriodicRecording::ExtendablePeriodicRecording() void ExtendablePeriodicRecording::extend() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; // push the data back to accepted recording mAcceptedRecording.appendPeriodicRecording(mPotentialRecording); // flush data, so we can start from scratch @@ -1093,22 +1155,26 @@ void ExtendablePeriodicRecording::extend() void ExtendablePeriodicRecording::handleStart() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.start(); } void ExtendablePeriodicRecording::handleStop() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.pause(); } void ExtendablePeriodicRecording::handleReset() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mAcceptedRecording.reset(); mPotentialRecording.reset(); } void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mPotentialRecording.splitTo(other.mPotentialRecording); } @@ -1123,6 +1189,7 @@ PeriodicRecording& get_frame_recording() void LLStopWatchControlsMixinCommon::start() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1144,6 +1211,7 @@ void LLStopWatchControlsMixinCommon::start() void LLStopWatchControlsMixinCommon::stop() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1163,6 +1231,7 @@ void LLStopWatchControlsMixinCommon::stop() void LLStopWatchControlsMixinCommon::pause() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1182,6 +1251,7 @@ void LLStopWatchControlsMixinCommon::pause() void LLStopWatchControlsMixinCommon::unpause() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1201,6 +1271,7 @@ void LLStopWatchControlsMixinCommon::unpause() void LLStopWatchControlsMixinCommon::resume() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1221,6 +1292,7 @@ void LLStopWatchControlsMixinCommon::resume() void LLStopWatchControlsMixinCommon::restart() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch (mPlayState) { case STOPPED: @@ -1244,11 +1316,13 @@ void LLStopWatchControlsMixinCommon::restart() void LLStopWatchControlsMixinCommon::reset() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; handleReset(); } void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; switch(state) { case STOPPED: diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index d0b4a842a6..556b7470cf 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -355,6 +355,7 @@ namespace LLTrace template <typename T> S32 getSampleCount(const StatType<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); S32 num_samples = 0; @@ -374,6 +375,7 @@ namespace LLTrace template <typename T> typename T::value_t getPeriodMin(const StatType<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -396,6 +398,7 @@ namespace LLTrace template<typename T> T getPeriodMin(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); } @@ -403,6 +406,7 @@ namespace LLTrace template<typename T> T getPeriodMin(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); } @@ -410,6 +414,7 @@ namespace LLTrace template<typename T> T getPeriodMin(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); } @@ -419,6 +424,7 @@ namespace LLTrace template <typename T> typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max()); @@ -433,6 +439,7 @@ namespace LLTrace template<typename T> typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); } @@ -444,6 +451,7 @@ namespace LLTrace template <typename T> typename T::value_t getPeriodMax(const StatType<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); bool has_value = false; @@ -466,6 +474,7 @@ namespace LLTrace template<typename T> T getPeriodMax(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); } @@ -473,6 +482,7 @@ namespace LLTrace template<typename T> T getPeriodMax(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); } @@ -480,6 +490,7 @@ namespace LLTrace template<typename T> T getPeriodMax(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); } @@ -489,6 +500,7 @@ namespace LLTrace template <typename T> typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); F64 max_val = std::numeric_limits<F64>::min(); @@ -503,6 +515,7 @@ namespace LLTrace template<typename T> typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); } @@ -514,6 +527,7 @@ namespace LLTrace template <typename T> typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes<typename T::value_t>::fractional_t mean(0); @@ -534,12 +548,14 @@ namespace LLTrace template<typename T> typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); } F64 getPeriodMean(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); template<typename T> typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); } @@ -547,6 +563,7 @@ namespace LLTrace template<typename T> typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); } @@ -556,6 +573,7 @@ namespace LLTrace template <typename T> typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; num_periods = llmin(num_periods, getNumRecordedPeriods()); typename RelatedTypes<typename T::value_t>::fractional_t mean = 0; @@ -577,9 +595,39 @@ namespace LLTrace template<typename T> typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); } + F64 getPeriodMedian( const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMedianPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector <typename RelatedTypes<typename T::value_t>::fractional_t> buf; + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + buf.push_back(recording.getPerSec(stat)); + } + } + std::sort(buf.begin(), buf.end()); + + return typename RelatedTypes<T>::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMedianPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes<T>::fractional_t(getPeriodMedianPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + // // PERIODIC STANDARD DEVIATION // @@ -589,6 +637,7 @@ namespace LLTrace template<typename T> typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); } @@ -596,6 +645,7 @@ namespace LLTrace template<typename T> typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); } diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 025dc57044..090d3297a0 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -274,12 +274,10 @@ void ThreadRecorder::pushToParent() } -static LLTrace::BlockTimerStatHandle FTM_PULL_TRACE_DATA_FROM_CHILDREN("Pull child thread trace data"); - void ThreadRecorder::pullFromChildren() { #if LL_TRACE_ENABLED - LL_RECORD_BLOCK_TIME(FTM_PULL_TRACE_DATA_FROM_CHILDREN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; if (mActiveRecordings.empty()) return; { LLMutexLock lock(&mChildListMutex); diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index fe7482ba29..86a396ab06 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -184,6 +184,17 @@ struct boost::hash<LLUUID> } }; +// Adapt boost hash to std hash +namespace std +{ + template<> struct hash<LLUUID> + { + std::size_t operator()(LLUUID const& s) const noexcept + { + return boost::hash<LLUUID>()(s); + } + }; +} #endif diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h index 887f6ab733..b07805b628 100644 --- a/indra/llcommon/stdtypes.h +++ b/indra/llcommon/stdtypes.h @@ -42,10 +42,17 @@ typedef unsigned int U32; // Windows wchar_t is 16-bit, whichever way /Zc:wchar_t is set. In effect, // Windows wchar_t is always a typedef, either for unsigned short or __wchar_t. // (__wchar_t, available either way, is Microsoft's native 2-byte wchar_t type.) +// The version of clang available with VS 2019 also defines wchar_t as __wchar_t +// which is also 16 bits. // In any case, llwchar should be a UTF-32 type. typedef U32 llwchar; #else typedef wchar_t llwchar; +// What we'd actually want is a simple module-scope 'if constexpr' to test +// std::is_same<wchar_t, llwchar>::value and use that to define, or not +// define, string conversion specializations. Since we don't have that, we'll +// have to rely on #if instead. Sorry, Dr. Stroustrup. +#define LLWCHAR_IS_WCHAR_T 1 #endif #if LL_WINDOWS diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h index 38dd198ad3..12df693910 100644 --- a/indra/llcommon/stringize.h +++ b/indra/llcommon/stringize.h @@ -31,58 +31,109 @@ #include <sstream> #include <llstring.h> +#include <boost/call_traits.hpp> /** - * gstringize(item) encapsulates an idiom we use constantly, using - * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str() - * or their wstring equivalents - * to render a string expressing some item. + * stream_to(std::ostream&, items, ...) streams each item in the parameter list + * to the passed std::ostream using the insertion operator <<. This can be + * used, for instance, to make a simple print() function, e.g.: + * + * @code + * template <typename... Items> + * void print(Items&&... items) + * { + * stream_to(std::cout, std::forward<Items>(items)...); + * } + * @endcode */ -template <typename CHARTYPE, typename T> -std::basic_string<CHARTYPE> gstringize(const T& item) +// recursion tail +template <typename CHARTYPE> +void stream_to(std::basic_ostream<CHARTYPE>& out) {} +// stream one or more items +template <typename CHARTYPE, typename T, typename... Items> +void stream_to(std::basic_ostream<CHARTYPE>& out, T&& item, Items&&... items) { - std::basic_ostringstream<CHARTYPE> out; - out << item; - return out.str(); + out << std::forward<T>(item); + stream_to(out, std::forward<Items>(items)...); } +// why we use function overloads, not function template specializations: +// http://www.gotw.ca/publications/mill17.htm + /** - *partial specialization of stringize for handling wstring - *TODO: we should have similar specializations for wchar_t[] but not until it is needed. + * gstringize(item, ...) encapsulates an idiom we use constantly, using + * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str() + * or their wstring equivalents to render a string expressing one or more items. */ -inline std::string stringize(const std::wstring& item) +// two or more args - the case of a single argument is handled separately +template <typename CHARTYPE, typename T0, typename T1, typename... Items> +auto gstringize(T0&& item0, T1&& item1, Items&&... items) { - return wstring_to_utf8str(item); + std::basic_ostringstream<CHARTYPE> out; + stream_to(out, std::forward<T0>(item0), std::forward<T1>(item1), + std::forward<Items>(items)...); + return out.str(); } -/** - * Specialization of gstringize for std::string return types - */ -template <typename T> -std::string stringize(const T& item) +// generic single argument: stream to out, as above +template <typename CHARTYPE, typename T> +struct gstringize_impl { - return gstringize<char>(item); + auto operator()(typename boost::call_traits<T>::param_type arg) + { + std::basic_ostringstream<CHARTYPE> out; + out << arg; + return out.str(); + } +}; + +// partially specialize for a single STRING argument - +// note that ll_convert<T>(T) already handles the trivial case +template <typename OUTCHAR, typename INCHAR> +struct gstringize_impl<OUTCHAR, std::basic_string<INCHAR>> +{ + auto operator()(const std::basic_string<INCHAR>& arg) + { + return ll_convert<std::basic_string<OUTCHAR>>(arg); + } +}; + +// partially specialize for a single CHARTYPE* argument - +// since it's not a basic_string and we do want to optimize this common case +template <typename OUTCHAR, typename INCHAR> +struct gstringize_impl<OUTCHAR, INCHAR*> +{ + auto operator()(const INCHAR* arg) + { + return ll_convert<std::basic_string<OUTCHAR>>(arg); + } +}; + +// gstringize(single argument) +template <typename CHARTYPE, typename T> +auto gstringize(T&& item) +{ + // use decay<T> so we don't require separate specializations + // for T, const T, T&, const T& ... + return gstringize_impl<CHARTYPE, std::decay_t<T>>()(std::forward<T>(item)); } /** - * Specialization for generating wstring from string. - * Both a convenience function and saves a miniscule amount of overhead. + * Specialization of gstringize for std::string return types */ -inline std::wstring wstringize(const std::string& item) +template <typename... Items> +auto stringize(Items&&... items) { - // utf8str_to_wstring() returns LLWString, which isn't necessarily the - // same as std::wstring - LLWString s(utf8str_to_wstring(item)); - return std::wstring(s.begin(), s.end()); + return gstringize<char>(std::forward<Items>(items)...); } /** * Specialization of gstringize for std::wstring return types */ -template <typename T> -std::wstring wstringize(const T& item) +template <typename... Items> +auto wstringize(Items&&... items) { - return gstringize<wchar_t>(item); + return gstringize<wchar_t>(std::forward<Items>(items)...); } /** @@ -146,11 +197,9 @@ void destringize_f(std::basic_string<CHARTYPE> const & str, Functor const & f) * std::istringstream in(str); * in >> item1 >> item2 >> item3 ... ; * @endcode - * @NOTE - once we get generic lambdas, we shouldn't need DEWSTRINGIZE() any - * more since DESTRINGIZE() should do the right thing with a std::wstring. But - * until then, the lambda we pass must accept the right std::basic_istream. */ -#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::istream& in){in >> EXPRESSION;})) -#define DEWSTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::wistream& in){in >> EXPRESSION;})) +#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](auto& in){in >> EXPRESSION;})) +// legacy name, just use DESTRINGIZE() going forward +#define DEWSTRINGIZE(STR, EXPRESSION) DESTRINGIZE(STR, EXPRESSION) #endif /* ! defined(LL_STRINGIZE_H) */ diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 9b89159625..5daa29adf4 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -90,19 +90,19 @@ namespace tut { Keyed one("one"); ensure_equals(Keyed::instanceCount(), 1); - Keyed* found = Keyed::getInstance("one"); - ensure("couldn't find stack Keyed", found); - ensure_equals("found wrong Keyed instance", found, &one); + auto found = Keyed::getInstance("one"); + ensure("couldn't find stack Keyed", bool(found)); + ensure_equals("found wrong Keyed instance", found.get(), &one); { boost::scoped_ptr<Keyed> two(new Keyed("two")); ensure_equals(Keyed::instanceCount(), 2); - Keyed* found = Keyed::getInstance("two"); - ensure("couldn't find heap Keyed", found); - ensure_equals("found wrong Keyed instance", found, two.get()); + auto found = Keyed::getInstance("two"); + ensure("couldn't find heap Keyed", bool(found)); + ensure_equals("found wrong Keyed instance", found.get(), two.get()); } ensure_equals(Keyed::instanceCount(), 1); } - Keyed* found = Keyed::getInstance("one"); + auto found = Keyed::getInstance("one"); ensure("Keyed key lives too long", ! found); ensure_equals(Keyed::instanceCount(), 0); } diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index e530975e86..999d432079 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -356,14 +356,15 @@ namespace tut // Create a script file in a temporary place. NamedTempFile script("py", + "from __future__ import print_function" EOL "import sys" EOL "import time" EOL EOL "time.sleep(2)" EOL - "print('stdout after wait', file=sys.stdout)" EOL + "print('stdout after wait',file=sys.stdout)" EOL "sys.stdout.flush()" EOL "time.sleep(2)" EOL - "print('stderr after wait', file=sys.stderr)" EOL + "print('stderr after wait',file=sys.stderr)" EOL "sys.stderr.flush()" EOL ); @@ -572,12 +573,12 @@ namespace tut { set_test_name("arguments"); PythonProcessLauncher py(get_test_name(), - "from __future__ import with_statement\n" + "from __future__ import with_statement, print_function\n" "import sys\n" // note nonstandard output-file arg! "with open(sys.argv[3], 'w') as f:\n" " for arg in sys.argv[1:]:\n" - " print(arg, file=f)\n"); + " print(arg,file=f)\n"); // We expect that PythonProcessLauncher has already appended // its own NamedTempFile to mParams.args (sys.argv[0]). py.mParams.args.add("first arg"); // sys.argv[1] @@ -861,6 +862,7 @@ namespace tut set_test_name("'bogus' test"); CaptureLog recorder; PythonProcessLauncher py(get_test_name(), + "from __future__ import print_function\n" "print('Hello world')\n"); py.mParams.files.add(LLProcess::FileParam("bogus")); py.mPy = LLProcess::create(py.mParams); @@ -876,6 +878,7 @@ namespace tut // Replace this test with one or more real 'file' tests when we // implement 'file' support PythonProcessLauncher py(get_test_name(), + "from __future__ import print_function\n" "print('Hello world')\n"); py.mParams.files.add(LLProcess::FileParam()); py.mParams.files.add(LLProcess::FileParam("file")); @@ -891,6 +894,7 @@ namespace tut // implement 'tpipe' support CaptureLog recorder; PythonProcessLauncher py(get_test_name(), + "from __future__ import print_function\n" "print('Hello world')\n"); py.mParams.files.add(LLProcess::FileParam()); py.mParams.files.add(LLProcess::FileParam("tpipe")); @@ -908,6 +912,7 @@ namespace tut // implement 'npipe' support CaptureLog recorder; PythonProcessLauncher py(get_test_name(), + "from __future__ import print_function\n" "print('Hello world')\n"); py.mParams.files.add(LLProcess::FileParam()); py.mParams.files.add(LLProcess::FileParam()); @@ -984,7 +989,8 @@ namespace tut { set_test_name("get*Pipe() validation"); PythonProcessLauncher py(get_test_name(), - "print('this output is expected)'\n"); + "from __future__ import print_function\n" + "print('this output is expected')\n"); py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stdin py.mParams.files.add(LLProcess::FileParam()); // inherit stdout py.mParams.files.add(LLProcess::FileParam("pipe")); // pipe for stderr @@ -1004,6 +1010,7 @@ namespace tut { set_test_name("talk to stdin/stdout"); PythonProcessLauncher py(get_test_name(), + "from __future__ import print_function\n" "import sys, time\n" "print('ok')\n" "sys.stdout.flush()\n" @@ -1122,6 +1129,7 @@ namespace tut { set_test_name("ReadPipe \"eof\" event"); PythonProcessLauncher py(get_test_name(), + "from __future__ import print_function\n" "print('Hello from Python!')\n"); py.mParams.files.add(LLProcess::FileParam()); // stdin py.mParams.files.add(LLProcess::FileParam("pipe")); // stdout diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp new file mode 100644 index 0000000000..c421cc7b1c --- /dev/null +++ b/indra/llcommon/tests/threadsafeschedule_test.cpp @@ -0,0 +1,69 @@ +/** + * @file threadsafeschedule_test.cpp + * @author Nat Goodspeed + * @date 2021-10-04 + * @brief Test for threadsafeschedule. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "threadsafeschedule.h" +// STL headers +// std headers +#include <chrono> +// external library headers +// other Linden headers +#include "../test/lltut.h" + +using namespace std::literals::chrono_literals; // ms suffix +using namespace std::literals::string_literals; // s suffix +using Queue = LL::ThreadSafeSchedule<std::string>; + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct threadsafeschedule_data + { + Queue queue; + }; + typedef test_group<threadsafeschedule_data> threadsafeschedule_group; + typedef threadsafeschedule_group::object object; + threadsafeschedule_group threadsafeschedulegrp("threadsafeschedule"); + + template<> template<> + void object::test<1>() + { + set_test_name("push"); + // Simply calling push() a few times might result in indeterminate + // delivery order if the resolution of steady_clock is coarser than + // the real time required for each push() call. Explicitly increment + // the timestamp for each one -- but since we're passing explicit + // timestamps, make the queue reorder them. + queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi")); + // Given the various push() overloads, you have to match the type + // exactly: conversions are ambiguous. + queue.push("abc"s); + queue.push(Queue::Clock::now() + 100ms, "def"); + queue.close(); + auto entry = queue.pop(); + ensure_equals("failed to pop first", std::get<0>(entry), "abc"s); + entry = queue.pop(); + ensure_equals("failed to pop second", std::get<0>(entry), "def"s); + ensure("queue not closed", queue.isClosed()); + ensure("queue prematurely done", ! queue.done()); + std::string s; + bool popped = queue.tryPopFor(1s, s); + ensure("failed to pop third", popped); + ensure_equals("third is wrong", s, "ghi"s); + popped = queue.tryPop(s); + ensure("queue not empty", ! popped); + ensure("queue not done", queue.done()); + } +} // namespace tut diff --git a/indra/llcommon/tests/tuple_test.cpp b/indra/llcommon/tests/tuple_test.cpp new file mode 100644 index 0000000000..af94e2086c --- /dev/null +++ b/indra/llcommon/tests/tuple_test.cpp @@ -0,0 +1,47 @@ +/** + * @file tuple_test.cpp + * @author Nat Goodspeed + * @date 2021-10-04 + * @brief Test for tuple. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "tuple.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "../test/lltut.h" + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct tuple_data + { + }; + typedef test_group<tuple_data> tuple_group; + typedef tuple_group::object object; + tuple_group tuplegrp("tuple"); + + template<> template<> + void object::test<1>() + { + set_test_name("tuple"); + std::tuple<std::string, int> tup{ "abc", 17 }; + std::tuple<int, std::string, int> ptup{ tuple_cons(34, tup) }; + std::tuple<std::string, int> tup2; + int i; + std::tie(i, tup2) = tuple_split(ptup); + ensure_equals("tuple_car() fail", i, 34); + ensure_equals("tuple_cdr() (0) fail", std::get<0>(tup2), "abc"); + ensure_equals("tuple_cdr() (1) fail", std::get<1>(tup2), 17); + } +} // namespace tut diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp new file mode 100644 index 0000000000..1d73f7aa0d --- /dev/null +++ b/indra/llcommon/tests/workqueue_test.cpp @@ -0,0 +1,235 @@ +/** + * @file workqueue_test.cpp + * @author Nat Goodspeed + * @date 2021-10-07 + * @brief Test for workqueue. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "workqueue.h" +// STL headers +// std headers +#include <chrono> +#include <deque> +// external library headers +// other Linden headers +#include "../test/lltut.h" +#include "../test/catch_and_store_what_in.h" +#include "llcond.h" +#include "llcoros.h" +#include "lleventcoro.h" +#include "llstring.h" +#include "stringize.h" + +using namespace LL; +using namespace std::literals::chrono_literals; // ms suffix +using namespace std::literals::string_literals; // s suffix + +/***************************************************************************** +* TUT +*****************************************************************************/ +namespace tut +{ + struct workqueue_data + { + WorkQueue queue{"queue"}; + }; + typedef test_group<workqueue_data> workqueue_group; + typedef workqueue_group::object object; + workqueue_group workqueuegrp("workqueue"); + + template<> template<> + void object::test<1>() + { + set_test_name("name"); + ensure_equals("didn't capture name", queue.getKey(), "queue"); + ensure("not findable", WorkQueue::getInstance("queue") == queue.getWeak().lock()); + WorkQueue q2; + ensure("has no name", LLStringUtil::startsWith(q2.getKey(), "WorkQueue")); + } + + template<> template<> + void object::test<2>() + { + set_test_name("post"); + bool wasRun{ false }; + // We only get away with binding a simple bool because we're running + // the work on the same thread. + queue.post([&wasRun](){ wasRun = true; }); + queue.close(); + ensure("ran too soon", ! wasRun); + queue.runUntilClose(); + ensure("didn't run", wasRun); + } + + template<> template<> + void object::test<3>() + { + set_test_name("postEvery"); + // record of runs + using Shared = std::deque<WorkQueue::TimePoint>; + // This is an example of how to share data between the originator of + // postEvery(work) and the work item itself, since usually a WorkQueue + // is used to dispatch work to a different thread. Neither of them + // should call any of LLCond's wait methods: you don't want to stall + // either the worker thread or the originating thread (conventionally + // main). Use LLCond or a subclass even if all you want to do is + // signal the work item that it can quit; consider LLOneShotCond. + LLCond<Shared> data; + auto start = WorkQueue::TimePoint::clock::now(); + auto interval = 100ms; + queue.postEvery( + interval, + [&data, count = 0] + () mutable + { + // record the timestamp at which this instance is running + data.update_one( + [](Shared& data) + { + data.push_back(WorkQueue::TimePoint::clock::now()); + }); + // by the 3rd call, return false to stop + return (++count < 3); + }); + // no convenient way to close() our queue while we've got a + // postEvery() running, so run until we have exhausted the iterations + // or we time out waiting + for (auto finish = start + 10*interval; + WorkQueue::TimePoint::clock::now() < finish && + data.get([](const Shared& data){ return data.size(); }) < 3; ) + { + queue.runPending(); + std::this_thread::sleep_for(interval/10); + } + // Take a copy of the captured deque. + Shared result = data.get(); + ensure_equals("called wrong number of times", result.size(), 3); + // postEvery() assumes you want the first call to happen right away. + // Pretend our start time was (interval) earlier than that, to make + // our too early/too late tests uniform for all entries. + start -= interval; + for (size_t i = 0; i < result.size(); ++i) + { + auto diff = result[i] - start; + start += interval; + try + { + ensure(STRINGIZE("call " << i << " too soon"), diff >= interval); + ensure(STRINGIZE("call " << i << " too late"), diff < interval*1.5); + } + catch (const tut::failure&) + { + auto interval_ms = interval / 1ms; + auto diff_ms = diff / 1ms; + std::cerr << "interval " << interval_ms + << "ms; diff " << diff_ms << "ms" << std::endl; + throw; + } + } + } + + template<> template<> + void object::test<4>() + { + set_test_name("postTo"); + WorkQueue main("main"); + auto qptr = WorkQueue::getInstance("queue"); + int result = 0; + main.postTo( + qptr, + [](){ return 17; }, + // Note that a postTo() *callback* can safely bind a reference to + // a variable on the invoking thread, because the callback is run + // on the invoking thread. (Of course the bound variable must + // survive until the callback is called.) + [&result](int i){ result = i; }); + // this should post the callback to main + qptr->runOne(); + // this should run the callback + main.runOne(); + ensure_equals("failed to run int callback", result, 17); + + std::string alpha; + // postTo() handles arbitrary return types + main.postTo( + qptr, + [](){ return "abc"s; }, + [&alpha](const std::string& s){ alpha = s; }); + qptr->runPending(); + main.runPending(); + ensure_equals("failed to run string callback", alpha, "abc"); + } + + template<> template<> + void object::test<5>() + { + set_test_name("postTo with void return"); + WorkQueue main("main"); + auto qptr = WorkQueue::getInstance("queue"); + std::string observe; + main.postTo( + qptr, + // The ONLY reason we can get away with binding a reference to + // 'observe' in our work callable is because we're directly + // calling qptr->runOne() on this same thread. It would be a + // mistake to do that if some other thread were servicing 'queue'. + [&observe](){ observe = "queue"; }, + [&observe](){ observe.append(";main"); }); + qptr->runOne(); + main.runOne(); + ensure_equals("failed to run both lambdas", observe, "queue;main"); + } + + template<> template<> + void object::test<6>() + { + set_test_name("waitForResult"); + std::string stored; + // Try to call waitForResult() on this thread's main coroutine. It + // should throw because the main coroutine must service the queue. + auto what{ catch_what<WorkQueue::Error>( + [this, &stored](){ stored = queue.waitForResult( + [](){ return "should throw"; }); }) }; + ensure("lambda should not have run", stored.empty()); + ensure_not("waitForResult() should have thrown", what.empty()); + ensure(STRINGIZE("should mention waitForResult: " << what), + what.find("waitForResult") != std::string::npos); + + // Call waitForResult() on a coroutine, with a string result. + LLCoros::instance().launch( + "waitForResult string", + [this, &stored]() + { stored = queue.waitForResult( + [](){ return "string result"; }); }); + llcoro::suspend(); + // Nothing will have happened yet because, even if the coroutine did + // run immediately, all it did was to queue the inner lambda on + // 'queue'. Service it. + queue.runOne(); + llcoro::suspend(); + ensure_equals("bad waitForResult return", stored, "string result"); + + // Call waitForResult() on a coroutine, with a void callable. + stored.clear(); + bool done = false; + LLCoros::instance().launch( + "waitForResult void", + [this, &stored, &done]() + { + queue.waitForResult([&stored](){ stored = "ran"; }); + done = true; + }); + llcoro::suspend(); + queue.runOne(); + llcoro::suspend(); + ensure_equals("didn't run coroutine", stored, "ran"); + ensure("void waitForResult() didn't return", done); + } +} // namespace tut diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp new file mode 100644 index 0000000000..ba914035e2 --- /dev/null +++ b/indra/llcommon/threadpool.cpp @@ -0,0 +1,88 @@ +/** + * @file threadpool.cpp + * @author Nat Goodspeed + * @date 2021-10-21 + * @brief Implementation for threadpool. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "threadpool.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llerror.h" +#include "llevents.h" +#include "stringize.h" + +LL::ThreadPool::ThreadPool(const std::string& name, size_t threads, size_t capacity): + mQueue(name, capacity), + mName("ThreadPool:" + name), + mThreadCount(threads) +{} + +void LL::ThreadPool::start() +{ + for (size_t i = 0; i < mThreadCount; ++i) + { + std::string tname{ stringize(mName, ':', (i+1), '/', mThreadCount) }; + mThreads.emplace_back(tname, [this, tname]() + { + LL_PROFILER_SET_THREAD_NAME(tname.c_str()); + run(tname); + }); + } + // Listen on "LLApp", and when the app is shutting down, close the queue + // and join the workers. + LLEventPumps::instance().obtain("LLApp").listen( + mName, + [this](const LLSD& stat) + { + std::string status(stat["status"]); + if (status != "running") + { + // viewer is starting shutdown -- proclaim the end is nigh! + LL_DEBUGS("ThreadPool") << mName << " saw " << status << LL_ENDL; + close(); + } + return false; + }); +} + +LL::ThreadPool::~ThreadPool() +{ + close(); +} + +void LL::ThreadPool::close() +{ + if (! mQueue.isClosed()) + { + LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL; + mQueue.close(); + for (auto& pair: mThreads) + { + LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL; + pair.second.join(); + } + LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL; + } +} + +void LL::ThreadPool::run(const std::string& name) +{ + LL_DEBUGS("ThreadPool") << name << " starting" << LL_ENDL; + run(); + LL_DEBUGS("ThreadPool") << name << " stopping" << LL_ENDL; +} + +void LL::ThreadPool::run() +{ + mQueue.runUntilClose(); +} diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h new file mode 100644 index 0000000000..b79c9b9090 --- /dev/null +++ b/indra/llcommon/threadpool.h @@ -0,0 +1,71 @@ +/** + * @file threadpool.h + * @author Nat Goodspeed + * @date 2021-10-21 + * @brief ThreadPool configures a WorkQueue along with a pool of threads to + * service it. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_THREADPOOL_H) +#define LL_THREADPOOL_H + +#include "workqueue.h" +#include <string> +#include <thread> +#include <utility> // std::pair +#include <vector> + +namespace LL +{ + + class ThreadPool + { + public: + /** + * Pass ThreadPool a string name. This can be used to look up the + * relevant WorkQueue. + */ + ThreadPool(const std::string& name, size_t threads=1, size_t capacity=1024); + virtual ~ThreadPool(); + + /** + * Launch the ThreadPool. Until this call, a constructed ThreadPool + * launches no threads. That permits coders to derive from ThreadPool, + * or store it as a member of some other class, but refrain from + * launching it until all other construction is complete. + */ + void start(); + + /** + * ThreadPool listens for application shutdown messages on the "LLApp" + * LLEventPump. Call close() to shut down this ThreadPool early. + */ + void close(); + + std::string getName() const { return mName; } + size_t getWidth() const { return mThreads.size(); } + /// obtain a non-const reference to the WorkQueue to post work to it + WorkQueue& getQueue() { return mQueue; } + + /** + * Override run() if you need special processing. The default run() + * implementation simply calls WorkQueue::runUntilClose(). + */ + virtual void run(); + + private: + void run(const std::string& name); + + WorkQueue mQueue; + std::string mName; + size_t mThreadCount; + std::vector<std::pair<std::string, std::thread>> mThreads; + }; + +} // namespace LL + +#endif /* ! defined(LL_THREADPOOL_H) */ diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h new file mode 100644 index 0000000000..3e0da94c02 --- /dev/null +++ b/indra/llcommon/threadsafeschedule.h @@ -0,0 +1,399 @@ +/** + * @file threadsafeschedule.h + * @author Nat Goodspeed + * @date 2021-10-02 + * @brief ThreadSafeSchedule is an ordered queue in which every item has an + * associated timestamp. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_THREADSAFESCHEDULE_H) +#define LL_THREADSAFESCHEDULE_H + +#include "chrono.h" +#include "llexception.h" +#include "llthreadsafequeue.h" +#include "tuple.h" +#include <chrono> +#include <tuple> + +namespace LL +{ + namespace ThreadSafeSchedulePrivate + { + using TimePoint = std::chrono::steady_clock::time_point; + // Bundle consumer's data with a TimePoint to order items by timestamp. + template <typename... Args> + using TimestampedTuple = std::tuple<TimePoint, Args...>; + + // comparison functor for TimedTuples -- see TimedQueue comments + struct ReverseTupleOrder + { + template <typename Tuple> + bool operator()(const Tuple& left, const Tuple& right) const + { + return std::get<0>(left) > std::get<0>(right); + } + }; + + template <typename... Args> + using TimedQueue = PriorityQueueAdapter< + TimestampedTuple<Args...>, + // std::vector is the default storage for std::priority_queue, + // have to restate to specify comparison template parameter + std::vector<TimestampedTuple<Args...>>, + // std::priority_queue uses a counterintuitive comparison + // behavior: the default std::less comparator is used to present + // the *highest* value as top(). So to sort by earliest timestamp, + // we must invert by using >. + ReverseTupleOrder>; + } // namespace ThreadSafeSchedulePrivate + + /** + * ThreadSafeSchedule is an ordered LLThreadSafeQueue in which every item + * is given an associated timestamp. That is, TimePoint is implicitly + * prepended to the std::tuple with the specified types. + * + * Items are popped in increasing chronological order. Moreover, any item + * with a timestamp in the future is held back until + * std::chrono::steady_clock reaches that timestamp. + */ + template <typename... Args> + class ThreadSafeSchedule: + public LLThreadSafeQueue<ThreadSafeSchedulePrivate::TimestampedTuple<Args...>, + ThreadSafeSchedulePrivate::TimedQueue<Args...>> + { + public: + using DataTuple = std::tuple<Args...>; + using TimeTuple = ThreadSafeSchedulePrivate::TimestampedTuple<Args...>; + + private: + using super = LLThreadSafeQueue<TimeTuple, ThreadSafeSchedulePrivate::TimedQueue<Args...>>; + using lock_t = typename super::lock_t; + // VS 2017 needs this due to a bug: + // https://developercommunity.visualstudio.com/t/cannot-access-protected-enumerator-of-enclosing-cl/203430 + enum pop_result { EMPTY=super::EMPTY, DONE=super::DONE, WAITING=super::WAITING, POPPED=super::POPPED }; + + public: + using Closed = LLThreadSafeQueueInterrupt; + using TimePoint = ThreadSafeSchedulePrivate::TimePoint; + using Clock = TimePoint::clock; + + ThreadSafeSchedule(U32 capacity=1024): + super(capacity) + {} + + /*----------------------------- push() -----------------------------*/ + /// explicitly pass TimeTuple + using super::push; + + /// pass DataTuple with implicit now + // This could be ambiguous for Args with a single type. Unfortunately + // we can't enable_if an individual method with a condition based on + // the *class* template arguments, only on that method's template + // arguments. We could specialize this class for the single-Args case; + // we could minimize redundancy by breaking out a common base class... + void push(const DataTuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + push(tuple_cons(Clock::now(), tuple)); + } + + /// individually pass each component of the TimeTuple + void push(const TimePoint& time, Args&&... args) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + push(TimeTuple(time, std::forward<Args>(args)...)); + } + + /// individually pass every component except the TimePoint (implies now) + // This could be ambiguous if the first specified template parameter + // type is also TimePoint. We could try to disambiguate, but a simpler + // approach would be for the caller to explicitly construct DataTuple + // and call that overload. + void push(Args&&... args) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + push(Clock::now(), std::forward<Args>(args)...); + } + + /*--------------------------- tryPush() ----------------------------*/ + /// explicit TimeTuple + using super::tryPush; + + /// DataTuple with implicit now + bool tryPush(const DataTuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPush(tuple_cons(Clock::now(), tuple)); + } + + /// individually pass components + bool tryPush(const TimePoint& time, Args&&... args) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPush(TimeTuple(time, std::forward<Args>(args)...)); + } + + /// individually pass components with implicit now + bool tryPush(Args&&... args) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPush(Clock::now(), std::forward<Args>(args)...); + } + + /*-------------------------- tryPushFor() --------------------------*/ + /// explicit TimeTuple + using super::tryPushFor; + + /// DataTuple with implicit now + template <typename Rep, typename Period> + bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout, + const DataTuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPushFor(timeout, tuple_cons(Clock::now(), tuple)); + } + + /// individually pass components + template <typename Rep, typename Period> + bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout, + const TimePoint& time, Args&&... args) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPushFor(TimeTuple(time, std::forward<Args>(args)...)); + } + + /// individually pass components with implicit now + template <typename Rep, typename Period> + bool tryPushFor(const std::chrono::duration<Rep, Period>& timeout, + Args&&... args) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPushFor(Clock::now(), std::forward<Args>(args)...); + } + + /*------------------------- tryPushUntil() -------------------------*/ + /// explicit TimeTuple + using super::tryPushUntil; + + /// DataTuple with implicit now + template <typename Clock, typename Duration> + bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until, + const DataTuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPushUntil(until, tuple_cons(Clock::now(), tuple)); + } + + /// individually pass components + template <typename Clock, typename Duration> + bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until, + const TimePoint& time, Args&&... args) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPushUntil(until, TimeTuple(time, std::forward<Args>(args)...)); + } + + /// individually pass components with implicit now + template <typename Clock, typename Duration> + bool tryPushUntil(const std::chrono::time_point<Clock, Duration>& until, + Args&&... args) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tryPushUntil(until, Clock::now(), std::forward<Args>(args)...); + } + + /*----------------------------- pop() ------------------------------*/ + // Our consumer may or may not care about the timestamp associated + // with each popped item, so we allow retrieving either DataTuple or + // TimeTuple. One potential use would be to observe, and possibly + // adjust for, the time lag between the item time and the actual + // current time. + + /// pop DataTuple by value + // It would be great to notice when sizeof...(Args) == 1 and directly + // return the first (only) value, instead of making pop()'s caller + // call std::get<0>(value). See push(DataTuple) remarks for why we + // haven't yet jumped through those hoops. + DataTuple pop() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + return tuple_cdr(popWithTime()); + } + + /// pop TimeTuple by value + TimeTuple popWithTime() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + lock_t lock(super::mLock); + // We can't just sit around waiting forever, given that there may + // be items in the queue that are not yet ready but will *become* + // ready in the near future. So in fact, with this class, every + // pop() becomes a tryPopUntil(), constrained to the timestamp of + // the head item. It almost doesn't matter what we specify for the + // caller's time constraint -- all we really care about is the + // head item's timestamp. Since pop() and popWithTime() are + // defined to wait until either an item becomes available or the + // queue is closed, loop until one of those things happens. The + // constraint we pass just determines how often we'll loop while + // waiting. + TimeTuple tt; + while (true) + { + // Pick a point suitably far into the future. + TimePoint until = TimePoint::clock::now() + std::chrono::hours(24); + pop_result popped = tryPopUntil_(lock, until, tt); + if (popped == POPPED) + return std::move(tt); + + // DONE: throw, just as super::pop() does + if (popped == DONE) + { + LLTHROW(LLThreadSafeQueueInterrupt()); + } + // WAITING: we've still got items to drain. + // EMPTY: not closed, so it's worth waiting for more items. + // Either way, loop back to wait. + } + } + + // We can use tryPop(TimeTuple&) just as it stands; the only behavior + // difference is in our canPop() override method. + using super::tryPop; + + /// tryPop(DataTuple&) + bool tryPop(DataTuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + TimeTuple tt; + if (! super::tryPop(tt)) + return false; + tuple = tuple_cdr(std::move(tt)); + return true; + } + + /// for when Args has exactly one type + bool tryPop(typename std::tuple_element<1, TimeTuple>::type& value) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + TimeTuple tt; + if (! super::tryPop(tt)) + return false; + value = std::get<1>(std::move(tt)); + return true; + } + + /// tryPopFor() + template <typename Rep, typename Period, typename Tuple> + bool tryPopFor(const std::chrono::duration<Rep, Period>& timeout, Tuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + // It's important to use OUR tryPopUntil() implementation, rather + // than delegating immediately to our base class. + return tryPopUntil(Clock::now() + timeout, tuple); + } + + /// tryPopUntil(TimeTuple&) + template <typename Clock, typename Duration> + bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until, + TimeTuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + // super::tryPopUntil() wakes up when an item becomes available or + // we hit 'until', whichever comes first. Thing is, the current + // head of the queue could become ready sooner than either of + // those events, and we need to deliver it as soon as it does. + // Don't wait past the TimePoint of the head item. + // Naturally, lock the queue before peeking at mStorage. + return super::tryLockUntil( + until, + [this, until, &tuple](lock_t& lock) + { + // Use our time_point_cast to allow for 'until' that's a + // time_point type other than TimePoint. + return POPPED == + tryPopUntil_(lock, LL::time_point_cast<TimePoint>(until), tuple); + }); + } + + pop_result tryPopUntil_(lock_t& lock, const TimePoint& until, TimeTuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + TimePoint adjusted = until; + if (! super::mStorage.empty()) + { + LL_PROFILE_ZONE_NAMED("tpu - adjust"); + // use whichever is earlier: the head item's timestamp, or + // the caller's limit + adjusted = min(std::get<0>(super::mStorage.front()), adjusted); + } + // now delegate to base-class tryPopUntil_() + pop_result popped; + { + LL_PROFILE_ZONE_NAMED("tpu - super"); + while ((popped = pop_result(super::tryPopUntil_(lock, adjusted, tuple))) == WAITING) + { + // If super::tryPopUntil_() returns WAITING, it means there's + // a head item, but it's not yet time. But it's worth looping + // back to recheck. + } + } + return popped; + } + + /// tryPopUntil(DataTuple&) + template <typename Clock, typename Duration> + bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until, + DataTuple& tuple) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + TimeTuple tt; + if (! tryPopUntil(until, tt)) + return false; + tuple = tuple_cdr(std::move(tt)); + return true; + } + + /// for when Args has exactly one type + template <typename Clock, typename Duration> + bool tryPopUntil(const std::chrono::time_point<Clock, Duration>& until, + typename std::tuple_element<1, TimeTuple>::type& value) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + TimeTuple tt; + if (! tryPopUntil(until, tt)) + return false; + value = std::get<1>(std::move(tt)); + return true; + } + + /*------------------------------ etc. ------------------------------*/ + // We can't hide items that aren't yet ready because we can't traverse + // the underlying priority_queue: it has no iterators, only top(). So + // a consumer could observe size() > 0 and yet tryPop() returns false. + // Shrug, in a multi-consumer scenario that would be expected behavior. + using super::size; + // open/closed state + using super::close; + using super::isClosed; + using super::done; + + private: + // this method is called by base class pop_() every time we're + // considering whether to deliver the current head element + bool canPop(const TimeTuple& head) const override + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + // an item with a future timestamp isn't yet ready to pop + // (should we add some slop for overhead?) + return std::get<0>(head) <= Clock::now(); + } + }; + +} // namespace LL + +#endif /* ! defined(LL_THREADSAFESCHEDULE_H) */ diff --git a/indra/llcommon/tuple.h b/indra/llcommon/tuple.h new file mode 100644 index 0000000000..bfe7e3c2ba --- /dev/null +++ b/indra/llcommon/tuple.h @@ -0,0 +1,84 @@ +/** + * @file tuple.h + * @author Nat Goodspeed + * @date 2021-10-04 + * @brief A couple tuple utilities + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_TUPLE_H) +#define LL_TUPLE_H + +#include <tuple> +#include <type_traits> // std::remove_reference +#include <utility> // std::pair + +/** + * tuple_cons() behaves like LISP cons: it uses std::tuple_cat() to prepend a + * new item of arbitrary type to an existing std::tuple. + */ +template <typename First, typename... Rest, typename Tuple_=std::tuple<Rest...>> +auto tuple_cons(First&& first, Tuple_&& rest) +{ + // All we need to do is make a tuple containing 'first', and let + // tuple_cat() do the hard part. + return std::tuple_cat(std::tuple<First>(std::forward<First>(first)), + std::forward<Tuple_>(rest)); +} + +/** + * tuple_car() behaves like LISP car: it extracts the first item from a + * std::tuple. + */ +template <typename... Args, typename Tuple_=std::tuple<Args...>> +auto tuple_car(Tuple_&& tuple) +{ + return std::get<0>(std::forward<Tuple_>(tuple)); +} + +/** + * tuple_cdr() behaves like LISP cdr: it returns a new tuple containing + * everything BUT the first item. + */ +// derived from https://stackoverflow.com/a/24046437 +template <typename Tuple, std::size_t... Indices> +auto tuple_cdr_(Tuple&& tuple, const std::index_sequence<Indices...>) +{ + // Given an index sequence from [0..N-1), extract tuple items [1..N) + return std::make_tuple(std::get<Indices+1u>(std::forward<Tuple>(tuple))...); +} + +template <typename Tuple> +auto tuple_cdr(Tuple&& tuple) +{ + return tuple_cdr_( + std::forward<Tuple>(tuple), + // Pass helper function an index sequence one item shorter than tuple + std::make_index_sequence< + std::tuple_size< + // tuple_size doesn't like reference types + typename std::remove_reference<Tuple>::type + >::value - 1u> + ()); +} + +/** + * tuple_split(), the opposite of tuple_cons(), has no direct analog in LISP. + * It returns a std::pair of tuple_car(), tuple_cdr(). We could call this + * function tuple_car_cdr(), or tuple_slice() or some such. But tuple_split() + * feels more descriptive. + */ +template <typename... Args, typename Tuple_=std::tuple<Args...>> +auto tuple_split(Tuple_&& tuple) +{ + // We're not really worried about forwarding multiple times a tuple that + // might contain move-only items, because the implementation above only + // applies std::get() exactly once to each item. + return std::make_pair(tuple_car(std::forward<Tuple_>(tuple)), + tuple_cdr(std::forward<Tuple_>(tuple))); +} + +#endif /* ! defined(LL_TUPLE_H) */ diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp new file mode 100644 index 0000000000..eb06890468 --- /dev/null +++ b/indra/llcommon/workqueue.cpp @@ -0,0 +1,158 @@ +/** + * @file workqueue.cpp + * @author Nat Goodspeed + * @date 2021-10-06 + * @brief Implementation for WorkQueue. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "workqueue.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llcoros.h" +#include LLCOROS_MUTEX_HEADER +#include "llerror.h" +#include "llexception.h" +#include "stringize.h" + +using Mutex = LLCoros::Mutex; +using Lock = LLCoros::LockType; + +LL::WorkQueue::WorkQueue(const std::string& name, size_t capacity): + super(makeName(name)), + mQueue(capacity) +{ + // TODO: register for "LLApp" events so we can implicitly close() on + // viewer shutdown. +} + +void LL::WorkQueue::close() +{ + mQueue.close(); +} + +size_t LL::WorkQueue::size() +{ + return mQueue.size(); +} + +bool LL::WorkQueue::isClosed() +{ + return mQueue.isClosed(); +} + +bool LL::WorkQueue::done() +{ + return mQueue.done(); +} + +void LL::WorkQueue::runUntilClose() +{ + try + { + for (;;) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + callWork(mQueue.pop()); + } + } + catch (const Queue::Closed&) + { + } +} + +bool LL::WorkQueue::runPending() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + for (Work work; mQueue.tryPop(work); ) + { + callWork(work); + } + return ! mQueue.done(); +} + +bool LL::WorkQueue::runOne() +{ + Work work; + if (mQueue.tryPop(work)) + { + callWork(work); + } + return ! mQueue.done(); +} + +bool LL::WorkQueue::runUntil(const TimePoint& until) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + // Should we subtract some slop to allow for typical Work execution time? + // How much slop? + // runUntil() is simply a time-bounded runPending(). + for (Work work; TimePoint::clock::now() < until && mQueue.tryPop(work); ) + { + callWork(work); + } + return ! mQueue.done(); +} + +std::string LL::WorkQueue::makeName(const std::string& name) +{ + if (! name.empty()) + return name; + + static U32 discriminator = 0; + static Mutex mutex; + U32 num; + { + // Protect discriminator from concurrent access by different threads. + // It can't be thread_local, else two racing threads will come up with + // the same name. + Lock lk(mutex); + num = discriminator++; + } + return STRINGIZE("WorkQueue" << num); +} + +void LL::WorkQueue::callWork(const Queue::DataTuple& work) +{ + // ThreadSafeSchedule::pop() always delivers a tuple, even when + // there's only one data field per item, as for us. + callWork(std::get<0>(work)); +} + +void LL::WorkQueue::callWork(const Work& work) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; + try + { + work(); + } + catch (...) + { + // No matter what goes wrong with any individual work item, the worker + // thread must go on! Log our own instance name with the exception. + LOG_UNHANDLED_EXCEPTION(getKey()); + } +} + +void LL::WorkQueue::error(const std::string& msg) +{ + LL_ERRS("WorkQueue") << msg << LL_ENDL; +} + +void LL::WorkQueue::checkCoroutine(const std::string& method) +{ + // By convention, the default coroutine on each thread has an empty name + // string. See also LLCoros::logname(). + if (LLCoros::getName().empty()) + { + LLTHROW(Error("Do not call " + method + " from a thread's default coroutine")); + } +} diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h new file mode 100644 index 0000000000..96574a18b9 --- /dev/null +++ b/indra/llcommon/workqueue.h @@ -0,0 +1,574 @@ +/** + * @file workqueue.h + * @author Nat Goodspeed + * @date 2021-09-30 + * @brief Queue used for inter-thread work passing. + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Copyright (c) 2021, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_WORKQUEUE_H) +#define LL_WORKQUEUE_H + +#include "llcoros.h" +#include "llexception.h" +#include "llinstancetracker.h" +#include "threadsafeschedule.h" +#include <chrono> +#include <exception> // std::current_exception +#include <functional> // std::function +#include <string> + +namespace LL +{ + /** + * A typical WorkQueue has a string name that can be used to find it. + */ + class WorkQueue: public LLInstanceTracker<WorkQueue, std::string> + { + private: + using super = LLInstanceTracker<WorkQueue, std::string>; + + public: + using Work = std::function<void()>; + + private: + using Queue = ThreadSafeSchedule<Work>; + // helper for postEvery() + template <typename Rep, typename Period, typename CALLABLE> + class BackJack; + + public: + using TimePoint = Queue::TimePoint; + using TimedWork = Queue::TimeTuple; + using Closed = Queue::Closed; + + struct Error: public LLException + { + Error(const std::string& what): LLException(what) {} + }; + + /** + * You may omit the WorkQueue name, in which case a unique name is + * synthesized; for practical purposes that makes it anonymous. + */ + WorkQueue(const std::string& name = std::string(), size_t capacity=1024); + + /** + * Since the point of WorkQueue is to pass work to some other worker + * thread(s) asynchronously, it's important that the WorkQueue continue + * to exist until the worker thread(s) have drained it. To communicate + * that it's time for them to quit, close() the queue. + */ + void close(); + + /** + * WorkQueue supports multiple producers and multiple consumers. In + * the general case it's misleading to test size(), since any other + * thread might change it the nanosecond the lock is released. On that + * basis, some might argue against publishing a size() method at all. + * + * But there are two specific cases in which a test based on size() + * might be reasonable: + * + * * If you're the only producer, noticing that size() == 0 is + * meaningful. + * * If you're the only consumer, noticing that size() > 0 is + * meaningful. + */ + size_t size(); + /// producer end: are we prevented from pushing any additional items? + bool isClosed(); + /// consumer end: are we done, is the queue entirely drained? + bool done(); + + /*---------------------- fire and forget API -----------------------*/ + + /// fire-and-forget, but at a particular (future?) time + template <typename CALLABLE> + void post(const TimePoint& time, CALLABLE&& callable) + { + // Defer reifying an arbitrary CALLABLE until we hit this or + // postIfOpen(). All other methods should accept CALLABLEs of + // arbitrary type to avoid multiple levels of std::function + // indirection. + mQueue.push(TimedWork(time, std::move(callable))); + } + + /// fire-and-forget + template <typename CALLABLE> + void post(CALLABLE&& callable) + { + // We use TimePoint::clock::now() instead of TimePoint's + // representation of the epoch because this WorkQueue may contain + // a mix of past-due TimedWork items and TimedWork items scheduled + // for the future. Sift this new item into the correct place. + post(TimePoint::clock::now(), std::move(callable)); + } + + /** + * post work for a particular time, unless the queue is closed before + * we can post + */ + template <typename CALLABLE> + bool postIfOpen(const TimePoint& time, CALLABLE&& callable) + { + // Defer reifying an arbitrary CALLABLE until we hit this or + // post(). All other methods should accept CALLABLEs of arbitrary + // type to avoid multiple levels of std::function indirection. + return mQueue.pushIfOpen(TimedWork(time, std::move(callable))); + } + + /** + * post work, unless the queue is closed before we can post + */ + template <typename CALLABLE> + bool postIfOpen(CALLABLE&& callable) + { + return postIfOpen(TimePoint::clock::now(), std::move(callable)); + } + + /** + * Post work to be run at a specified time to another WorkQueue, which + * may or may not still exist and be open. Return true if we were able + * to post. + */ + template <typename CALLABLE> + static bool postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable); + + /** + * Post work to another WorkQueue, which may or may not still exist + * and be open. Return true if we were able to post. + */ + template <typename CALLABLE> + static bool postMaybe(weak_t target, CALLABLE&& callable) + { + return postMaybe(target, TimePoint::clock::now(), + std::forward<CALLABLE>(callable)); + } + + /** + * Launch a callable returning bool that will trigger repeatedly at + * specified interval, until the callable returns false. + * + * If you need to signal that callable from outside, DO NOT bind a + * reference to a simple bool! That's not thread-safe. Instead, bind + * an LLCond variant, e.g. LLOneShotCond or LLBoolCond. + */ + template <typename Rep, typename Period, typename CALLABLE> + void postEvery(const std::chrono::duration<Rep, Period>& interval, + CALLABLE&& callable); + + template <typename CALLABLE> + bool tryPost(CALLABLE&& callable) + { + return mQueue.tryPush(TimedWork(TimePoint::clock::now(), std::move(callable))); + } + + /*------------------------- handshake API --------------------------*/ + + /** + * Post work to another WorkQueue to be run at a specified time, + * requesting a specific callback to be run on this WorkQueue on + * completion. + * + * Returns true if able to post, false if the other WorkQueue is + * inaccessible. + */ + // Apparently some Microsoft header file defines a macro CALLBACK? The + // natural template argument name CALLBACK produces very weird Visual + // Studio compile errors that seem utterly unrelated to this source + // code. + template <typename CALLABLE, typename FOLLOWUP> + bool postTo(weak_t target, + const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback); + + /** + * Post work to another WorkQueue, requesting a specific callback to + * be run on this WorkQueue on completion. + * + * Returns true if able to post, false if the other WorkQueue is + * inaccessible. + */ + template <typename CALLABLE, typename FOLLOWUP> + bool postTo(weak_t target, CALLABLE&& callable, FOLLOWUP&& callback) + { + return postTo(target, TimePoint::clock::now(), + std::move(callable), std::move(callback)); + } + + /** + * Post work to another WorkQueue to be run at a specified time, + * blocking the calling coroutine until then, returning the result to + * caller on completion. + * + * In general, we assume that each thread's default coroutine is busy + * servicing its WorkQueue or whatever. To try to prevent mistakes, we + * forbid calling waitForResult() from a thread's default coroutine. + */ + template <typename CALLABLE> + auto waitForResult(const TimePoint& time, CALLABLE&& callable); + + /** + * Post work to another WorkQueue, blocking the calling coroutine + * until then, returning the result to caller on completion. + * + * In general, we assume that each thread's default coroutine is busy + * servicing its WorkQueue or whatever. To try to prevent mistakes, we + * forbid calling waitForResult() from a thread's default coroutine. + */ + template <typename CALLABLE> + auto waitForResult(CALLABLE&& callable) + { + return waitForResult(TimePoint::clock::now(), std::move(callable)); + } + + /*--------------------------- worker API ---------------------------*/ + + /** + * runUntilClose() pulls TimedWork items off this WorkQueue until the + * queue is closed, at which point it returns. This would be the + * typical entry point for a simple worker thread. + */ + void runUntilClose(); + + /** + * runPending() runs all TimedWork items that are ready to run. It + * returns true if the queue remains open, false if the queue has been + * closed. This could be used by a thread whose primary purpose is to + * serve the queue, but also wants to do other things with its idle time. + */ + bool runPending(); + + /** + * runOne() runs at most one ready TimedWork item -- zero if none are + * ready. It returns true if the queue remains open, false if the + * queue has been closed. + */ + bool runOne(); + + /** + * runFor() runs a subset of ready TimedWork items, until the + * timeslice has been exceeded. It returns true if the queue remains + * open, false if the queue has been closed. This could be used by a + * busy main thread to lend a bounded few CPU cycles to this WorkQueue + * without risking the WorkQueue blowing out the length of any one + * frame. + */ + template <typename Rep, typename Period> + bool runFor(const std::chrono::duration<Rep, Period>& timeslice) + { + LL_PROFILE_ZONE_SCOPED; + return runUntil(TimePoint::clock::now() + timeslice); + } + + /** + * runUntil() is just like runFor(), only with a specific end time + * instead of a timeslice duration. + */ + bool runUntil(const TimePoint& until); + + private: + template <typename CALLABLE, typename FOLLOWUP> + static auto makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback); + /// general case: arbitrary C++ return type + template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE> + struct MakeReplyLambda; + /// specialize for CALLABLE returning void + template <typename CALLABLE, typename FOLLOWUP> + struct MakeReplyLambda<CALLABLE, FOLLOWUP, void>; + + /// general case: arbitrary C++ return type + template <typename CALLABLE, typename RETURNTYPE> + struct WaitForResult; + /// specialize for CALLABLE returning void + template <typename CALLABLE> + struct WaitForResult<CALLABLE, void>; + + static void checkCoroutine(const std::string& method); + static void error(const std::string& msg); + static std::string makeName(const std::string& name); + void callWork(const Queue::DataTuple& work); + void callWork(const Work& work); + Queue mQueue; + }; + + /** + * BackJack is, in effect, a hand-rolled lambda, binding a WorkQueue, a + * CALLABLE that returns bool, a TimePoint and an interval at which to + * relaunch it. As long as the callable continues returning true, BackJack + * keeps resubmitting it to the target WorkQueue. + */ + // Why is BackJack a class and not a lambda? Because, unlike a lambda, a + // class method gets its own 'this' pointer -- which we need to resubmit + // the whole BackJack callable. + template <typename Rep, typename Period, typename CALLABLE> + class WorkQueue::BackJack + { + public: + // bind the desired data + BackJack(weak_t target, + const TimePoint& start, + const std::chrono::duration<Rep, Period>& interval, + CALLABLE&& callable): + mTarget(target), + mStart(start), + mInterval(interval), + mCallable(std::move(callable)) + {} + + // Call by target WorkQueue -- note that although WE require a + // callable returning bool, WorkQueue wants a void callable. We + // consume the bool. + void operator()() + { + // If mCallable() throws an exception, don't catch it here: if it + // throws once, it's likely to throw every time, so it's a waste + // of time to arrange to call it again. + if (mCallable()) + { + // Modify mStart to the new start time we desire. If we simply + // added mInterval to now, we'd get actual timings of + // (mInterval + slop), where 'slop' is the latency between the + // previous mStart and the WorkQueue actually calling us. + // Instead, add mInterval to mStart so that at least we + // register our intent to fire at exact mIntervals. + mStart += mInterval; + + // We're being called at this moment by the target WorkQueue. + // Assume it still exists, rather than checking the result of + // lock(). + // Resubmit the whole *this callable: that's why we're a class + // rather than a lambda. Allow moving *this so we can carry a + // move-only callable; but naturally this statement must be + // the last time we reference this instance, which may become + // moved-from. + try + { + mTarget.lock()->post(mStart, std::move(*this)); + } + catch (const Closed&) + { + // Once this queue is closed, oh well, just stop + } + } + } + + private: + weak_t mTarget; + TimePoint mStart; + std::chrono::duration<Rep, Period> mInterval; + CALLABLE mCallable; + }; + + template <typename Rep, typename Period, typename CALLABLE> + void WorkQueue::postEvery(const std::chrono::duration<Rep, Period>& interval, + CALLABLE&& callable) + { + if (interval.count() <= 0) + { + // It's essential that postEvery() be called with a positive + // interval, since each call to BackJack posts another instance of + // itself at (start + interval) and we order by target time. A + // zero or negative interval would result in that BackJack + // instance going to the head of the queue every time, immediately + // ready to run. Effectively that would produce an infinite loop, + // a denial of service on this WorkQueue. + error("postEvery(interval) may not be 0"); + } + // Instantiate and post a suitable BackJack, binding a weak_ptr to + // self, the current time, the desired interval and the desired + // callable. + post( + BackJack<Rep, Period, CALLABLE>( + getWeak(), TimePoint::clock::now(), interval, std::move(callable))); + } + + /// general case: arbitrary C++ return type + template <typename CALLABLE, typename FOLLOWUP, typename RETURNTYPE> + struct WorkQueue::MakeReplyLambda + { + auto operator()(CALLABLE&& callable, FOLLOWUP&& callback) + { + // Call the callable in any case -- but to minimize + // copying the result, immediately bind it into the reply + // lambda. The reply lambda also binds the original + // callback, so that when we, the originating WorkQueue, + // finally receive and process the reply lambda, we'll + // call the bound callback with the bound result -- on the + // same thread that originally called postTo(). + return + [result = std::forward<CALLABLE>(callable)(), + callback = std::move(callback)] + () + { callback(std::move(result)); }; + } + }; + + /// specialize for CALLABLE returning void + template <typename CALLABLE, typename FOLLOWUP> + struct WorkQueue::MakeReplyLambda<CALLABLE, FOLLOWUP, void> + { + auto operator()(CALLABLE&& callable, FOLLOWUP&& callback) + { + // Call the callable, which produces no result. + std::forward<CALLABLE>(callable)(); + // Our completion callback is simply the caller's callback. + return std::move(callback); + } + }; + + template <typename CALLABLE, typename FOLLOWUP> + auto WorkQueue::makeReplyLambda(CALLABLE&& callable, FOLLOWUP&& callback) + { + return MakeReplyLambda<CALLABLE, FOLLOWUP, + decltype(std::forward<CALLABLE>(callable)())>() + (std::move(callable), std::move(callback)); + } + + template <typename CALLABLE, typename FOLLOWUP> + bool WorkQueue::postTo(weak_t target, + const TimePoint& time, CALLABLE&& callable, FOLLOWUP&& callback) + { + LL_PROFILE_ZONE_SCOPED; + // We're being asked to post to the WorkQueue at target. + // target is a weak_ptr: have to lock it to check it. + auto tptr = target.lock(); + if (! tptr) + // can't post() if the target WorkQueue has been destroyed + return false; + + // Here we believe target WorkQueue still exists. Post to it a + // lambda that packages our callable, our callback and a weak_ptr + // to this originating WorkQueue. + tptr->post( + time, + [reply = super::getWeak(), + callable = std::move(callable), + callback = std::move(callback)] + () + { + // Use postMaybe() below in case this originating WorkQueue + // has been closed or destroyed. Remember, the outer lambda is + // now running on a thread servicing the target WorkQueue, and + // real time has elapsed since postTo()'s tptr->post() call. + try + { + // Make a reply lambda to repost to THIS WorkQueue. + // Delegate to makeReplyLambda() so we can partially + // specialize on void return. + postMaybe(reply, makeReplyLambda(std::move(callable), std::move(callback))); + } + catch (...) + { + // Either variant of makeReplyLambda() is responsible for + // calling the caller's callable. If that throws, return + // the exception to the originating thread. + postMaybe( + reply, + // Bind the current exception to transport back to the + // originating WorkQueue. Once there, rethrow it. + [exc = std::current_exception()](){ std::rethrow_exception(exc); }); + } + }); + + // looks like we were able to post() + return true; + } + + template <typename CALLABLE> + bool WorkQueue::postMaybe(weak_t target, const TimePoint& time, CALLABLE&& callable) + { + LL_PROFILE_ZONE_SCOPED; + // target is a weak_ptr: have to lock it to check it + auto tptr = target.lock(); + if (tptr) + { + try + { + tptr->post(time, std::forward<CALLABLE>(callable)); + // we were able to post() + return true; + } + catch (const Closed&) + { + // target WorkQueue still exists, but is Closed + } + } + // either target no longer exists, or its WorkQueue is Closed + return false; + } + + /// general case: arbitrary C++ return type + template <typename CALLABLE, typename RETURNTYPE> + struct WorkQueue::WaitForResult + { + auto operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable) + { + LLCoros::Promise<RETURNTYPE> promise; + self->post( + time, + // We dare to bind a reference to Promise because it's + // specifically designed for cross-thread communication. + [&promise, callable = std::move(callable)]() + { + try + { + // call the caller's callable and trigger promise with result + promise.set_value(callable()); + } + catch (...) + { + promise.set_exception(std::current_exception()); + } + }); + auto future{ LLCoros::getFuture(promise) }; + // now, on the calling thread, wait for that result + LLCoros::TempStatus st("waiting for WorkQueue::waitForResult()"); + return future.get(); + } + }; + + /// specialize for CALLABLE returning void + template <typename CALLABLE> + struct WorkQueue::WaitForResult<CALLABLE, void> + { + void operator()(WorkQueue* self, const TimePoint& time, CALLABLE&& callable) + { + LLCoros::Promise<void> promise; + self->post( + time, + // &promise is designed for cross-thread access + [&promise, callable = std::move(callable)]() + { + try + { + callable(); + promise.set_value(); + } + catch (...) + { + promise.set_exception(std::current_exception()); + } + }); + auto future{ LLCoros::getFuture(promise) }; + // block until set_value() + LLCoros::TempStatus st("waiting for void WorkQueue::waitForResult()"); + future.get(); + } + }; + + template <typename CALLABLE> + auto WorkQueue::waitForResult(const TimePoint& time, CALLABLE&& callable) + { + checkCoroutine("waitForResult()"); + // derive callable's return type so we can specialize for void + return WaitForResult<CALLABLE, decltype(std::forward<CALLABLE>(callable)())>() + (this, time, std::forward<CALLABLE>(callable)); + } + +} // namespace LL + +#endif /* ! defined(LL_WORKQUEUE_H) */ diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 8922f46ffe..0fa027c9c3 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -623,8 +623,7 @@ void LLImage::setLastError(const std::string& message) //--------------------------------------------------------------------------- LLImageBase::LLImageBase() -: LLTrace::MemTrackable<LLImageBase>("LLImage"), - mData(NULL), +: mData(NULL), mDataSize(0), mWidth(0), mHeight(0), @@ -673,7 +672,6 @@ void LLImageBase::sanityCheck() void LLImageBase::deleteData() { ll_aligned_free_16(mData); - disclaimMem(mDataSize); mDataSize = 0; mData = NULL; } @@ -731,7 +729,6 @@ U8* LLImageBase::allocateData(S32 size) } } mDataSize = size; - claimMem(mDataSize); return mData; } @@ -752,9 +749,7 @@ U8* LLImageBase::reallocateData(S32 size) ll_aligned_free_16(mData) ; } mData = new_datap; - disclaimMem(mDataSize); mDataSize = size; - claimMem(mDataSize); mBadBufferAllocation = false; return mData; } @@ -865,6 +860,12 @@ U8* LLImageRaw::reallocateData(S32 size) return res; } +void LLImageRaw::releaseData() +{ + LLImageBase::setSize(0, 0, 0); + LLImageBase::setDataAndSize(nullptr, 0); +} + // virtual void LLImageRaw::deleteData() { @@ -883,8 +884,6 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) LLImageBase::setSize(width, height, components) ; LLImageBase::setDataAndSize(data, width * height * components) ; - - sGlobalRawMemory += getDataSize(); } bool LLImageRaw::resize(U16 width, U16 height, S8 components) @@ -2254,9 +2253,7 @@ void LLImageBase::setDataAndSize(U8 *data, S32 size) { ll_assert_aligned(data, 16); mData = data; - disclaimMem(mDataSize); mDataSize = size; - claimMem(mDataSize); } //static diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index f66b1666d7..7a588cfb03 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -112,8 +112,7 @@ protected: // Image base class class LLImageBase -: public LLThreadSafeRefCount, - public LLTrace::MemTrackable<LLImageBase> +: public LLThreadSafeRefCount { protected: virtual ~LLImageBase(); @@ -192,6 +191,12 @@ public: /*virtual*/ void deleteData(); /*virtual*/ U8* allocateData(S32 size = -1); /*virtual*/ U8* reallocateData(S32 size); + + // use in conjunction with "no_copy" constructor to release data pointer before deleting + // so that deletion of this LLImageRaw will not free the memory at the "data" parameter + // provided to "no_copy" constructor + void releaseData(); + bool resize(U16 width, U16 height, S8 components); diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 4bff21610f..e1809dbe59 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -60,7 +60,6 @@ LLImageJ2C::LLImageJ2C() : LLImageFormatted(IMG_CODEC_J2C), mAreaUsedForDataSizeCalcs(0) { mImpl.reset(fallbackCreateLLImageJ2CImpl()); - claimMem(mImpl); // Clear data size table for( S32 i = 0; i <= MAX_DISCARD_LEVEL; i++) diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp index 62638fa16c..32a5472ec8 100644 --- a/indra/llimage/llimagejpeg.cpp +++ b/indra/llimage/llimagejpeg.cpp @@ -393,9 +393,7 @@ boolean LLImageJPEG::encodeEmptyOutputBuffer( j_compress_ptr cinfo ) cinfo->dest->next_output_byte = self->mOutputBuffer + self->mOutputBufferSize; cinfo->dest->free_in_buffer = self->mOutputBufferSize; - self->disclaimMem(self->mOutputBufferSize); self->mOutputBufferSize = new_buffer_size; - self->claimMem(new_buffer_size); return true; } @@ -501,13 +499,10 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) // Allocate a temporary buffer big enough to hold the entire compressed image (and then some) // (Note: we make it bigger in emptyOutputBuffer() if we need to) delete[] mOutputBuffer; - disclaimMem(mOutputBufferSize); mOutputBufferSize = getWidth() * getHeight() * getComponents() + 1024; - claimMem(mOutputBufferSize); mOutputBuffer = new(std::nothrow) U8[ mOutputBufferSize ]; if (mOutputBuffer == NULL) { - disclaimMem(mOutputBufferSize); mOutputBufferSize = 0; setLastError("Failed to allocate output buffer"); return false; @@ -547,7 +542,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) jpeg_destroy_compress(&cinfo); delete[] mOutputBuffer; mOutputBuffer = NULL; - disclaimMem(mOutputBufferSize); mOutputBufferSize = 0; return false; } @@ -650,7 +644,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) // After finish_compress, we can release the temp output buffer. delete[] mOutputBuffer; mOutputBuffer = NULL; - disclaimMem(mOutputBufferSize); mOutputBufferSize = 0; //////////////////////////////////////// @@ -663,7 +656,6 @@ bool LLImageJPEG::encode( const LLImageRaw* raw_image, F32 encode_time ) jpeg_destroy_compress(&cinfo); delete[] mOutputBuffer; mOutputBuffer = NULL; - disclaimMem(mOutputBufferSize); mOutputBufferSize = 0; return false; } diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp index 5f42fba866..0dbb744bcf 100644 --- a/indra/llimage/llimageworker.cpp +++ b/indra/llimage/llimageworker.cpp @@ -48,6 +48,7 @@ LLImageDecodeThread::~LLImageDecodeThread() // virtual S32 LLImageDecodeThread::update(F32 max_time_ms) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLMutexLock lock(mCreationMutex); for (creation_list_t::iterator iter = mCreationList.begin(); iter != mCreationList.end(); ++iter) @@ -71,6 +72,7 @@ S32 LLImageDecodeThread::update(F32 max_time_ms) LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, U32 priority, S32 discard, BOOL needs_aux, Responder* responder) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLMutexLock lock(mCreationMutex); handle_t handle = generateHandle(); mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder)); @@ -118,6 +120,7 @@ LLImageDecodeThread::ImageRequest::~ImageRequest() // Returns true when done, whether or not decode was successful. bool LLImageDecodeThread::ImageRequest::processRequest() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; const F32 decode_time_slice = .1f; bool done = true; if (!mDecodedRaw && mFormattedImage.notNull()) @@ -164,6 +167,7 @@ bool LLImageDecodeThread::ImageRequest::processRequest() void LLImageDecodeThread::ImageRequest::finishRequest(bool completed) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (mResponder.notNull()) { bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux); diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp index 51c5c63556..9011ac615c 100644 --- a/indra/llimage/tests/llimageworker_test.cpp +++ b/indra/llimage/tests/llimageworker_test.cpp @@ -45,8 +45,7 @@ // * A simulator for a class can be implemented here. Please comment and document thoroughly. LLImageBase::LLImageBase() -: LLTrace::MemTrackable<LLImageBase>("LLImageBase"), -mData(NULL), +: mData(NULL), mDataSize(0), mWidth(0), mHeight(0), diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 18bc1b5a91..81261f0767 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -74,20 +74,17 @@ LLInventoryObject::LLInventoryObject(const LLUUID& uuid, const LLUUID& parent_uuid, LLAssetType::EType type, const std::string& name) -: LLTrace::MemTrackable<LLInventoryObject>("LLInventoryObject"), - mUUID(uuid), +: mUUID(uuid), mParentUUID(parent_uuid), mType(type), mName(name), mCreationDate(0) { - claimMem(mName); correctInventoryName(mName); } LLInventoryObject::LLInventoryObject() -: LLTrace::MemTrackable<LLInventoryObject>("LLInventoryObject"), - mType(LLAssetType::AT_NONE), +: mType(LLAssetType::AT_NONE), mCreationDate(0) { } @@ -101,9 +98,7 @@ void LLInventoryObject::copyObject(const LLInventoryObject* other) mUUID = other->mUUID; mParentUUID = other->mParentUUID; mType = other->mType; - disclaimMem(mName); mName = other->mName; - claimMem(mName); } const LLUUID& LLInventoryObject::getUUID() const @@ -156,9 +151,7 @@ void LLInventoryObject::rename(const std::string& n) correctInventoryName(new_name); if( !new_name.empty() && new_name != mName ) { - disclaimMem(mName); mName = new_name; - claimMem(mName); } } @@ -311,7 +304,6 @@ LLInventoryItem::LLInventoryItem(const LLUUID& uuid, LLStringUtil::replaceNonstandardASCII(mDescription, ' '); LLStringUtil::replaceChar(mDescription, '|', ' '); - claimMem(mDescription); mPermissions.initMasks(inv_type); } @@ -344,9 +336,7 @@ void LLInventoryItem::copyItem(const LLInventoryItem* other) copyObject(other); mPermissions = other->mPermissions; mAssetUUID = other->mAssetUUID; - disclaimMem(mDescription); mDescription = other->mDescription; - claimMem(mDescription); mSaleInfo = other->mSaleInfo; mInventoryType = other->mInventoryType; mFlags = other->mFlags; @@ -426,9 +416,7 @@ void LLInventoryItem::setDescription(const std::string& d) LLInventoryItem::correctInventoryDescription(new_desc); if( new_desc != mDescription ) { - disclaimMem(mDescription); mDescription = new_desc; - claimMem(mDescription); } } @@ -708,10 +696,8 @@ BOOL LLInventoryItem::importLegacyStream(std::istream& input_stream) valuestr[0] = '\000'; } - disclaimMem(mDescription); mDescription.assign(valuestr); LLStringUtil::replaceNonstandardASCII(mDescription, ' '); - claimMem(mDescription); /* TODO -- ask Ian about this code const char *donkey = mDescription.c_str(); if (donkey[0] == '|') @@ -840,11 +826,9 @@ void LLInventoryItem::asLLSD( LLSD& sd ) const sd[INV_CREATION_DATE_LABEL] = (S32) mCreationDate; } -LLTrace::BlockTimerStatHandle FTM_INVENTORY_SD_DESERIALIZE("Inventory SD Deserialize"); - bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) { - LL_RECORD_BLOCK_TIME(FTM_INVENTORY_SD_DESERIALIZE); + LL_PROFILE_ZONE_SCOPED; if (is_new) { // If we're adding LLSD to an existing object, need avoid @@ -961,10 +945,8 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd, bool is_new) w = INV_DESC_LABEL; if (sd.has(w)) { - disclaimMem(mDescription); mDescription = sd[w].asString(); LLStringUtil::replaceNonstandardASCII(mDescription, ' '); - claimMem(mDescription); } w = INV_CREATION_DATE_LABEL; if (sd.has(w)) diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 0f336a072f..7d9f9704f1 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -44,7 +44,7 @@ class LLMessageSystem; // Base class for anything in the user's inventory. Handles the common code // between items and categories. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLInventoryObject : public LLRefCount, public LLTrace::MemTrackable<LLInventoryObject> +class LLInventoryObject : public LLRefCount { public: typedef std::list<LLPointer<LLInventoryObject> > object_list_t; diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp index 8a8e2bb340..936b166409 100644 --- a/indra/llinventory/llsettingsbase.cpp +++ b/indra/llinventory/llsettingsbase.cpp @@ -683,6 +683,7 @@ bool LLSettingsBase::Validator::verifyStringLength(LLSD &value, U32, S32 length) //========================================================================= void LLSettingsBlender::update(const LLSettingsBase::BlendFactor& blendf) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; F64 res = setBlendFactor(blendf); llassert(res >= 0.0 && res <= 1.0); (void)res; @@ -713,6 +714,7 @@ F64 LLSettingsBlender::setBlendFactor(const LLSettingsBase::BlendFactor& blendf_ void LLSettingsBlender::triggerComplete() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; if (mTarget) mTarget->replaceSettings(mFinal->getSettings()); LLSettingsBlender::ptr_t hold = shared_from_this(); // prevents this from deleting too soon @@ -725,11 +727,13 @@ const LLSettingsBase::BlendFactor LLSettingsBlenderTimeDelta::MIN_BLEND_DELTA(FL LLSettingsBase::BlendFactor LLSettingsBlenderTimeDelta::calculateBlend(const LLSettingsBase::TrackPosition& spanpos, const LLSettingsBase::TrackPosition& spanlen) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; return LLSettingsBase::BlendFactor(fmod((F64)spanpos, (F64)spanlen) / (F64)spanlen); } bool LLSettingsBlenderTimeDelta::applyTimeDelta(const LLSettingsBase::Seconds& timedelta) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; mTimeSpent += timedelta; if (mTimeSpent > mBlendSpan) diff --git a/indra/llinventory/llsettingsdaycycle.cpp b/indra/llinventory/llsettingsdaycycle.cpp index 2bb03e8391..241826604f 100644 --- a/indra/llinventory/llsettingsdaycycle.cpp +++ b/indra/llinventory/llsettingsdaycycle.cpp @@ -41,9 +41,6 @@ //========================================================================= namespace { - LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment Day"); - LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment Day"); - template<typename T> inline T get_wrapping_distance(T begin, T end) { diff --git a/indra/llinventory/llsettingssky.cpp b/indra/llinventory/llsettingssky.cpp index 1470edbf38..83a92f08d0 100644 --- a/indra/llinventory/llsettingssky.cpp +++ b/indra/llinventory/llsettingssky.cpp @@ -66,11 +66,6 @@ namespace { } } -static LLTrace::BlockTimerStatHandle FTM_BLEND_SKYVALUES("Blending Sky Environment"); -static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_SKYVALUES("Recalculate Sky"); -static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_BODIES("Recalculate Heavenly Bodies"); -static LLTrace::BlockTimerStatHandle FTM_RECALCULATE_LIGHTING("Recalculate Lighting"); - //========================================================================= const std::string LLSettingsSky::SETTING_AMBIENT("ambient"); const std::string LLSettingsSky::SETTING_BLUE_DENSITY("blue_density"); @@ -444,6 +439,7 @@ void LLSettingsSky::replaceWithSky(LLSettingsSky::ptr_t pother) void LLSettingsSky::blend(const LLSettingsBase::ptr_t &end, F64 blendf) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; llassert(getSettingsType() == end->getSettingsType()); LLSettingsSky::ptr_t other = PTR_NAMESPACE::dynamic_pointer_cast<LLSettingsSky>(end); @@ -939,7 +935,7 @@ LLSD LLSettingsSky::translateLegacySettings(const LLSD& legacy) void LLSettingsSky::updateSettings() { - LL_RECORD_BLOCK_TIME(FTM_RECALCULATE_SKYVALUES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; // base class clears dirty flag so as to not trigger recursive update LLSettingsBase::updateSettings(); @@ -1022,6 +1018,7 @@ LLColor3 LLSettingsSky::getLightDiffuse() const LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default_value) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key)) { return LLColor3(mSettings[SETTING_LEGACY_HAZE][key]); @@ -1035,6 +1032,7 @@ LLColor3 LLSettingsSky::getColor(const std::string& key, const LLColor3& default F32 LLSettingsSky::getFloat(const std::string& key, F32 default_value) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; if (mSettings.has(SETTING_LEGACY_HAZE) && mSettings[SETTING_LEGACY_HAZE].has(key)) { return mSettings[SETTING_LEGACY_HAZE][key].asReal(); @@ -1206,11 +1204,19 @@ LLColor3 LLSettingsSky::getLightTransmittance(F32 distance) const return transmittance; } +// SL-16127: getTotalDensity() and getDensityMultiplier() call LLSettingsSky::getColor() and LLSettingsSky::getFloat() respectively which are S-L-O-W +LLColor3 LLSettingsSky::getLightTransmittanceFast( const LLColor3& total_density, const F32 density_multiplier, const F32 distance ) const +{ + // Transparency (-> density) from Beer's law + LLColor3 transmittance = componentExp(total_density * -(density_multiplier * distance)); + return transmittance; +} + // performs soft scale clip and gamma correction ala the shader implementation // scales colors down to 0 - 1 range preserving relative ratios -LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in) const +LLColor3 LLSettingsSky::gammaCorrect(const LLColor3& in,const F32 &gamma) const { - F32 gamma = getGamma(); + //F32 gamma = getGamma(); // SL-16127: Use cached gamma from atmospheric vars LLColor3 v(in); // scale down to 0 to 1 range preserving relative ratio (aka homegenize) diff --git a/indra/llinventory/llsettingssky.h b/indra/llinventory/llsettingssky.h index 4127911643..fa9326f006 100644 --- a/indra/llinventory/llsettingssky.h +++ b/indra/llinventory/llsettingssky.h @@ -252,8 +252,9 @@ public: LLColor3 getLightAttenuation(F32 distance) const; LLColor3 getLightTransmittance(F32 distance) const; + LLColor3 getLightTransmittanceFast(const LLColor3& total_density, const F32 density_multiplier, const F32 distance) const; LLColor3 getTotalDensity() const; - LLColor3 gammaCorrect(const LLColor3& in) const; + LLColor3 gammaCorrect(const LLColor3& in,const F32 &gamma) const; LLColor3 getBlueDensity() const; LLColor3 getBlueHorizon() const; diff --git a/indra/llinventory/llsettingswater.cpp b/indra/llinventory/llsettingswater.cpp index 1ae8d78b22..90f99e8198 100644 --- a/indra/llinventory/llsettingswater.cpp +++ b/indra/llinventory/llsettingswater.cpp @@ -33,14 +33,6 @@ #include "v3colorutil.h" #include "indra_constants.h" -//========================================================================= -namespace -{ - LLTrace::BlockTimerStatHandle FTM_BLEND_WATERVALUES("Blending Water Environment"); - LLTrace::BlockTimerStatHandle FTM_UPDATE_WATERVALUES("Update Water Environment"); -} - -//========================================================================= const std::string LLSettingsWater::SETTING_BLUR_MULTIPLIER("blur_multiplier"); const std::string LLSettingsWater::SETTING_FOG_COLOR("water_fog_color"); const std::string LLSettingsWater::SETTING_FOG_DENSITY("water_fog_density"); diff --git a/indra/llkdu/tests/llimagej2ckdu_test.cpp b/indra/llkdu/tests/llimagej2ckdu_test.cpp index ee7b14be85..16213b7f45 100644 --- a/indra/llkdu/tests/llimagej2ckdu_test.cpp +++ b/indra/llkdu/tests/llimagej2ckdu_test.cpp @@ -63,8 +63,7 @@ U8* LLImageRaw::reallocateData(S32 ) { return NULL; } bool LLImageRaw::resize(U16, U16, S8) { return true; } // this method always returns true... LLImageBase::LLImageBase() -: LLTrace::MemTrackable<LLImageBase>("LLImageBase"), -mData(NULL), +: mData(NULL), mDataSize(0), mWidth(0), mHeight(0), diff --git a/indra/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 7ba347062f..2cf50e9cd2 100644 --- a/indra/llmath/llmatrix4a.h +++ b/indra/llmath/llmatrix4a.h @@ -36,6 +36,26 @@ class LLMatrix4a public: LL_ALIGN_16(LLVector4a mMatrix[4]); + LLMatrix4a() + { + + } + + explicit LLMatrix4a(const LLMatrix4& val) + { + loadu(val); + } + + inline F32* getF32ptr() + { + return (F32*) &mMatrix; + } + + inline const F32* getF32ptr() const + { + return (F32*)&mMatrix; + } + inline void clear() { mMatrix[0].clear(); @@ -44,14 +64,29 @@ public: mMatrix[3].clear(); } + inline void setIdentity() + { + mMatrix[0].set(1.f, 0.f, 0.f, 0.f); + mMatrix[1].set(0.f, 1.f, 0.f, 0.f); + mMatrix[2].set(0.f, 0.f, 1.f, 0.f); + mMatrix[3].set(0.f, 0.f, 0.f, 1.f); + } + inline void loadu(const LLMatrix4& src) { mMatrix[0] = _mm_loadu_ps(src.mMatrix[0]); mMatrix[1] = _mm_loadu_ps(src.mMatrix[1]); mMatrix[2] = _mm_loadu_ps(src.mMatrix[2]); mMatrix[3] = _mm_loadu_ps(src.mMatrix[3]); - } + + inline void loadu(const F32* src) + { + mMatrix[0] = _mm_loadu_ps(src); + mMatrix[1] = _mm_loadu_ps(src+4); + mMatrix[2] = _mm_loadu_ps(src+8); + mMatrix[3] = _mm_loadu_ps(src+12); + } inline void loadu(const LLMatrix3& src) { @@ -105,7 +140,7 @@ public: mMatrix[3].setAdd(a.mMatrix[3],d3); } - inline void rotate(const LLVector4a& v, LLVector4a& res) + inline void rotate(const LLVector4a& v, LLVector4a& res) const { LLVector4a y,z; @@ -151,6 +186,8 @@ public: { affineTransformSSE(v,res); } + + const LLVector4a& getTranslation() const { return mMatrix[3]; } }; inline LLVector4a rowMul(const LLVector4a &row, const LLMatrix4a &mat) @@ -176,6 +213,15 @@ inline void matMul(const LLMatrix4a &a, const LLMatrix4a &b, LLMatrix4a &res) res.mMatrix[3] = row3; } +//Faster version of matMul wehere res must not be a or b +inline void matMulUnsafe(const LLMatrix4a &a, const LLMatrix4a &b, LLMatrix4a &res) +{ + res.mMatrix[0] = rowMul(a.mMatrix[0], b); + res.mMatrix[1] = rowMul(a.mMatrix[1], b); + res.mMatrix[2] = rowMul(a.mMatrix[2], b); + res.mMatrix[3] = rowMul(a.mMatrix[3], b); +} + inline std::ostream& operator<<(std::ostream& s, const LLMatrix4a& m) { s << "[" << m.mMatrix[0] << ", " << m.mMatrix[1] << ", " << m.mMatrix[2] << ", " << m.mMatrix[3] << "]"; diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index 0e2f62f9db..2283df1e1a 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -34,6 +34,9 @@ #define OCT_ERRS LL_WARNS("OctreeErrors") +#define OCTREE_DEBUG_COLOR_REMOVE 0x0000FF // r +#define OCTREE_DEBUG_COLOR_INSERT 0x00FF00 // g +#define OCTREE_DEBUG_COLOR_BALANCE 0xFF0000 // b extern U32 gOctreeMaxCapacity; extern float gOctreeMinSize; @@ -74,8 +77,9 @@ public: }; template <class T> -class LLOctreeNode : public LLTreeNode<T> +class alignas(16) LLOctreeNode : public LLTreeNode<T> { + LL_ALIGN_NEW public: typedef LLOctreeTraveler<T> oct_traveler; @@ -91,20 +95,15 @@ public: typedef LLOctreeNode<T> oct_node; typedef LLOctreeListener<T> oct_listener; - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } + enum + { + NO_CHILD_NODES = 255 // Note: This is an U8 to match the max value in mChildMap[] + }; LLOctreeNode( const LLVector4a& center, const LLVector4a& size, BaseType* parent, - U8 octant = 255) + U8 octant = NO_CHILD_NODES) : mParent((oct_node*)parent), mOctant(octant) { @@ -117,7 +116,7 @@ public: mSize = size; updateMinMax(); - if ((mOctant == 255) && mParent) + if ((mOctant == NO_CHILD_NODES) && mParent) { mOctant = ((oct_node*) mParent)->getOctant(mCenter); } @@ -127,9 +126,9 @@ public: clearChildren(); } - virtual ~LLOctreeNode() + virtual ~LLOctreeNode() { - BaseType::destroyListeners(); + BaseType::destroyListeners(); for (U32 i = 0; i < mElementCount; ++i) { @@ -168,7 +167,7 @@ public: return rad <= mSize[0]*2.f && isInside(pos); } - inline bool isInside(T* data) const + inline bool isInside(T* data) const { return isInside(data->getPositionGroup(), data->getBinRadius()); } @@ -262,7 +261,7 @@ public: for (U32 i = 0; i < 8; i++) { U8 idx = mChildMap[i]; - if (idx != 255) + if (idx != NO_CHILD_NODES) { LLOctreeNode<T>* child = mChild[idx]; @@ -285,7 +284,7 @@ public: LLOctreeNode<T>* node = this; if (node->isInside(pos, rad)) - { + { //do a quick search by octant U8 octant = node->getOctant(pos); @@ -295,7 +294,7 @@ public: // the data U8 next_node = node->mChildMap[octant]; - while (next_node != 255 && node->getSize()[0] >= rad) + while (next_node != NO_CHILD_NODES && node->getSize()[0] >= rad) { node = node->getChild(next_node); octant = node->getOctant(pos); @@ -312,6 +311,8 @@ public: virtual bool insert(T* data) { + //LL_PROFILE_ZONE_NAMED_COLOR("Octree::insert()",OCTREE_DEBUG_COLOR_INSERT); + if (data == NULL || data->getBinIndex() != -1) { OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << LL_ENDL; @@ -458,6 +459,8 @@ public: bool remove(T* data) { + //LL_PROFILE_ZONE_NAMED_COLOR("Octree::remove()", OCTREE_DEBUG_COLOR_REMOVE); + S32 i = data->getBinIndex(); if (i >= 0 && i < mElementCount) @@ -523,9 +526,7 @@ public: void clearChildren() { mChildCount = 0; - - U32* foo = (U32*) mChildMap; - foo[0] = foo[1] = 0xFFFFFFFF; + memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap)); } void validate() @@ -616,11 +617,9 @@ public: --mChildCount; mChild[index] = mChild[mChildCount]; - //rebuild child map - U32* foo = (U32*) mChildMap; - foo[0] = foo[1] = 0xFFFFFFFF; + memset(mChildMap, NO_CHILD_NODES, sizeof(mChildMap)); for (U32 i = 0; i < mChildCount; ++i) { @@ -656,7 +655,7 @@ public: OCT_ERRS << "Octree failed to delete requested child." << LL_ENDL; } -protected: +protected: typedef enum { CENTER = 0, @@ -680,7 +679,6 @@ protected: element_list mData; element_iter mDataEnd; U32 mElementCount; - }; //just like a regular node, except it might expand on insert and compress on balance @@ -689,7 +687,7 @@ class LLOctreeRoot : public LLOctreeNode<T> { public: typedef LLOctreeNode<T> BaseType; - typedef LLOctreeNode<T> oct_node; + typedef LLOctreeNode<T> oct_node; LLOctreeRoot(const LLVector4a& center, const LLVector4a& size, @@ -700,9 +698,11 @@ public: bool balance() { + //LL_PROFILE_ZONE_NAMED_COLOR("Octree::balance()",OCTREE_DEBUG_COLOR_BALANCE); + if (this->getChildCount() == 1 && !(this->mChild[0]->isLeaf()) && - this->mChild[0]->getElementCount() == 0) + this->mChild[0]->getElementCount() == 0) { //if we have only one child and that child is an empty branch, make that child the root oct_node* child = this->mChild[0]; diff --git a/indra/llmath/llrigginginfo.h b/indra/llmath/llrigginginfo.h index b3d6bc2d19..059c6ae082 100644 --- a/indra/llmath/llrigginginfo.h +++ b/indra/llmath/llrigginginfo.h @@ -34,9 +34,9 @@ // Extents are in joint space // isRiggedTo is based on the state of all currently associated rigged meshes -LL_ALIGN_PREFIX(16) -class LLJointRiggingInfo +class alignas(16) LLJointRiggingInfo { + LL_ALIGN_NEW public: LLJointRiggingInfo(); bool isRiggedTo() const; @@ -45,31 +45,10 @@ public: const LLVector4a *getRiggedExtents() const; void merge(const LLJointRiggingInfo& other); - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - - void* operator new[](size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete[](void* ptr) - { - ll_aligned_free_16(ptr); - } - - private: - LL_ALIGN_16(LLVector4a mRiggedExtents[2]); + LLVector4a mRiggedExtents[2]; bool mIsRiggedTo; -} LL_ALIGN_POSTFIX(16); +}; // For storing all the rigging info associated with a given avatar or // object, keyed by joint_num. diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h index 27abf39537..53c8f604f6 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -46,11 +46,10 @@ class LLRotation; // of this writing, July 08, 2010) about getting it implemented before you resort to // LLVector3/LLVector4. ///////////////////////////////// -struct LLVector4a; -LL_ALIGN_PREFIX(16) -struct LLVector4a +class alignas(16) LLVector4a { + LL_ALIGN_NEW public: /////////////////////////////////// @@ -138,10 +137,10 @@ public: // BASIC GET/SET //////////////////////////////////// - // Return a "this" as an F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon) + // Return a "this" as an F32 pointer. inline F32* getF32ptr(); - // Return a "this" as a const F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon) + // Return a "this" as a const F32 pointer. inline const F32* const getF32ptr() const; // Read-only access a single float in this vector. Do not use in proximity to any function call that manipulates @@ -324,7 +323,7 @@ public: private: LLQuad mQ; -} LL_ALIGN_POSTFIX(16); +}; inline void update_min_max(LLVector4a& min, LLVector4a& max, const LLVector4a& p) { diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl index 69d3d01efe..8be1c1b114 100644 --- a/indra/llmath/llvector4a.inl +++ b/indra/llmath/llvector4a.inl @@ -58,13 +58,13 @@ inline void LLVector4a::store4a(F32* dst) const // BASIC GET/SET //////////////////////////////////// -// Return a "this" as an F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon) +// Return a "this" as an F32 pointer. F32* LLVector4a::getF32ptr() { return (F32*) &mQ; } -// Return a "this" as a const F32 pointer. Do not use unless you have a very good reason. (Not sure? Ask Falcon) +// Return a "this" as a const F32 pointer. const F32* const LLVector4a::getF32ptr() const { return (const F32* const) &mQ; diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 411d76adb2..3727ce85af 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -88,7 +88,7 @@ const F32 SKEW_MAX = 0.95f; const F32 SCULPT_MIN_AREA = 0.002f; const S32 SCULPT_MIN_AREA_DETAIL = 1; -BOOL gDebugGL = FALSE; +BOOL gDebugGL = FALSE; // See settings.xml "RenderDebugGL" BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm) { @@ -383,6 +383,7 @@ public: virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch) { //this is a depth first traversal, so it's safe to assum all children have complete //bounding data + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0); @@ -822,6 +823,8 @@ S32 LLProfile::getNumPoints(const LLProfileParams& params, BOOL path_open,F32 de BOOL LLProfile::generate(const LLProfileParams& params, BOOL path_open,F32 detail, S32 split, BOOL is_sculpted, S32 sculpt_size) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + if ((!mDirty) && (!is_sculpted)) { return FALSE; @@ -1302,6 +1305,8 @@ S32 LLPath::getNumNGonPoints(const LLPathParams& params, S32 sides, F32 startOff void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 end_scale, F32 twist_scale) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + // Generates a circular path, starting at (1, 0, 0), counterclockwise along the xz plane. static const F32 tableScale[] = { 1, 1, 1, 0.5f, 0.707107f, 0.53f, 0.525f, 0.5f }; @@ -1536,6 +1541,8 @@ S32 LLPath::getNumPoints(const LLPathParams& params, F32 detail) BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split, BOOL is_sculpted, S32 sculpt_size) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + if ((!mDirty) && (!is_sculpted)) { return FALSE; @@ -2112,6 +2119,8 @@ LLVolume::~LLVolume() BOOL LLVolume::generate() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + LL_CHECK_MEMORY llassert_always(mProfilep); @@ -2370,6 +2379,8 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + //input stream is now pointing at a zlib compressed block of LLSD //decompress block LLSD mdl; @@ -2776,6 +2787,8 @@ S32 LLVolume::getNumFaces() const void LLVolume::createVolumeFaces() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + if (mGenerateSingleFace) { // do nothing @@ -3741,6 +3754,8 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices, const LLMatrix3& norm_mat_in, S32 face_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + LLMatrix4a mat; mat.loadu(mat_in); @@ -4867,6 +4882,8 @@ void LLVolumeFace::freeData() BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + //tree for this face is no longer valid delete mOctree; mOctree = NULL; @@ -5536,6 +5553,8 @@ bool LLVolumeFace::cacheOptimize() void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + if (mOctree) { return; @@ -6318,6 +6337,8 @@ void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVe void LLVolumeFace::createTangents() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + if (!mTangents) { allocateTangents(mNumVertices); @@ -6358,9 +6379,9 @@ void LLVolumeFace::resizeVertices(S32 num_verts) if (num_verts) { //pad texture coordinate block end to allow for QWORD reads - S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; + S32 tc_size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF; - mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+size); + mPositions = (LLVector4a*) ll_aligned_malloc<64>(sizeof(LLVector4a)*2*num_verts+tc_size); mNormals = mPositions+num_verts; mTexCoords = (LLVector2*) (mNormals+num_verts); @@ -6531,6 +6552,8 @@ void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + LL_CHECK_MEMORY BOOL flat = mTypeMask & FLAT_MASK; @@ -7039,6 +7062,8 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build) void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal, const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME + //LLVector4a *tan1 = new LLVector4a[vertexCount * 2]; LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a)); // new(tan1) LLVector4a; diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index a77e8c08c6..c0b224b1ff 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -936,17 +936,23 @@ public: LLVector4a* mCenter; LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face. - S32 mNumVertices; + S32 mNumVertices; // num vertices == num normals == num texcoords S32 mNumAllocatedVertices; S32 mNumIndices; - LLVector4a* mPositions; - LLVector4a* mNormals; + LLVector4a* mPositions; // Contains vertices, nortmals and texcoords + LLVector4a* mNormals; // pointer into mPositions LLVector4a* mTangents; - LLVector2* mTexCoords; + LLVector2* mTexCoords; // pointer into mPositions + + // mIndices contains mNumIndices amount of elements. + // It contains triangles, each 3 indices describe one triangle. + // If mIndices contains {0, 2, 3, 1, 2, 4}, it means there + // are two triangles {0, 2, 3} and {1, 2, 4} with values being + // indexes for mPositions/mNormals/mTexCoords U16* mIndices; - //vertex buffer filled in by LLFace to cache this volume face geometry in vram + // vertex buffer filled in by LLFace to cache this volume face geometry in vram // (declared as a LLPointer to LLRefCount to avoid dependency on LLVertexBuffer) mutable LLPointer<LLRefCount> mVertexBuffer; diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h index 13150028d8..b2bc440368 100644 --- a/indra/llmath/llvolumeoctree.h +++ b/indra/llmath/llvolumeoctree.h @@ -34,19 +34,10 @@ #include "llvolume.h" #include "llvector4a.h" -class LLVolumeTriangle : public LLRefCount +class alignas(16) LLVolumeTriangle : public LLRefCount { + LL_ALIGN_NEW public: - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - LLVolumeTriangle() { mBinIndex = -1; @@ -86,20 +77,10 @@ public: }; -class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle> +class alignas(16) LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle> { + LL_ALIGN_NEW public: - - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } - LLVolumeOctreeListener(LLOctreeNode<LLVolumeTriangle>* node); ~LLVolumeOctreeListener(); diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp index 3baf1bad18..6e40dae30b 100644 --- a/indra/llmath/m4math.cpp +++ b/indra/llmath/m4math.cpp @@ -32,8 +32,7 @@ #include "m4math.h" #include "m3math.h" #include "llquaternion.h" - - +#include "llmatrix4a.h" // LLMatrix4 @@ -115,6 +114,12 @@ LLMatrix4::LLMatrix4(const LLQuaternion &q) *this = initRotation(q); } +LLMatrix4::LLMatrix4(const LLMatrix4a& mat) + : LLMatrix4(mat.getF32ptr()) +{ + +} + LLMatrix4::LLMatrix4(const LLQuaternion &q, const LLVector4 &pos) { *this = initRotTrans(q, pos); diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h index bf60adb9b6..b9da970cde 100644 --- a/indra/llmath/m4math.h +++ b/indra/llmath/m4math.h @@ -32,6 +32,7 @@ class LLVector4; class LLMatrix3; class LLQuaternion; +class LLMatrix4a; // NOTA BENE: Currently assuming a right-handed, x-forward, y-left, z-up universe @@ -104,6 +105,7 @@ public: explicit LLMatrix4(const F32 *mat); // Initializes Matrix to values in mat explicit LLMatrix4(const LLMatrix3 &mat); // Initializes Matrix to values in mat and sets position to (0,0,0) explicit LLMatrix4(const LLQuaternion &q); // Initializes Matrix with rotation q and sets position to (0,0,0) + explicit LLMatrix4(const LLMatrix4a& mat); LLMatrix4(const LLMatrix3 &mat, const LLVector4 &pos); // Initializes Matrix to values in mat and pos diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index b04c67d926..93010d2250 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -316,6 +316,12 @@ LLVector3::LLVector3(const LLVector4 &vec) mV[VZ] = (F32)vec.mV[VZ]; } +LLVector3::LLVector3(const LLVector4a& vec) + : LLVector3(vec.getF32ptr()) +{ + +} + LLVector3::LLVector3(const LLSD& sd) { setValue(sd); diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 6f857d7061..068f489020 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -33,6 +33,7 @@ #include "llsd.h" class LLVector2; class LLVector4; +class LLVector4a; class LLMatrix3; class LLMatrix4; class LLVector3d; @@ -62,7 +63,9 @@ class LLVector3 explicit LLVector3(const LLVector2 &vec); // Initializes LLVector3 to (vec[0]. vec[1], 0) explicit LLVector3(const LLVector3d &vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2]) explicit LLVector3(const LLVector4 &vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2]) - explicit LLVector3(const LLSD& sd); + explicit LLVector3(const LLVector4a& vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2]) + explicit LLVector3(const LLSD& sd); + LLSD getValue() const; diff --git a/indra/llmeshoptimizer/CMakeLists.txt b/indra/llmeshoptimizer/CMakeLists.txt new file mode 100644 index 0000000000..016794cfad --- /dev/null +++ b/indra/llmeshoptimizer/CMakeLists.txt @@ -0,0 +1,44 @@ +# -*- cmake -*- + +project(llmeshoptimizer) + +include(MESHOPTIMIZER) + +include(00-Common) +include(LLCommon) +include(LLMath) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLMESHOPTIMIZER_INCLUDE_DIR} + ${MESHOPTIMIZER_INCLUDE_DIRS} + ${LIBS_PREBUILT_DIR}/include #access to boost headers, needed for LLError + ) + +set(llmeshoptimizer_SOURCE_FILES + llmeshoptimizer.cpp + ) + +set(llmeshoptimizer_HEADER_FILES + CMakeLists.txt + + llmeshoptimizer.h + ) + +set_source_files_properties(${llmeshoptimizer_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llmeshoptimizer_SOURCE_FILES ${llmeshoptimizer_HEADER_FILES}) + +#if (USE_MESHOPT) + add_library (llmeshoptimizer ${llmeshoptimizer_SOURCE_FILES}) + + target_link_libraries(llmeshoptimizer + ${LLCOMMON_LIBRARIES} + ${LLMATH_LIBRARIES} + ${MESHOPTIMIZER_LIBRARIES}) + + # Add tests + +#endif (USE_MESHOPT) diff --git a/indra/llmeshoptimizer/llmeshoptimizer.cpp b/indra/llmeshoptimizer/llmeshoptimizer.cpp new file mode 100644 index 0000000000..a879389c5a --- /dev/null +++ b/indra/llmeshoptimizer/llmeshoptimizer.cpp @@ -0,0 +1,142 @@ + /** +* @file llmeshoptimizer.cpp +* @brief Wrapper around meshoptimizer +* +* $LicenseInfo:firstyear=2021&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2021, 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$ +*/ + +#include "llmeshoptimizer.h" + +#include "meshoptimizer.h" + +LLMeshOptimizer::LLMeshOptimizer() +{ + // Todo: Looks like for memory management, we can add allocator and deallocator callbacks + // Should be one time + // meshopt_setAllocator(allocate, deallocate); +} + +LLMeshOptimizer::~LLMeshOptimizer() +{ +} + +//static +void LLMeshOptimizer::generateShadowIndexBuffer(U16 *destination, + const U16 *indices, + U64 index_count, + const LLVector4a *vertex_positions, + U64 vertex_count, + U64 vertex_positions_stride +) +{ + meshopt_generateShadowIndexBuffer<unsigned short>(destination, + indices, + index_count, + (const float*)vertex_positions, // verify that it is correct to convert to float + vertex_count, + sizeof(LLVector4a), + vertex_positions_stride + ); +} + +//static +U64 LLMeshOptimizer::simplifyU32(U32 *destination, + const U32 *indices, + U64 index_count, + const LLVector4a *vertex_positions, + U64 vertex_count, + U64 vertex_positions_stride, + U64 target_index_count, + F32 target_error, + bool sloppy, + F32* result_error +) +{ + if (sloppy) + { + return meshopt_simplifySloppy<unsigned int>(destination, + indices, + index_count, + (const float*)vertex_positions, + vertex_count, + vertex_positions_stride, + target_index_count, + target_error, + result_error + ); + } + else + { + return meshopt_simplify<unsigned int>(destination, + indices, + index_count, + (const float*)vertex_positions, + vertex_count, + vertex_positions_stride, + target_index_count, + target_error, + result_error + ); + } +} + +//static +U64 LLMeshOptimizer::simplify(U16 *destination, + const U16 *indices, + U64 index_count, + const LLVector4a *vertex_positions, + U64 vertex_count, + U64 vertex_positions_stride, + U64 target_index_count, + F32 target_error, + bool sloppy, + F32* result_error + ) +{ + if (sloppy) + { + return meshopt_simplifySloppy<unsigned short>(destination, + indices, + index_count, + (const float*)vertex_positions, + vertex_count, + vertex_positions_stride, + target_index_count, + target_error, + result_error + ); + } + else + { + return meshopt_simplify<unsigned short>(destination, + indices, + index_count, + (const float*)vertex_positions, + vertex_count, + vertex_positions_stride, + target_index_count, + target_error, + result_error + ); + } +} + diff --git a/indra/llmeshoptimizer/llmeshoptimizer.h b/indra/llmeshoptimizer/llmeshoptimizer.h new file mode 100644 index 0000000000..e8dd16dae9 --- /dev/null +++ b/indra/llmeshoptimizer/llmeshoptimizer.h @@ -0,0 +1,83 @@ +/** +* @file llmeshoptimizer.h +* @brief Wrapper around meshoptimizer +* +* $LicenseInfo:firstyear=2021&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2021, 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 LLMESHOPTIMIZER_H +#define LLMESHOPTIMIZER_H + +#include "linden_common.h" + +#include "llmath.h" + +class LLMeshOptimizer +{ +public: + LLMeshOptimizer(); + ~LLMeshOptimizer(); + + static void generateShadowIndexBuffer( + U16 *destination, + const U16 *indices, + U64 index_count, + const LLVector4a *vertex_positions, + U64 vertex_count, + U64 vertex_positions_stride); + + // returns amount of indices in destiantion + // sloppy engages a variant of a mechanizm that does not respect topology as much + // but is much more efective for simpler models + // result_error returns how far from original the model is in % if not NULL + // Works with U32 indices (LLFace uses U16 indices) + static U64 simplifyU32( + U32 *destination, + const U32 *indices, + U64 index_count, + const LLVector4a *vertex_positions, + U64 vertex_count, + U64 vertex_positions_stride, + U64 target_index_count, + F32 target_error, + bool sloppy, + F32* result_error); + + // Returns amount of indices in destiantion + // sloppy engages a variant of a mechanizm that does not respect topology as much + // but is much better for simpler models + // result_error returns how far from original the model is in % if not NULL + // Meant for U16 indices (LLFace uses U16 indices) + static U64 simplify( + U16 *destination, + const U16 *indices, + U64 index_count, + const LLVector4a *vertex_positions, + U64 vertex_count, + U64 vertex_positions_stride, + U64 target_index_count, + F32 target_error, + bool sloppy, + F32* result_error); +private: +}; + +#endif //LLMESHOPTIMIZER_H diff --git a/indra/llmessage/llfiltersd2xmlrpc.cpp b/indra/llmessage/llfiltersd2xmlrpc.cpp index d3e195789b..0abdafbdfc 100644 --- a/indra/llmessage/llfiltersd2xmlrpc.cpp +++ b/indra/llmessage/llfiltersd2xmlrpc.cpp @@ -309,7 +309,6 @@ LLFilterSD2XMLRPCResponse::~LLFilterSD2XMLRPCResponse() } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_SD2XMLRPC_RESPONSE("SD2XMLRPC Response"); // virtual LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( const LLChannelDescriptors& channels, @@ -318,7 +317,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCResponse::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_SD2XMLRPC_RESPONSE); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; // This pipe does not work if it does not have everyting. This @@ -386,8 +385,6 @@ LLFilterSD2XMLRPCRequest::~LLFilterSD2XMLRPCRequest() { } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_SD2XMLRPC_REQUEST("S22XMLRPC Request"); - // virtual LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( const LLChannelDescriptors& channels, @@ -396,7 +393,7 @@ LLIOPipe::EStatus LLFilterSD2XMLRPCRequest::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_SD2XMLRPC_REQUEST); + LL_PROFILE_ZONE_SCOPED; // This pipe does not work if it does not have everyting. This // could be addressed by making a stream parser for llsd which // handled partial information. @@ -593,8 +590,6 @@ LLFilterXMLRPCResponse2LLSD::~LLFilterXMLRPCResponse2LLSD() { } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_XMLRPC2LLSD_RESPONSE("XMLRPC2LLSD Response"); - LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, @@ -602,7 +597,7 @@ LLIOPipe::EStatus LLFilterXMLRPCResponse2LLSD::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_XMLRPC2LLSD_RESPONSE); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; if(!eos) return STATUS_BREAK; @@ -679,7 +674,6 @@ LLFilterXMLRPCRequest2LLSD::~LLFilterXMLRPCRequest2LLSD() { } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_XMLRPC2LLSD_REQUEST("XMLRPC2LLSD Request"); LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, @@ -687,7 +681,7 @@ LLIOPipe::EStatus LLFilterXMLRPCRequest2LLSD::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_XMLRPC2LLSD_REQUEST); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; if(!eos) return STATUS_BREAK; if(!buffer) return STATUS_ERROR; diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 6fd17c9154..6e9598a0a3 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -121,6 +121,7 @@ LLSD LLHTTPNode::simplePost(const LLSD& input) const // virtual void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) const { + LL_PROFILE_ZONE_SCOPED; try { response->result(simpleGet()); @@ -134,6 +135,7 @@ void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) cons // virtual void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { + LL_PROFILE_ZONE_SCOPED; try { response->result(simplePut(input)); @@ -147,6 +149,7 @@ void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, cons // virtual void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, const LLSD& input) const { + LL_PROFILE_ZONE_SCOPED; try { response->result(simplePost(input)); @@ -160,6 +163,7 @@ void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, con // virtual void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) const { + LL_PROFILE_ZONE_SCOPED; try { response->result(simpleDel(context)); diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index d9042fa8b0..c707c7ad09 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -132,12 +132,6 @@ private: LLSD mHeaders; }; -static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_PIPE("HTTP Pipe"); -static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_GET("HTTP Get"); -static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_PUT("HTTP Put"); -static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_POST("HTTP Post"); -static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_DELETE("HTTP Delete"); - LLIOPipe::EStatus LLHTTPPipe::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, @@ -145,7 +139,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_PIPE); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; LL_DEBUGS() << "LLSDHTTPServer::process_impl" << LL_ENDL; @@ -174,12 +168,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB]; if(verb == HTTP_VERB_GET) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_GET); mNode.get(LLHTTPNode::ResponsePtr(mResponse), context); } else if(verb == HTTP_VERB_PUT) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_PUT); LLSD input; if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) { @@ -195,7 +187,6 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( } else if(verb == HTTP_VERB_POST) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_POST); LLSD input; if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) { @@ -211,7 +202,6 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( } else if(verb == HTTP_VERB_DELETE) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_DELETE); mNode.del(LLHTTPNode::ResponsePtr(mResponse), context); } else if(verb == HTTP_VERB_OPTIONS) @@ -455,8 +445,6 @@ protected: * LLHTTPResponseHeader */ -static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_HEADER("HTTP Header"); - // virtual LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( const LLChannelDescriptors& channels, @@ -465,7 +453,7 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_HEADER); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; if(eos) { @@ -655,8 +643,6 @@ void LLHTTPResponder::markBad( << "</body>\n</html>\n"; } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_HTTP_RESPONDER("HTTP Responder"); - // virtual LLIOPipe::EStatus LLHTTPResponder::process_impl( const LLChannelDescriptors& channels, @@ -665,7 +651,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_HTTP_RESPONDER); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; LLIOPipe::EStatus status = STATUS_OK; diff --git a/indra/llmessage/lliosocket.cpp b/indra/llmessage/lliosocket.cpp index a9cc71c365..321d7286eb 100644 --- a/indra/llmessage/lliosocket.cpp +++ b/indra/llmessage/lliosocket.cpp @@ -300,8 +300,6 @@ LLIOSocketReader::~LLIOSocketReader() //LL_DEBUGS() << "Destroying LLIOSocketReader" << LL_ENDL; } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_SOCKET_READER("Socket Reader"); - // virtual LLIOPipe::EStatus LLIOSocketReader::process_impl( const LLChannelDescriptors& channels, @@ -310,7 +308,7 @@ LLIOPipe::EStatus LLIOSocketReader::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_READER); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; if(!mSource) return STATUS_PRECONDITION_NOT_MET; if(!mInitialized) @@ -400,7 +398,6 @@ LLIOSocketWriter::~LLIOSocketWriter() //LL_DEBUGS() << "Destroying LLIOSocketWriter" << LL_ENDL; } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_SOCKET_WRITER("Socket Writer"); // virtual LLIOPipe::EStatus LLIOSocketWriter::process_impl( const LLChannelDescriptors& channels, @@ -409,7 +406,7 @@ LLIOPipe::EStatus LLIOSocketWriter::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_SOCKET_WRITER); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; if(!mDestination) return STATUS_PRECONDITION_NOT_MET; if(!mInitialized) @@ -556,7 +553,6 @@ void LLIOServerSocket::setResponseTimeout(F32 timeout_secs) mResponseTimeout = timeout_secs; } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_SERVER_SOCKET("Server Socket"); // virtual LLIOPipe::EStatus LLIOServerSocket::process_impl( const LLChannelDescriptors& channels, @@ -565,7 +561,7 @@ LLIOPipe::EStatus LLIOServerSocket::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_SERVER_SOCKET); + LL_PROFILE_ZONE_SCOPED; PUMP_DEBUG; if(!pump) { diff --git a/indra/llmessage/llioutil.cpp b/indra/llmessage/llioutil.cpp index b8443c0600..850bc2a616 100644 --- a/indra/llmessage/llioutil.cpp +++ b/indra/llmessage/llioutil.cpp @@ -45,7 +45,6 @@ LLIOPipe::EStatus LLIOFlush::process_impl( } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_SLEEP("IO Sleep"); /** * @class LLIOSleep */ @@ -56,7 +55,7 @@ LLIOPipe::EStatus LLIOSleep::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_SLEEP); + LL_PROFILE_ZONE_SCOPED; if(mSeconds > 0.0) { if(pump) pump->sleepChain(mSeconds); @@ -66,7 +65,6 @@ LLIOPipe::EStatus LLIOSleep::process_impl( return STATUS_DONE; } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_ADD_CHAIN("Add Chain"); /** * @class LLIOAddChain */ @@ -77,7 +75,7 @@ LLIOPipe::EStatus LLIOAddChain::process_impl( LLSD& context, LLPumpIO* pump) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_ADD_CHAIN); + LL_PROFILE_ZONE_SCOPED; pump->addChain(mChain, mTimeout); return STATUS_DONE; } diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index a2524e9804..44720f0015 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -416,9 +416,6 @@ void LLPumpIO::pump() pump(DEFAULT_POLL_TIMEOUT); } -static LLTrace::BlockTimerStatHandle FTM_PUMP_IO("Pump IO"); -static LLTrace::BlockTimerStatHandle FTM_PUMP_POLL("Pump Poll"); - LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain) { std::for_each( @@ -431,7 +428,7 @@ LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t //timeout is in microseconds void LLPumpIO::pump(const S32& poll_timeout) { - LL_RECORD_BLOCK_TIME(FTM_PUMP_IO); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_INFOS() << "LLPumpIO::pump()" << LL_ENDL; // Run any pending runners. @@ -509,7 +506,7 @@ void LLPumpIO::pump(const S32& poll_timeout) S32 count = 0; S32 client_id = 0; { - LL_RECORD_BLOCK_TIME(FTM_PUMP_POLL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd); } PUMP_DEBUG; @@ -737,10 +734,9 @@ bool LLPumpIO::respond( return true; } -static LLTrace::BlockTimerStatHandle FTM_PUMP_CALLBACK_CHAIN("Chain"); - void LLPumpIO::callback() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_INFOS() << "LLPumpIO::callback()" << LL_ENDL; if(true) { @@ -756,7 +752,6 @@ void LLPumpIO::callback() callbacks_t::iterator end = mCallbacks.end(); for(; it != end; ++it) { - LL_RECORD_BLOCK_TIME(FTM_PUMP_CALLBACK_CHAIN); // it's always the first and last time for respone chains (*it).mHead = (*it).mChainLinks.begin(); (*it).mInit = true; diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 6d5ad0ba08..32f79f0546 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -533,6 +533,8 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_MESSAGES("Process Messages"); // decode a given message BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender ) { + LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES); + llassert( mReceiveSize >= 0 ); llassert( mCurrentRMessageTemplate); llassert( !mCurrentRMessageData ); @@ -707,12 +709,9 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender decode_timer.reset(); } + if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) ) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_MESSAGES); - if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) ) - { - LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL; - } + LL_WARNS() << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << LL_ENDL; } if(LLMessageReader::getTimeDecodes() || gMessageSystem->getTimingCallback()) diff --git a/indra/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index 33e90555fa..e89690438e 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -149,7 +149,11 @@ bool get_dom_sources(const domInputLocalOffset_Array& inputs, S32& pos_offset, S return true; } -LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domTrianglesRef& tri) +LLModel::EModelStatus load_face_from_dom_triangles( + std::vector<LLVolumeFace>& face_list, + std::vector<std::string>& materials, + domTrianglesRef& tri, + LLSD& log_msg) { LLVolumeFace face; std::vector<LLVolumeFace::VertexData> verts; @@ -169,12 +173,18 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa if ( !get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) { + LLSD args; + args["Message"] = "ParsingErrorBadElement"; + log_msg.append(args); return LLModel::BAD_ELEMENT; } if (!pos_source || !pos_source->getFloat_array()) { LL_WARNS() << "Unable to process mesh without position data; invalid model; invalid model." << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorPositionInvalidModel"; + log_msg.append(args); return LLModel::BAD_ELEMENT; } @@ -354,7 +364,11 @@ LLModel::EModelStatus load_face_from_dom_triangles(std::vector<LLVolumeFace>& fa return LLModel::NO_ERRORS ; } -LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& face_list, std::vector<std::string>& materials, domPolylistRef& poly, LLSD& log_msg) +LLModel::EModelStatus load_face_from_dom_polylist( + std::vector<LLVolumeFace>& face_list, + std::vector<std::string>& materials, + domPolylistRef& poly, + LLSD& log_msg) { domPRef p = poly->getP(); domListOfUInts& idx = p->getValue(); @@ -381,6 +395,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac if (!get_dom_sources(inputs, pos_offset, tc_offset, norm_offset, idx_stride, pos_source, tc_source, norm_source)) { + LL_WARNS() << "Bad element." << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorBadElement"; + log_msg.append(args); return LLModel::BAD_ELEMENT; } @@ -432,6 +450,9 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac if (!cv.getPosition().isFinite3()) { LL_WARNS() << "Found NaN while loading position data from DAE-Model, invalid model." << LL_ENDL; + LLSD args; + args["Message"] = "PositionNaN"; + log_msg.append(args); return LLModel::BAD_ELEMENT; } } @@ -464,6 +485,10 @@ LLModel::EModelStatus load_face_from_dom_polylist(std::vector<LLVolumeFace>& fac if (!cv.getNormal().isFinite3()) { LL_WARNS() << "Found NaN while loading normals from DAE-Model, invalid model." << LL_ENDL; + LLSD args; + args["Message"] = "NormalsNaN"; + log_msg.append(args); + return LLModel::BAD_ELEMENT; } } @@ -781,6 +806,9 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac } } + // Viewer can only fit U16 vertices, shouldn't we do some checks here and return overflow if result has more? + llassert(vert_idx.size() < U16_MAX); + //build vertex array from map std::vector<LLVolumeFace::VertexData> new_verts; new_verts.resize(vert_idx.size()); @@ -798,7 +826,12 @@ LLModel::EModelStatus load_face_from_dom_polygons(std::vector<LLVolumeFace>& fac for (U32 i = 0; i < verts.size(); ++i) { indices[i] = vert_idx[verts[i]]; - llassert(!i || (indices[i-1] != indices[i])); + if (i % 3 != 0) // assumes GL_TRIANGLES, compare 0-1, 1-2, 3-4, 4-5 but not 2-3 or 5-6 + { + // A faulty degenerate triangle detection (triangle with 0 area), + // probably should be a warning and not an assert + llassert(!i || (indices[i-1] != indices[i])); + } } // DEBUG just build an expanded triangle list @@ -918,6 +951,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!dom) { LL_INFOS() <<" Error with dae - traditionally indicates a corrupt file."<<LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorCorrupt"; + mWarningsArray.append(args); setLoadState( ERROR_PARSING ); return false; } @@ -945,6 +981,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!doc) { LL_WARNS() << "can't find internal doc" << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorNoDoc"; + mWarningsArray.append(args); return false; } @@ -952,6 +991,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!root) { LL_WARNS() << "document has no root" << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorNoRoot"; + mWarningsArray.append(args); return false; } @@ -967,6 +1009,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!result) { LL_INFOS() << "Could not verify controller" << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorBadElement"; + mWarningsArray.append(args); setLoadState( ERROR_PARSING ); return true; } @@ -1100,6 +1145,9 @@ bool LLDAELoader::OpenFile(const std::string& filename) if (!scene) { LL_WARNS() << "document has no visual_scene" << LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorNoScene"; + mWarningsArray.append(args); setLoadState( ERROR_PARSING ); return true; } @@ -1108,11 +1156,14 @@ bool LLDAELoader::OpenFile(const std::string& filename) bool badElement = false; - processElement( scene, badElement, &dae ); + processElement( scene, badElement, &dae); if ( badElement ) { LL_INFOS()<<"Scene could not be parsed"<<LL_ENDL; + LLSD args; + args["Message"] = "ParsingErrorCantParseScene"; + mWarningsArray.append(args); setLoadState( ERROR_PARSING ); } @@ -1184,17 +1235,19 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do LLMeshSkinInfo& skin_info = model->mSkinInfo; + LLMatrix4 mat; for (int i = 0; i < 4; i++) { for(int j = 0; j < 4; j++) { - skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4]; + mat.mMatrix[i][j] = dom_value[i + j*4]; } } - LLMatrix4 trans = normalized_transformation; - trans *= skin_info.mBindShapeMatrix; - skin_info.mBindShapeMatrix = trans; + skin_info.mBindShapeMatrix.loadu(mat); + + LLMatrix4a trans(normalized_transformation); + matMul(trans, skin_info.mBindShapeMatrix, skin_info.mBindShapeMatrix); } @@ -1412,7 +1465,7 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do mat.mMatrix[i][j] = transform[k*16 + i + j*4]; } } - model->mSkinInfo.mInvBindMatrix.push_back(mat); + model->mSkinInfo.mInvBindMatrix.push_back(LLMatrix4a(mat)); } } } @@ -1486,9 +1539,9 @@ void LLDAELoader::processDomModel(LLModel* model, DAE* dae, daeElement* root, do if (mJointMap.find(lookingForJoint) != mJointMap.end() && model->mSkinInfo.mInvBindMatrix.size() > i) { - LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i]; + LLMatrix4 newInverse = LLMatrix4(model->mSkinInfo.mInvBindMatrix[i].getF32ptr()); newInverse.setTranslation( mJointList[lookingForJoint].getTranslation() ); - model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse ); + model->mSkinInfo.mAlternateBindMatrix.push_back( LLMatrix4a(newInverse) ); } else { @@ -1951,7 +2004,7 @@ daeElement* LLDAELoader::getChildFromElement( daeElement* pElement, std::string return NULL; } -void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae ) +void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* dae) { LLMatrix4 saved_transform; bool pushed_mat = false; @@ -2045,6 +2098,11 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da if (mTransform.determinant() < 0) { //negative scales are not supported LL_INFOS() << "Negative scale detected, unsupported transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL; + LLSD args; + args["Message"] = "NegativeScaleTrans"; + args["LABEL"] = getElementLabel(instance_geo); + mWarningsArray.append(args); + badElement = true; } @@ -2068,6 +2126,10 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da if (transformation.determinant() < 0) { //negative scales are not supported LL_INFOS() << "Negative scale detected, unsupported post-normalization transform. domInstance_geometry: " << getElementLabel(instance_geo) << LL_ENDL; + LLSD args; + args["Message"] = "NegativeScaleNormTrans"; + args["LABEL"] = getElementLabel(instance_geo); + mWarningsArray.append(args); badElement = true; } @@ -2109,6 +2171,9 @@ void LLDAELoader::processElement( daeElement* element, bool& badElement, DAE* da else { LL_INFOS()<<"Unable to resolve geometry URL."<<LL_ENDL; + LLSD args; + args["Message"] = "CantResolveGeometryUrl"; + mWarningsArray.append(args); badElement = true; } @@ -2399,7 +2464,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD& { domTrianglesRef& tri = tris.get(i); - status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri); + status = load_face_from_dom_triangles(pModel->getVolumeFaces(), pModel->getMaterialList(), tri, log_msg); pModel->mStatus = status; if(status != LLModel::NO_ERRORS) { @@ -2426,6 +2491,7 @@ bool LLDAELoader::addVolumeFacesFromDomMesh(LLModel* pModel,domMesh* mesh, LLSD& for (U32 i = 0; i < polygons.getCount(); ++i) { domPolygonsRef& poly = polygons.get(i); + status = load_face_from_dom_polygons(pModel->getVolumeFaces(), pModel->getMaterialList(), poly); if(status != LLModel::NO_ERRORS) diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 1b34068ece..204ff63712 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -31,6 +31,7 @@ #include "llconvexdecomposition.h" #include "llsdserialize.h" #include "llvector4a.h" +#include "llmd5.h" #ifdef LL_USESYSTEMLIBS # include <zlib.h> @@ -1404,7 +1405,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) } } - mInvBindMatrix.push_back(mat); + mInvBindMatrix.push_back(LLMatrix4a(mat)); } if (mJointNames.size() != mInvBindMatrix.size()) @@ -1418,13 +1419,15 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) if (skin.has("bind_shape_matrix")) { + LLMatrix4 mat; for (U32 j = 0; j < 4; j++) { for (U32 k = 0; k < 4; k++) { - mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal(); + mat.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal(); } } + mBindShapeMatrix.loadu(mat); } if (skin.has("alt_inverse_bind_matrix")) @@ -1440,7 +1443,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) } } - mAlternateBindMatrix.push_back(mat); + mAlternateBindMatrix.push_back(LLMatrix4a(mat)); } } @@ -1457,6 +1460,8 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) { mLockScaleIfJointPosition = false; } + + updateHash(); } LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_position) const @@ -1508,6 +1513,38 @@ LLSD LLMeshSkinInfo::asLLSD(bool include_joints, bool lock_scale_if_joint_positi return ret; } +void LLMeshSkinInfo::updateHash() +{ + // get hash of data relevant to render batches + LLMD5 hash; + + //mJointNames + for (auto& name : mJointNames) + { + hash.update(name); + } + + //mJointNums + hash.update((U8*)&(mJointNums[0]), sizeof(S32) * mJointNums.size()); + + //mInvBindMatrix + F32* src = mInvBindMatrix[0].getF32ptr(); + + for (int i = 0; i < mInvBindMatrix.size() * 16; ++i) + { + S32 t = llround(src[i] * 10000.f); + hash.update((U8*)&t, sizeof(S32)); + } + //hash.update((U8*)&(mInvBindMatrix[0]), sizeof(LLMatrix4a) * mInvBindMatrix.size()); + + hash.finalize(); + + U64 digest[2]; + hash.raw_digest((U8*) digest); + + mHash = digest[0]; +} + LLModel::Decomposition::Decomposition(LLSD& data) { fromLLSD(data); diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 51fa2f8079..3881b1338c 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -33,34 +33,44 @@ #include "m4math.h" #include <queue> +#include <boost/align/aligned_allocator.hpp> + class daeElement; class domMesh; #define MAX_MODEL_FACES 8 +LL_ALIGN_PREFIX(16) class LLMeshSkinInfo { + LL_ALIGN_NEW public: LLMeshSkinInfo(); LLMeshSkinInfo(LLSD& data); void fromLLSD(LLSD& data); LLSD asLLSD(bool include_joints, bool lock_scale_if_joint_position) const; + void updateHash(); LLUUID mMeshID; std::vector<std::string> mJointNames; mutable std::vector<S32> mJointNums; - std::vector<LLMatrix4> mInvBindMatrix; - std::vector<LLMatrix4> mAlternateBindMatrix; + typedef std::vector<LLMatrix4a, boost::alignment::aligned_allocator<LLMatrix4a, 16>> matrix_list_t; + matrix_list_t mInvBindMatrix; + matrix_list_t mAlternateBindMatrix; + + LL_ALIGN_16(LLMatrix4a mBindShapeMatrix); - LLMatrix4 mBindShapeMatrix; float mPelvisOffset; bool mLockScaleIfJointPosition; bool mInvalidJointsScrubbed; bool mJointNumsInitialized; -}; + U64 mHash = 0; +} LL_ALIGN_POSTFIX(16); +LL_ALIGN_PREFIX(16) class LLModel : public LLVolume { + LL_ALIGN_NEW public: enum @@ -281,8 +291,10 @@ public: EModelStatus mStatus ; + // A model/object can only have 8 faces, spillover faces will + // be moved to new model/object and assigned a submodel id. int mSubmodelID; -}; +} LL_ALIGN_POSTFIX(16); typedef std::vector<LLPointer<LLModel> > model_list; typedef std::queue<LLPointer<LLModel> > model_queue; diff --git a/indra/llrender/llcubemap.cpp b/indra/llrender/llcubemap.cpp index 5947bca670..834084674e 100644 --- a/indra/llrender/llcubemap.cpp +++ b/indra/llrender/llcubemap.cpp @@ -47,7 +47,6 @@ bool LLCubeMap::sUseCubeMaps = true; LLCubeMap::LLCubeMap(bool init_as_srgb) : mTextureStage(0), - mTextureCoordStage(0), mMatrixStage(0), mIssRGB(init_as_srgb) { @@ -150,6 +149,7 @@ void LLCubeMap::initRawData(const std::vector<LLPointer<LLImageRaw> >& rawimages void LLCubeMap::initGLData() { + LL_PROFILE_ZONE_SCOPED; for (int i = 0; i < 6; i++) { mImages[i]->setSubImage(mRawImages[i], 0, 0, RESOLUTION, RESOLUTION); @@ -179,7 +179,6 @@ void LLCubeMap::bind() void LLCubeMap::enable(S32 stage) { enableTexture(stage); - enableTextureCoords(stage); } void LLCubeMap::enableTexture(S32 stage) @@ -191,35 +190,9 @@ void LLCubeMap::enableTexture(S32 stage) } } -void LLCubeMap::enableTextureCoords(S32 stage) -{ - mTextureCoordStage = stage; - if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && stage >= 0 && LLCubeMap::sUseCubeMaps) - { - if (stage > 0) - { - gGL.getTexUnit(stage)->activate(); - } - - glEnable(GL_TEXTURE_GEN_R); - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); - glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP); - - if (stage > 0) - { - gGL.getTexUnit(0)->activate(); - } - } -} - void LLCubeMap::disable(void) { disableTexture(); - disableTextureCoords(); } void LLCubeMap::disableTexture(void) @@ -234,24 +207,6 @@ void LLCubeMap::disableTexture(void) } } -void LLCubeMap::disableTextureCoords(void) -{ - if (!LLGLSLShader::sNoFixedFunction && gGLManager.mHasCubeMap && mTextureCoordStage >= 0 && LLCubeMap::sUseCubeMaps) - { - if (mTextureCoordStage > 0) - { - gGL.getTexUnit(mTextureCoordStage)->activate(); - } - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - glDisable(GL_TEXTURE_GEN_R); - if (mTextureCoordStage > 0) - { - gGL.getTexUnit(0)->activate(); - } - } -} - void LLCubeMap::setMatrix(S32 stage) { mMatrixStage = stage; @@ -453,6 +408,7 @@ BOOL LLCubeMap::project(F32& v_min, F32& v_max, F32& h_min, F32& h_max, void LLCubeMap::paintIn(LLVector3 dir[4], const LLColor4U& col) { + LL_PROFILE_ZONE_SCOPED; F32 v_min, v_max, h_min, h_max; LLVector3 center = dir[0] + dir[1] + dir[2] + dir[3]; center.normVec(); diff --git a/indra/llrender/llcubemap.h b/indra/llrender/llcubemap.h index 95b6d12099..a01636d8d4 100644 --- a/indra/llrender/llcubemap.h +++ b/indra/llrender/llcubemap.h @@ -48,12 +48,10 @@ public: void enable(S32 stage); void enableTexture(S32 stage); - void enableTextureCoords(S32 stage); S32 getStage(void) { return mTextureStage; } void disable(void); void disableTexture(void); - void disableTextureCoords(void); void setMatrix(S32 stage); void restoreMatrix(); void setReflection (void); @@ -80,7 +78,6 @@ protected: LLPointer<LLImageGL> mImages[6]; LLPointer<LLImageRaw> mRawImages[6]; S32 mTextureStage; - S32 mTextureCoordStage; S32 mMatrixStage; }; diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index f128636ab2..c71e24c83a 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -30,8 +30,7 @@ #include "llfontbitmapcache.h" LLFontBitmapCache::LLFontBitmapCache() -: LLTrace::MemTrackable<LLFontBitmapCache>("LLFontBitmapCache"), - mNumComponents(0), +: mNumComponents(0), mBitmapWidth(0), mBitmapHeight(0), mBitmapNum(-1), @@ -124,9 +123,6 @@ BOOL LLFontBitmapCache::nextOpenPos(S32 width, S32 &pos_x, S32 &pos_y, S32& bitm image_gl->createGLTexture(0, image_raw); gGL.getTexUnit(0)->bind(image_gl); image_gl->setFilteringOption(LLTexUnit::TFO_POINT); // was setMipFilterNearest(TRUE, TRUE); - - claimMem(image_raw); - claimMem(image_gl); } else { @@ -156,20 +152,8 @@ void LLFontBitmapCache::destroyGL() void LLFontBitmapCache::reset() { - for (std::vector<LLPointer<LLImageRaw> >::iterator it = mImageRawVec.begin(), end_it = mImageRawVec.end(); - it != end_it; - ++it) - { - disclaimMem(**it); - } mImageRawVec.clear(); - for (std::vector<LLPointer<LLImageGL> >::iterator it = mImageGLVec.begin(), end_it = mImageGLVec.end(); - it != end_it; - ++it) - { - disclaimMem(**it); - } mImageGLVec.clear(); mBitmapWidth = 0; diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h index 75df3a94a7..7de3a6b56f 100644 --- a/indra/llrender/llfontbitmapcache.h +++ b/indra/llrender/llfontbitmapcache.h @@ -32,7 +32,7 @@ // Maintain a collection of bitmaps containing rendered glyphs. // Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL. -class LLFontBitmapCache : public LLTrace::MemTrackable<LLFontBitmapCache> +class LLFontBitmapCache { public: LLFontBitmapCache(); diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index c41730ebaa..e964d1586f 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -104,8 +104,7 @@ LLFontGlyphInfo::LLFontGlyphInfo(U32 index) } LLFontFreetype::LLFontFreetype() -: LLTrace::MemTrackable<LLFontFreetype>("LLFontFreetype"), - mFontBitmapCachep(new LLFontBitmapCache), +: mFontBitmapCachep(new LLFontBitmapCache), mAscender(0.f), mDescender(0.f), mLineHeight(0.f), @@ -222,8 +221,6 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v S32 max_char_height = ll_round(0.5f + (y_max - y_min)); mFontBitmapCachep->init(components, max_char_width, max_char_height); - claimMem(mFontBitmapCachep); - if (!mFTFace->charmap) { @@ -238,7 +235,6 @@ BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 v } mName = filename; - claimMem(mName); mPointSize = point_size; mStyle = LLFontGL::NORMAL; @@ -460,6 +456,7 @@ LLFontGlyphInfo* LLFontFreetype::addGlyph(llwchar wch) const LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const { + LL_PROFILE_ZONE_SCOPED; if (mFTFace == NULL) return NULL; @@ -585,7 +582,6 @@ void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const } else { - claimMem(gi); mCharGlyphInfoMap[wch] = gi; } } @@ -631,11 +627,9 @@ void LLFontFreetype::resetBitmapCache() it != end_it; ++it) { - disclaimMem(it->second); delete it->second; } mCharGlyphInfoMap.clear(); - disclaimMem(mFontBitmapCachep); mFontBitmapCachep->reset(); // Adding default glyph is skipped for fallback fonts here as well as in loadFace(). diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index 1afe84e770..f61f169987 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -76,7 +76,7 @@ struct LLFontGlyphInfo extern LLFontManager *gFontManagerp; -class LLFontFreetype : public LLRefCount, public LLTrace::MemTrackable<LLFontFreetype> +class LLFontFreetype : public LLRefCount { public: LLFontFreetype(); diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 86a4c35e6d..1bf061bc8d 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -109,8 +109,6 @@ S32 LLFontGL::getNumFaces(const std::string& filename) return mFontFreetype->getNumFaces(filename); } -static LLTrace::BlockTimerStatHandle FTM_RENDER_FONTS("Fonts"); - S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, F32* right_x, BOOL use_ellipses) const { @@ -147,7 +145,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRectf& rec S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const { - LL_RECORD_BLOCK_TIME(FTM_RENDER_FONTS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if(!sDisplayFont) //do not display texts { @@ -547,9 +545,19 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars return cur_x / sScaleX; } +void LLFontGL::generateASCIIglyphs() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI + for (U32 i = 32; (i < 127); i++) + { + mFontFreetype->getGlyphInfo(i); + } +} + // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, EWordWrapStyle end_on_word_boundary) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI if (!wchars || !wchars[0] || max_chars == 0) { return 0; @@ -829,6 +837,8 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st { sFontRegistry->reset(); } + + LLFontGL::loadDefaultFonts(); } // Force standard fonts to get generated up front. @@ -838,6 +848,7 @@ void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::st // static bool LLFontGL::loadDefaultFonts() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI bool succ = true; succ &= (NULL != getFontSansSerifSmall()); succ &= (NULL != getFontSansSerif()); @@ -845,10 +856,18 @@ bool LLFontGL::loadDefaultFonts() succ &= (NULL != getFontSansSerifHuge()); succ &= (NULL != getFontSansSerifBold()); succ &= (NULL != getFontMonospace()); - succ &= (NULL != getFontExtChar()); return succ; } +void LLFontGL::loadCommonFonts() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI + getFont(LLFontDescriptor("SansSerif", "Small", BOLD)); + getFont(LLFontDescriptor("SansSerif", "Large", BOLD)); + getFont(LLFontDescriptor("SansSerif", "Huge", BOLD)); + getFont(LLFontDescriptor("Monospace", "Medium", 0)); +} + // static void LLFontGL::destroyDefaultFonts() { @@ -1015,7 +1034,7 @@ LLFontGL* LLFontGL::getFontSansSerifBig() //static LLFontGL* LLFontGL::getFontSansSerifHuge() { - static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Large",0)); + static LLFontGL* fontp = getFont(LLFontDescriptor("SansSerif","Huge",0)); return fontp; } @@ -1026,12 +1045,6 @@ LLFontGL* LLFontGL::getFontSansSerifBold() return fontp; } -//static -LLFontGL* LLFontGL::getFontExtChar() -{ - return getFontSansSerif(); -} - //static LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc) { diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 10891faed9..3b58a37d33 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -160,12 +160,15 @@ public: const LLFontDescriptor& getFontDesc() const; + void generateASCIIglyphs(); + static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, bool create_gl_textures = true); // Load sans-serif, sans-serif-small, etc. // Slow, requires multiple seconds to load fonts. static bool loadDefaultFonts(); + static void loadCommonFonts(); static void destroyDefaultFonts(); static void destroyAllGL(); @@ -190,7 +193,6 @@ public: static LLFontGL* getFontSansSerifBig(); static LLFontGL* getFontSansSerifHuge(); static LLFontGL* getFontSansSerifBold(); - static LLFontGL* getFontExtChar(); static LLFontGL* getFont(const LLFontDescriptor& desc); // Use with legacy names like "SANSSERIF_SMALL" or "OCRA" static LLFontGL* getFontByName(const std::string& name); diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 33a33af160..bc1a2f8887 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -597,6 +597,11 @@ LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& desc) <<" style=[" << ((S32) desc.getStyle()) << "]" << " size=[" << desc.getSize() << "]" << LL_ENDL; } + else + { + //generate glyphs for ASCII chars to avoid stalls later + fontp->generateASCIIglyphs(); + } return fontp; } } diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 43fedeca64..639d1fba32 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -62,6 +62,7 @@ BOOL gDebugSession = FALSE; BOOL gClothRipple = FALSE; BOOL gHeadlessClient = FALSE; +BOOL gNonInteractive = FALSE; BOOL gGLActive = FALSE; BOOL gGLDebugLoggingEnabled = TRUE; @@ -87,24 +88,32 @@ void APIENTRY gl_debug_callback(GLenum source, { if (gGLDebugLoggingEnabled) { - if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) - { - LL_WARNS() << "----- GL ERROR --------" << LL_ENDL; - } - else - { - LL_WARNS() << "----- GL WARNING -------" << LL_ENDL; - } - LL_WARNS() << "Type: " << std::hex << type << LL_ENDL; - LL_WARNS() << "ID: " << std::hex << id << LL_ENDL; - LL_WARNS() << "Severity: " << std::hex << severity << LL_ENDL; - LL_WARNS() << "Message: " << message << LL_ENDL; - LL_WARNS() << "-----------------------" << LL_ENDL; - if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) - { - LL_ERRS() << "Halting on GL Error" << LL_ENDL; - } -} + + if (severity != GL_DEBUG_SEVERITY_HIGH_ARB && + severity != GL_DEBUG_SEVERITY_MEDIUM_ARB && + severity != GL_DEBUG_SEVERITY_LOW_ARB) + { //suppress out-of-spec messages sent by nvidia driver (mostly vertexbuffer hints) + return; + } + + if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) + { + LL_WARNS() << "----- GL ERROR --------" << LL_ENDL; + } + else + { + LL_WARNS() << "----- GL WARNING -------" << LL_ENDL; + } + LL_WARNS() << "Type: " << std::hex << type << LL_ENDL; + LL_WARNS() << "ID: " << std::hex << id << LL_ENDL; + LL_WARNS() << "Severity: " << std::hex << severity << LL_ENDL; + LL_WARNS() << "Message: " << message << LL_ENDL; + LL_WARNS() << "-----------------------" << LL_ENDL; + if (severity == GL_DEBUG_SEVERITY_HIGH_ARB) + { + LL_ERRS() << "Halting on GL Error" << LL_ENDL; + } + } } #endif @@ -152,7 +161,6 @@ LLMatrix4 gGLObliqueProjectionInverse; std::list<LLGLUpdate*> LLGLUpdate::sGLQ; #if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS -// ATI prototypes #if LL_WINDOWS PFNGLGETSTRINGIPROC glGetStringi = NULL; @@ -199,21 +207,6 @@ PFNGLGETSYNCIVPROC glGetSynciv = NULL; PFNGLBUFFERPARAMETERIAPPLEPROC glBufferParameteriAPPLE = NULL; PFNGLFLUSHMAPPEDBUFFERRANGEAPPLEPROC glFlushMappedBufferRangeAPPLE = NULL; -// vertex object prototypes -PFNGLNEWOBJECTBUFFERATIPROC glNewObjectBufferATI = NULL; -PFNGLISOBJECTBUFFERATIPROC glIsObjectBufferATI = NULL; -PFNGLUPDATEOBJECTBUFFERATIPROC glUpdateObjectBufferATI = NULL; -PFNGLGETOBJECTBUFFERFVATIPROC glGetObjectBufferfvATI = NULL; -PFNGLGETOBJECTBUFFERIVATIPROC glGetObjectBufferivATI = NULL; -PFNGLFREEOBJECTBUFFERATIPROC glFreeObjectBufferATI = NULL; -PFNGLARRAYOBJECTATIPROC glArrayObjectATI = NULL; -PFNGLVERTEXATTRIBARRAYOBJECTATIPROC glVertexAttribArrayObjectATI = NULL; -PFNGLGETARRAYOBJECTFVATIPROC glGetArrayObjectfvATI = NULL; -PFNGLGETARRAYOBJECTIVATIPROC glGetArrayObjectivATI = NULL; -PFNGLVARIANTARRAYOBJECTATIPROC glVariantObjectArrayATI = NULL; -PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI = NULL; -PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI = NULL; - // GL_ARB_occlusion_query PFNGLGENQUERIESARBPROC glGenQueriesARB = NULL; PFNGLDELETEQUERIESARBPROC glDeleteQueriesARB = NULL; @@ -434,9 +427,6 @@ LLGLManager::LLGLManager() : mHasMapBufferRange(FALSE), mHasFlushBufferRange(FALSE), mHasPBuffer(FALSE), - mHasShaderObjects(FALSE), - mHasVertexShader(FALSE), - mHasFragmentShader(FALSE), mNumTextureImageUnits(0), mHasOcclusionQuery(FALSE), mHasTimerQuery(FALSE), @@ -456,14 +446,9 @@ LLGLManager::LLGLManager() : mHasCubeMap(FALSE), mHasDebugOutput(FALSE), - mIsATI(FALSE), + mIsAMD(FALSE), mIsNVIDIA(FALSE), mIsIntel(FALSE), - mIsGF2or4MX(FALSE), - mIsGF3(FALSE), - mIsGFFX(FALSE), - mATIOffsetVerticalLines(FALSE), - mATIOldDriver(FALSE), #if LL_DARWIN mIsMobileGF(FALSE), #endif @@ -559,7 +544,7 @@ bool LLGLManager::initGL() glGetIntegerv(GL_NUM_EXTENSIONS, &count); for (GLint i = 0; i < count; ++i) { - std::string ext((const char*) glGetStringi(GL_EXTENSIONS, i)); + std::string ext = ll_safe_string((const char*) glGetStringi(GL_EXTENSIONS, i)); str << ext << " "; LL_DEBUGS("GLExtensions") << ext << LL_ENDL; } @@ -622,59 +607,17 @@ bool LLGLManager::initGL() // Trailing space necessary to keep "nVidia Corpor_ati_on" cards // from being recognized as ATI. + // NOTE: AMD has been pretty good about not breaking this check, do not rename without good reason if (mGLVendor.substr(0,4) == "ATI ") { - mGLVendorShort = "ATI"; + mGLVendorShort = "AMD"; // *TODO: Fix this? - mIsATI = TRUE; - -#if LL_WINDOWS && !LL_MESA_HEADLESS - if (mDriverVersionRelease < 3842) - { - mATIOffsetVerticalLines = TRUE; - } -#endif // LL_WINDOWS - -#if (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS - // count any pre OpenGL 3.0 implementation as an old driver - if (mGLVersion < 3.f) - { - mATIOldDriver = TRUE; - } -#endif // (LL_WINDOWS || LL_LINUX) && !LL_MESA_HEADLESS + mIsAMD = TRUE; } else if (mGLVendor.find("NVIDIA ") != std::string::npos) { mGLVendorShort = "NVIDIA"; mIsNVIDIA = TRUE; - if ( mGLRenderer.find("GEFORCE4 MX") != std::string::npos - || mGLRenderer.find("GEFORCE2") != std::string::npos - || mGLRenderer.find("GEFORCE 2") != std::string::npos - || mGLRenderer.find("GEFORCE4 460 GO") != std::string::npos - || mGLRenderer.find("GEFORCE4 440 GO") != std::string::npos - || mGLRenderer.find("GEFORCE4 420 GO") != std::string::npos) - { - mIsGF2or4MX = TRUE; - } - else if (mGLRenderer.find("GEFORCE FX") != std::string::npos - || mGLRenderer.find("QUADRO FX") != std::string::npos - || mGLRenderer.find("NV34") != std::string::npos) - { - mIsGFFX = TRUE; - } - else if(mGLRenderer.find("GEFORCE3") != std::string::npos) - { - mIsGF3 = TRUE; - } -#if LL_DARWIN - else if ((mGLRenderer.find("9400M") != std::string::npos) - || (mGLRenderer.find("9600M") != std::string::npos) - || (mGLRenderer.find("9800M") != std::string::npos)) - { - mIsMobileGF = TRUE; - } -#endif - } else if (mGLVendor.find("INTEL") != std::string::npos #if LL_LINUX @@ -775,14 +718,9 @@ bool LLGLManager::initGL() stop_glerror(); - stop_glerror(); - - if (mHasFragmentShader) - { - GLint num_tex_image_units; - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units); - mNumTextureImageUnits = llmin(num_tex_image_units, 32); - } + GLint num_tex_image_units; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &num_tex_image_units); + mNumTextureImageUnits = llmin(num_tex_image_units, 32); if (LLRender::sGLCoreProfile) { @@ -819,26 +757,9 @@ bool LLGLManager::initGL() stop_glerror(); -#if LL_WINDOWS - if (mHasDebugOutput && gDebugGL) - { //setup debug output callback - //glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE); - glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); - glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - } -#endif - - stop_glerror(); - //HACK always disable texture multisample, use FXAA instead mHasTextureMultisample = FALSE; #if LL_WINDOWS - if (mIsATI) - { //using multisample textures on ATI results in black screen for some reason - mHasTextureMultisample = FALSE; - } - - if (mIsIntel && mGLVersion <= 3.f) { //never try to use framebuffer objects on older intel drivers (crashy) mHasFramebufferObject = FALSE; @@ -975,9 +896,9 @@ void LLGLManager::asLLSD(LLSD& info) info["has_map_buffer_range"] = mHasMapBufferRange; info["has_flush_buffer_range"] = mHasFlushBufferRange; info["has_pbuffer"] = mHasPBuffer; - info["has_shader_objects"] = mHasShaderObjects; - info["has_vertex_shader"] = mHasVertexShader; - info["has_fragment_shader"] = mHasFragmentShader; + info["has_shader_objects"] = std::string("Assumed TRUE"); // was mHasShaderObjects; + info["has_vertex_shader"] = std::string("Assumed TRUE"); // was mHasVertexShader; + info["has_fragment_shader"] = std::string("Assumed TRUE"); // was mHasFragmentShader; info["num_texture_image_units"] = mNumTextureImageUnits; info["has_occlusion_query"] = mHasOcclusionQuery; info["has_timer_query"] = mHasTimerQuery; @@ -1003,14 +924,9 @@ void LLGLManager::asLLSD(LLSD& info) info["has_texture_srgb_decode"] = mHasTexturesRGBDecode; // Vendor-specific extensions - info["is_ati"] = mIsATI; + info["is_ati"] = mIsAMD; // note, do not rename is_ati to is_amd without coordinating with DW info["is_nvidia"] = mIsNVIDIA; info["is_intel"] = mIsIntel; - info["is_gf2or4mx"] = mIsGF2or4MX; - info["is_gf3"] = mIsGF3; - info["is_gf_gfx"] = mIsGFFX; - info["ati_offset_vertical_lines"] = mATIOffsetVerticalLines; - info["ati_old_driver"] = mATIOldDriver; // Other fields info["has_requirements"] = mHasRequirements; @@ -1083,9 +999,6 @@ void LLGLManager::initExtensions() mHasCubeMap = FALSE; mHasOcclusionQuery = FALSE; mHasPointParameters = FALSE; - mHasShaderObjects = FALSE; - mHasVertexShader = FALSE; - mHasFragmentShader = FALSE; mHasTextureRectangle = FALSE; #else // LL_MESA_HEADLESS //important, gGLHExts.mSysExts is uninitialized until after glh_init_extensions is called mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); @@ -1105,8 +1018,9 @@ void LLGLManager::initExtensions() mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts); mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts); mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts); - //mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); - mHasDepthClamp = FALSE; + // NOTE: Using extensions breaks reflections when Shadows are set to projector. See: SL-16727 + //mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts); + mHasDepthClamp = FALSE; // mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad #ifdef GL_ARB_framebuffer_object mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts); @@ -1141,12 +1055,8 @@ void LLGLManager::initExtensions() mHasDebugOutput = ExtensionExists("GL_ARB_debug_output", gGLHExts.mSysExts); mHasTransformFeedback = mGLVersion >= 4.f ? TRUE : FALSE; #if !LL_DARWIN - mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); + mHasPointParameters = ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); #endif - mHasShaderObjects = ExtensionExists("GL_ARB_shader_objects", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); - mHasVertexShader = ExtensionExists("GL_ARB_vertex_program", gGLHExts.mSysExts) && ExtensionExists("GL_ARB_vertex_shader", gGLHExts.mSysExts) - && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); - mHasFragmentShader = ExtensionExists("GL_ARB_fragment_shader", gGLHExts.mSysExts) && (LLRender::sGLCoreProfile || ExtensionExists("GL_ARB_shading_language_100", gGLHExts.mSysExts)); #endif #if LL_LINUX @@ -1169,9 +1079,6 @@ void LLGLManager::initExtensions() mHasCubeMap = FALSE; mHasOcclusionQuery = FALSE; mHasPointParameters = FALSE; - mHasShaderObjects = FALSE; - mHasVertexShader = FALSE; - mHasFragmentShader = FALSE; LL_WARNS("RenderInit") << "GL extension support DISABLED via LL_GL_NOEXT" << LL_ENDL; } else if (getenv("LL_GL_BASICEXT")) /* Flawfinder: ignore */ @@ -1184,9 +1091,6 @@ void LLGLManager::initExtensions() mHasAnisotropic = FALSE; //mHasCubeMap = FALSE; // apparently fatal on Intel 915 & similar //mHasOcclusionQuery = FALSE; // source of many ATI system hangs - mHasShaderObjects = FALSE; - mHasVertexShader = FALSE; - mHasFragmentShader = FALSE; mHasBlendFuncSeparate = FALSE; LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL; } @@ -1208,9 +1112,6 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'j')) mHasCubeMap = FALSE;//S // if (strchr(blacklist,'k')) mHasATIVAO = FALSE;//S if (strchr(blacklist,'l')) mHasOcclusionQuery = FALSE; - if (strchr(blacklist,'m')) mHasShaderObjects = FALSE;//S - if (strchr(blacklist,'n')) mHasVertexShader = FALSE;//S - if (strchr(blacklist,'o')) mHasFragmentShader = FALSE;//S if (strchr(blacklist,'p')) mHasPointParameters = FALSE;//S if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S @@ -1257,18 +1158,6 @@ void LLGLManager::initExtensions() { LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_point_parameters" << LL_ENDL; } - if (!mHasShaderObjects) - { - LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_shader_objects" << LL_ENDL; - } - if (!mHasVertexShader) - { - LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_vertex_shader" << LL_ENDL; - } - if (!mHasFragmentShader) - { - LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL; - } if (!mHasBlendFuncSeparate) { LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_blend_func_separate" << LL_ENDL; @@ -1284,14 +1173,7 @@ void LLGLManager::initExtensions() LL_INFOS("RenderInit") << "Disabling mip-map generation for Intel GPUs" << LL_ENDL; mHasMipMapGeneration = FALSE; } -#if !LL_DARWIN - if (mIsATI && mHasMipMapGeneration) - { - LL_INFOS("RenderInit") << "Disabling mip-map generation for ATI GPUs (performance opt)" << LL_ENDL; - mHasMipMapGeneration = FALSE; - } -#endif - + // Misc glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange); glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange); @@ -1436,134 +1318,132 @@ void LLGLManager::initExtensions() glPointParameterfARB = (PFNGLPOINTPARAMETERFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfARB"); glPointParameterfvARB = (PFNGLPOINTPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvARB"); } - if (mHasShaderObjects) - { - glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB"); - glGetHandleARB = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB"); - glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDetachObjectARB"); - glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateShaderObjectARB"); - glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glShaderSourceARB"); - glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCompileShaderARB"); - glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateProgramObjectARB"); - glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glAttachObjectARB"); - glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glLinkProgramARB"); - glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUseProgramObjectARB"); - glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glValidateProgramARB"); - glUniform1fARB = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fARB"); - glUniform2fARB = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fARB"); - glUniform3fARB = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fARB"); - glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fARB"); - glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1iARB"); - glUniform2iARB = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2iARB"); - glUniform3iARB = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3iARB"); - glUniform4iARB = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4iARB"); - glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fvARB"); - glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fvARB"); - glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fvARB"); - glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fvARB"); - glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1ivARB"); - glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2ivARB"); - glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3ivARB"); - glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB"); - glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB"); - glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB"); - glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3x4fv"); - glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB"); - glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB"); - glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB"); - glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInfoLogARB"); - glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttachedObjectsARB"); - glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformLocationARB"); - glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformARB"); - glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformfvARB"); - glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformivARB"); - glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetShaderSourceARB"); - } - if (mHasVertexShader) - { - LL_INFOS() << "initExtensions() VertexShader-related procs..." << LL_ENDL; - - // nSight doesn't support use of ARB funcs that have been normalized in the API - if (!LLRender::sNsightDebugSupport) - { - glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocationARB"); - glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocationARB"); - } - else - { - glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocation"); - glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocation"); - } - glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveAttribARB"); - glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB"); - glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB"); - glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB"); - glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB"); - glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB"); - glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB"); - glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB"); - glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB"); - glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB"); - glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB"); - glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB"); - glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB"); - glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB"); - glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB"); - glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB"); - glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB"); - glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB"); - glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB"); - glVertexAttrib4nbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nbvARB"); - glVertexAttrib4nivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nivARB"); - glVertexAttrib4nsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nsvARB"); - glVertexAttrib4nubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubARB"); - glVertexAttrib4nubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubvARB"); - glVertexAttrib4nuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nuivARB"); - glVertexAttrib4nusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nusvARB"); - glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB"); - glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB"); - glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB"); - glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB"); - glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB"); - glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB"); - glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB"); - glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB"); - glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB"); - glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB"); - glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB"); - glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB"); - glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribIPointer"); - glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB"); - glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB"); - glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB"); - glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB"); - glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB"); - glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB"); - glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB"); - glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB"); - glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB"); - glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB"); - glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB"); - glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB"); - glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB"); - glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB"); - glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB"); - glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB"); - glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB"); - glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB"); - glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB"); - glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB"); - glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB"); - glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB"); - glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB"); - glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glgetVertexAttribPointervARB"); - glIsProgramARB = (PFNGLISPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB"); - } - LL_DEBUGS("RenderInit") << "GL Probe: Got symbols" << LL_ENDL; + // Assume shader capabilities + glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteObjectARB"); + glGetHandleARB = (PFNGLGETHANDLEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetHandleARB"); + glDetachObjectARB = (PFNGLDETACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDetachObjectARB"); + glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateShaderObjectARB"); + glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glShaderSourceARB"); + glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCompileShaderARB"); + glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glCreateProgramObjectARB"); + glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glAttachObjectARB"); + glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glLinkProgramARB"); + glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUseProgramObjectARB"); + glValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glValidateProgramARB"); + glUniform1fARB = (PFNGLUNIFORM1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fARB"); + glUniform2fARB = (PFNGLUNIFORM2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fARB"); + glUniform3fARB = (PFNGLUNIFORM3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fARB"); + glUniform4fARB = (PFNGLUNIFORM4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fARB"); + glUniform1iARB = (PFNGLUNIFORM1IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1iARB"); + glUniform2iARB = (PFNGLUNIFORM2IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2iARB"); + glUniform3iARB = (PFNGLUNIFORM3IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3iARB"); + glUniform4iARB = (PFNGLUNIFORM4IARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4iARB"); + glUniform1fvARB = (PFNGLUNIFORM1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1fvARB"); + glUniform2fvARB = (PFNGLUNIFORM2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2fvARB"); + glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3fvARB"); + glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4fvARB"); + glUniform1ivARB = (PFNGLUNIFORM1IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform1ivARB"); + glUniform2ivARB = (PFNGLUNIFORM2IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform2ivARB"); + glUniform3ivARB = (PFNGLUNIFORM3IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform3ivARB"); + glUniform4ivARB = (PFNGLUNIFORM4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniform4ivARB"); + glUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix2fvARB"); + glUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3fvARB"); + glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix3x4fv"); + glUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glUniformMatrix4fvARB"); + glGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterfvARB"); + glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetObjectParameterivARB"); + glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetInfoLogARB"); + glGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttachedObjectsARB"); + glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformLocationARB"); + glGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveUniformARB"); + glGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformfvARB"); + glGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetUniformivARB"); + glGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetShaderSourceARB"); + + LL_INFOS() << "initExtensions() VertexShader-related procs..." << LL_ENDL; + + // nSight doesn't support use of ARB funcs that have been normalized in the API + if (!LLRender::sNsightDebugSupport) + { + glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocationARB"); + glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocationARB"); + } + else + { + glGetAttribLocationARB = (PFNGLGETATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetAttribLocation"); + glBindAttribLocationARB = (PFNGLBINDATTRIBLOCATIONARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindAttribLocation"); + } + + glGetActiveAttribARB = (PFNGLGETACTIVEATTRIBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetActiveAttribARB"); + glVertexAttrib1dARB = (PFNGLVERTEXATTRIB1DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB"); + glVertexAttrib1dvARB = (PFNGLVERTEXATTRIB1DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB"); + glVertexAttrib1fARB = (PFNGLVERTEXATTRIB1FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB"); + glVertexAttrib1fvARB = (PFNGLVERTEXATTRIB1FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB"); + glVertexAttrib1sARB = (PFNGLVERTEXATTRIB1SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB"); + glVertexAttrib1svARB = (PFNGLVERTEXATTRIB1SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB"); + glVertexAttrib2dARB = (PFNGLVERTEXATTRIB2DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB"); + glVertexAttrib2dvARB = (PFNGLVERTEXATTRIB2DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB"); + glVertexAttrib2fARB = (PFNGLVERTEXATTRIB2FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB"); + glVertexAttrib2fvARB = (PFNGLVERTEXATTRIB2FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB"); + glVertexAttrib2sARB = (PFNGLVERTEXATTRIB2SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB"); + glVertexAttrib2svARB = (PFNGLVERTEXATTRIB2SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB"); + glVertexAttrib3dARB = (PFNGLVERTEXATTRIB3DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB"); + glVertexAttrib3dvARB = (PFNGLVERTEXATTRIB3DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB"); + glVertexAttrib3fARB = (PFNGLVERTEXATTRIB3FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB"); + glVertexAttrib3fvARB = (PFNGLVERTEXATTRIB3FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB"); + glVertexAttrib3sARB = (PFNGLVERTEXATTRIB3SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB"); + glVertexAttrib3svARB = (PFNGLVERTEXATTRIB3SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB"); + glVertexAttrib4nbvARB = (PFNGLVERTEXATTRIB4NBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nbvARB"); + glVertexAttrib4nivARB = (PFNGLVERTEXATTRIB4NIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nivARB"); + glVertexAttrib4nsvARB = (PFNGLVERTEXATTRIB4NSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nsvARB"); + glVertexAttrib4nubARB = (PFNGLVERTEXATTRIB4NUBARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubARB"); + glVertexAttrib4nubvARB = (PFNGLVERTEXATTRIB4NUBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nubvARB"); + glVertexAttrib4nuivARB = (PFNGLVERTEXATTRIB4NUIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nuivARB"); + glVertexAttrib4nusvARB = (PFNGLVERTEXATTRIB4NUSVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4nusvARB"); + glVertexAttrib4bvARB = (PFNGLVERTEXATTRIB4BVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB"); + glVertexAttrib4dARB = (PFNGLVERTEXATTRIB4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB"); + glVertexAttrib4dvARB = (PFNGLVERTEXATTRIB4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB"); + glVertexAttrib4fARB = (PFNGLVERTEXATTRIB4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB"); + glVertexAttrib4fvARB = (PFNGLVERTEXATTRIB4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB"); + glVertexAttrib4ivARB = (PFNGLVERTEXATTRIB4IVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB"); + glVertexAttrib4sARB = (PFNGLVERTEXATTRIB4SARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB"); + glVertexAttrib4svARB = (PFNGLVERTEXATTRIB4SVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB"); + glVertexAttrib4ubvARB = (PFNGLVERTEXATTRIB4UBVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB"); + glVertexAttrib4uivARB = (PFNGLVERTEXATTRIB4UIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB"); + glVertexAttrib4usvARB = (PFNGLVERTEXATTRIB4USVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB"); + glVertexAttribPointerARB = (PFNGLVERTEXATTRIBPOINTERARBPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB"); + glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) GLH_EXT_GET_PROC_ADDRESS("glVertexAttribIPointer"); + glEnableVertexAttribArrayARB = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB"); + glDisableVertexAttribArrayARB = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB"); + glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB"); + glBindProgramARB = (PFNGLBINDPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB"); + glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB"); + glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB"); + glProgramEnvParameter4dARB = (PFNGLPROGRAMENVPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB"); + glProgramEnvParameter4dvARB = (PFNGLPROGRAMENVPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB"); + glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB"); + glProgramEnvParameter4fvARB = (PFNGLPROGRAMENVPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB"); + glProgramLocalParameter4dARB = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB"); + glProgramLocalParameter4dvARB = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB"); + glProgramLocalParameter4fARB = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB"); + glProgramLocalParameter4fvARB = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB"); + glGetProgramEnvParameterdvARB = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB"); + glGetProgramEnvParameterfvARB = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB"); + glGetProgramLocalParameterdvARB = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB"); + glGetProgramLocalParameterfvARB = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB"); + glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB"); + glGetProgramStringARB = (PFNGLGETPROGRAMSTRINGARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB"); + glGetVertexAttribdvARB = (PFNGLGETVERTEXATTRIBDVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB"); + glGetVertexAttribfvARB = (PFNGLGETVERTEXATTRIBFVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB"); + glGetVertexAttribivARB = (PFNGLGETVERTEXATTRIBIVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB"); + glGetVertexAttribPointervARB = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC) GLH_EXT_GET_PROC_ADDRESS("glgetVertexAttribPointervARB"); + glIsProgramARB = (PFNGLISPROGRAMARBPROC) GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB"); + + LL_DEBUGS("RenderInit") << "GL Probe: Got symbols" << LL_ENDL; #endif - mInited = TRUE; + mInited = TRUE; } void rotate_quat(LLQuaternion& rotation) @@ -1974,206 +1854,30 @@ void LLGLState::checkTextureChannels(const std::string& msg) #endif } -void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) -{ - if (!gDebugGL || LLGLSLShader::sNoFixedFunction) - { - return; - } - - stop_glerror(); - BOOL error = FALSE; - - GLint active_texture; - glGetIntegerv(GL_CLIENT_ACTIVE_TEXTURE_ARB, &active_texture); - - if (active_texture != GL_TEXTURE0_ARB) - { - LL_WARNS() << "Client active texture corrupted: " << active_texture << LL_ENDL; - if (gDebugSession) - { - gFailLog << "Client active texture corrupted: " << active_texture << std::endl; - } - error = TRUE; - } - - /*glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &active_texture); - if (active_texture != GL_TEXTURE0_ARB) - { - LL_WARNS() << "Active texture corrupted: " << active_texture << LL_ENDL; - if (gDebugSession) - { - gFailLog << "Active texture corrupted: " << active_texture << std::endl; - } - error = TRUE; - }*/ - - static const char* label[] = - { - "GL_VERTEX_ARRAY", - "GL_NORMAL_ARRAY", - "GL_COLOR_ARRAY", - "GL_TEXTURE_COORD_ARRAY" - }; - - static GLint value[] = - { - GL_VERTEX_ARRAY, - GL_NORMAL_ARRAY, - GL_COLOR_ARRAY, - GL_TEXTURE_COORD_ARRAY - }; - - static const U32 mask[] = - { //copied from llvertexbuffer.h - 0x0001, //MAP_VERTEX, - 0x0002, //MAP_NORMAL, - 0x0010, //MAP_COLOR, - 0x0004, //MAP_TEXCOORD - }; - - - for (S32 j = 1; j < 4; j++) - { - if (glIsEnabled(value[j])) - { - if (!(mask[j] & data_mask)) - { - error = TRUE; - LL_WARNS("RenderState") << "GL still has " << label[j] << " enabled." << LL_ENDL; - if (gDebugSession) - { - gFailLog << "GL still has " << label[j] << " enabled." << std::endl; - } - } - } - else - { - if (mask[j] & data_mask) - { - error = TRUE; - LL_WARNS("RenderState") << "GL does not have " << label[j] << " enabled." << LL_ENDL; - if (gDebugSession) - { - gFailLog << "GL does not have " << label[j] << " enabled." << std::endl; - } - } - } - } - - glClientActiveTextureARB(GL_TEXTURE1_ARB); - gGL.getTexUnit(1)->activate(); - if (glIsEnabled(GL_TEXTURE_COORD_ARRAY)) - { - if (!(data_mask & 0x0008)) - { - error = TRUE; - LL_WARNS("RenderState") << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL; - if (gDebugSession) - { - gFailLog << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << std::endl; - } - } - } - else - { - if (data_mask & 0x0008) - { - error = TRUE; - LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL; - if (gDebugSession) - { - gFailLog << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << std::endl; - } - } - } - - /*if (glIsEnabled(GL_TEXTURE_2D)) - { - if (!(data_mask & 0x0008)) - { - error = TRUE; - LL_WARNS("RenderState") << "GL still has GL_TEXTURE_2D enabled on channel 1." << LL_ENDL; - if (gDebugSession) - { - gFailLog << "GL still has GL_TEXTURE_2D enabled on channel 1." << std::endl; - } - } - } - else - { - if (data_mask & 0x0008) - { - error = TRUE; - LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_2D enabled on channel 1." << LL_ENDL; - if (gDebugSession) - { - gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl; - } - } - }*/ - - glClientActiveTextureARB(GL_TEXTURE0_ARB); - gGL.getTexUnit(0)->activate(); - - if (gGLManager.mHasVertexShader && LLGLSLShader::sNoFixedFunction) - { //make sure vertex attribs are all disabled - GLint count; - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS_ARB, &count); - for (GLint i = 0; i < count; i++) - { - GLint enabled; - glGetVertexAttribivARB((GLuint) i, GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB, &enabled); - if (enabled) - { - error = TRUE; - LL_WARNS("RenderState") << "GL still has vertex attrib array " << i << " enabled." << LL_ENDL; - if (gDebugSession) - { - gFailLog << "GL still has vertex attrib array " << i << " enabled." << std::endl; - } - } - } - } - - if (error) - { - if (gDebugSession) - { - ll_fail("LLGLState::checkClientArrays failed."); - } - else - { - LL_GL_ERRS << "GL client array corruption detected. " << msg << LL_ENDL; - } - } -} - /////////////////////////////////////////////////////////////////////// LLGLState::LLGLState(LLGLenum state, S32 enabled) : mState(state), mWasEnabled(FALSE), mIsEnabled(FALSE) { - if (LLGLSLShader::sNoFixedFunction) - { //always ignore state that's deprecated post GL 3.0 - switch (state) - { - case GL_ALPHA_TEST: - case GL_NORMALIZE: - case GL_TEXTURE_GEN_R: - case GL_TEXTURE_GEN_S: - case GL_TEXTURE_GEN_T: - case GL_TEXTURE_GEN_Q: - case GL_LIGHTING: - case GL_COLOR_MATERIAL: - case GL_FOG: - case GL_LINE_STIPPLE: - case GL_POLYGON_STIPPLE: - mState = 0; - break; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + switch (state) + { + case GL_ALPHA_TEST: + case GL_NORMALIZE: + case GL_TEXTURE_GEN_R: + case GL_TEXTURE_GEN_S: + case GL_TEXTURE_GEN_T: + case GL_TEXTURE_GEN_Q: + case GL_LIGHTING: + case GL_COLOR_MATERIAL: + case GL_FOG: + case GL_LINE_STIPPLE: + case GL_POLYGON_STIPPLE: + mState = 0; + break; } + stop_glerror(); if (mState) { @@ -2212,6 +1916,7 @@ void LLGLState::setEnabled(S32 enabled) LLGLState::~LLGLState() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; stop_glerror(); if (mState) { @@ -2398,7 +2103,8 @@ LLGLUserClipPlane::LLGLUserClipPlane(const LLPlane& p, const glh::matrix4f& mode mModelview = modelview; mProjection = projection; - setPlane(p[0], p[1], p[2], p[3]); + //flip incoming LLPlane to get consistent behavior compared to frustum culling + setPlane(-p[0], -p[1], -p[2], -p[3]); } } @@ -2444,94 +2150,6 @@ LLGLUserClipPlane::~LLGLUserClipPlane() disable(); } -LLGLNamePool::LLGLNamePool() -{ -} - -LLGLNamePool::~LLGLNamePool() -{ -} - -void LLGLNamePool::upkeep() -{ - std::sort(mNameList.begin(), mNameList.end(), CompareUsed()); -} - -void LLGLNamePool::cleanup() -{ - for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) - { - releaseName(iter->name); - } - - mNameList.clear(); -} - -GLuint LLGLNamePool::allocate() -{ -#if LL_GL_NAME_POOLING - for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) - { - if (!iter->used) - { - iter->used = TRUE; - return iter->name; - } - } - - NameEntry entry; - entry.name = allocateName(); - entry.used = TRUE; - mNameList.push_back(entry); - - return entry.name; -#else - return allocateName(); -#endif -} - -void LLGLNamePool::release(GLuint name) -{ -#if LL_GL_NAME_POOLING - for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter) - { - if (iter->name == name) - { - if (iter->used) - { - iter->used = FALSE; - return; - } - else - { - LL_ERRS() << "Attempted to release a pooled name that is not in use!" << LL_ENDL; - } - } - } - LL_ERRS() << "Attempted to release a non pooled name!" << LL_ENDL; -#else - releaseName(name); -#endif -} - -//static -void LLGLNamePool::upkeepPools() -{ - for (auto& pool : instance_snapshot()) - { - pool.upkeep(); - } -} - -//static -void LLGLNamePool::cleanupPools() -{ - for (auto& pool : instance_snapshot()) - { - pool.cleanup(); - } -} - LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func) : mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled) { @@ -2723,22 +2341,10 @@ LLGLSPipelineSkyBox::LLGLSPipelineSkyBox() , mCullFace(GL_CULL_FACE) , mSquashClip() { - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHTING); - glDisable(GL_FOG); - glDisable(GL_CLIP_PLANE0); - } } LLGLSPipelineSkyBox::~LLGLSPipelineSkyBox() { - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHTING); - glEnable(GL_FOG); - glEnable(GL_CLIP_PLANE0); - } } LLGLSPipelineDepthTestSkyBox::LLGLSPipelineDepthTestSkyBox(bool depth_test, bool depth_write) @@ -2765,3 +2371,4 @@ extern "C" } #endif + diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index a07e2d9bb0..52338364e6 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -94,9 +94,6 @@ public: BOOL mHasMapBufferRange; BOOL mHasFlushBufferRange; BOOL mHasPBuffer; - BOOL mHasShaderObjects; - BOOL mHasVertexShader; - BOOL mHasFragmentShader; S32 mNumTextureImageUnits; BOOL mHasOcclusionQuery; BOOL mHasTimerQuery; @@ -122,14 +119,9 @@ public: BOOL mHasTexturesRGBDecode; // Vendor-specific extensions - BOOL mIsATI; + BOOL mIsAMD; BOOL mIsNVIDIA; BOOL mIsIntel; - BOOL mIsGF2or4MX; - BOOL mIsGF3; - BOOL mIsGFFX; - BOOL mATIOffsetVerticalLines; - BOOL mATIOldDriver; #if LL_DARWIN // Needed to distinguish problem cards on older Macs that break with Materials @@ -269,7 +261,6 @@ public: static void dumpStates(); static void checkStates(const std::string& msg = ""); static void checkTextureChannels(const std::string& msg = ""); - static void checkClientArrays(const std::string& msg = "", U32 data_mask = 0); protected: static boost::unordered_map<LLGLenum, LLGLboolean> sStateMap; @@ -376,51 +367,6 @@ public: }; /* - Generic pooling scheme for things which use GL names (used for occlusion queries and vertex buffer objects). - Prevents thrashing of GL name caches by avoiding calls to glGenFoo and glDeleteFoo. -*/ -class LLGLNamePool : public LLInstanceTracker<LLGLNamePool> -{ -public: - typedef LLInstanceTracker<LLGLNamePool> tracker_t; - - struct NameEntry - { - GLuint name; - BOOL used; - }; - - struct CompareUsed - { - bool operator()(const NameEntry& lhs, const NameEntry& rhs) - { - return lhs.used < rhs.used; //FALSE entries first - } - }; - - typedef std::vector<NameEntry> name_list_t; - name_list_t mNameList; - - LLGLNamePool(); - virtual ~LLGLNamePool(); - - void upkeep(); - void cleanup(); - - GLuint allocate(); - void release(GLuint name); - - static void upkeepPools(); - static void cleanupPools(); - -protected: - typedef std::vector<LLGLNamePool*> pool_list_t; - - virtual GLuint allocateName() = 0; - virtual void releaseName(GLuint name) = 0; -}; - -/* Interface for objects that need periodic GL updates applied to them. Used to synchronize GL updates with GL thread. */ @@ -488,6 +434,7 @@ void parse_gl_version( S32* major, S32* minor, S32* release, std::string* vendor extern BOOL gClothRipple; extern BOOL gHeadlessClient; +extern BOOL gNonInteractive; extern BOOL gGLActive; // Deal with changing glext.h definitions for newer SDK versions, specifically diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h index 6bca3623e0..3d93cc0762 100644 --- a/indra/llrender/llglheaders.h +++ b/indra/llrender/llglheaders.h @@ -812,4 +812,23 @@ extern void glGetBufferPointervARB (GLenum, GLenum, GLvoid* *); #define GL_RENDERBUFFER_FREE_MEMORY_ATI 0x87FD #endif +#if defined(TRACY_ENABLE) && LL_PROFILER_ENABLE_TRACY_OPENGL + // Tracy uses the following: + // glGenQueries + // glGetQueryiv + // glGetQueryObjectiv + #define glGenQueries glGenQueriesARB + #define glGetQueryiv glGetQueryivARB + #define glGetQueryObjectiv glGetQueryObjectivARB + #include <tracy/TracyOpenGL.hpp> + + #define LL_PROFILER_GPU_ZONEC(name,color) TracyGpuZoneC(name,color); + #define LL_PROFILER_GPU_COLLECT TracyGpuCollect + #define LL_PROFILER_GPU_CONTEXT TracyGpuContext +#else + #define LL_PROFILER_GPU_ZONEC(name,color) (void)name;(void)color; + #define LL_PROFILER_GPU_COLLECT + #define LL_PROFILER_GPU_CONTEXT +#endif + #endif // LL_LLGLHEADERS_H diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 4351f6e2c8..185c1450c8 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -50,7 +50,6 @@ using std::string; GLhandleARB LLGLSLShader::sCurBoundShader = 0; LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL; S32 LLGLSLShader::sIndexedTextureChannels = 0; -bool LLGLSLShader::sNoFixedFunction = false; bool LLGLSLShader::sProfileEnabled = false; std::set<LLGLSLShader*> LLGLSLShader::sInstances; U64 LLGLSLShader::sTotalTimeElapsed = 0; @@ -208,6 +207,7 @@ void LLGLSLShader::dumpStats() //static void LLGLSLShader::startProfile() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; if (sProfileEnabled && sCurBoundShaderPtr) { sCurBoundShaderPtr->placeProfileQuery(); @@ -218,6 +218,7 @@ void LLGLSLShader::startProfile() //static void LLGLSLShader::stopProfile(U32 count, U32 mode) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; if (sProfileEnabled && sCurBoundShaderPtr) { sCurBoundShaderPtr->readProfileQuery(count, mode); @@ -384,6 +385,8 @@ BOOL LLGLSLShader::createShader(std::vector<LLStaticHashedString> * attributes, U32 varying_count, const char** varyings) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + unloadInternal(); sInstances.insert(this); @@ -588,6 +591,8 @@ void LLGLSLShader::attachObjects(GLhandleARB* objects, S32 count) BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attributes) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + //before linking, make sure reserved attributes always have consistent locations for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++) { @@ -649,6 +654,8 @@ BOOL LLGLSLShader::mapAttributes(const std::vector<LLStaticHashedString> * attri void LLGLSLShader::mapUniform(GLint index, const vector<LLStaticHashedString> * uniforms) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if (index == -1) { return; @@ -770,6 +777,8 @@ void LLGLSLShader::removePermutation(std::string name) GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) || type == GL_SAMPLER_2D_MULTISAMPLE) { //this here is a texture @@ -782,7 +791,9 @@ GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type) BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms) { - BOOL res = TRUE; + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + BOOL res = TRUE; mTotalUniformSize = 0; mActiveTextureChannels = 0; @@ -925,6 +936,8 @@ BOOL LLGLSLShader::mapUniforms(const vector<LLStaticHashedString> * uniforms) BOOL LLGLSLShader::link(BOOL suppress_errors) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + BOOL success = LLShaderMgr::instance()->linkProgramObject(mProgramObject, suppress_errors); if (!success && !suppress_errors) @@ -937,56 +950,65 @@ BOOL LLGLSLShader::link(BOOL suppress_errors) void LLGLSLShader::bind() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + gGL.flush(); - if (gGLManager.mHasShaderObjects) + + if (sCurBoundShader != mProgramObject) // Don't re-bind current shader { LLVertexBuffer::unbind(); glUseProgramObjectARB(mProgramObject); sCurBoundShader = mProgramObject; sCurBoundShaderPtr = this; - if (mUniformsDirty) - { - LLShaderMgr::instance()->updateShaderUniforms(this); - mUniformsDirty = FALSE; - } + } + + if (mUniformsDirty) + { + LLShaderMgr::instance()->updateShaderUniforms(this); + mUniformsDirty = FALSE; } } -void LLGLSLShader::unbind() +void LLGLSLShader::bind(bool rigged) { - gGL.flush(); - if (gGLManager.mHasShaderObjects) + if (rigged) { - stop_glerror(); - if (gGLManager.mIsNVIDIA) - { - for (U32 i = 0; i < mAttribute.size(); ++i) - { - vertexAttrib4f(i, 0,0,0,1); - stop_glerror(); - } - } - LLVertexBuffer::unbind(); - glUseProgramObjectARB(0); - sCurBoundShader = 0; - sCurBoundShaderPtr = NULL; - stop_glerror(); + llassert(mRiggedVariant); + mRiggedVariant->bind(); + } + else + { + bind(); } } +void LLGLSLShader::unbind() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + gGL.flush(); + stop_glerror(); + LLVertexBuffer::unbind(); + glUseProgramObjectARB(0); + sCurBoundShader = 0; + sCurBoundShaderPtr = NULL; + stop_glerror(); +} + void LLGLSLShader::bindNoShader(void) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + LLVertexBuffer::unbind(); - if (gGLManager.mHasShaderObjects) - { - glUseProgramObjectARB(0); - sCurBoundShader = 0; - sCurBoundShaderPtr = NULL; - } + glUseProgramObjectARB(0); + sCurBoundShader = 0; + sCurBoundShaderPtr = NULL; } S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + S32 channel = 0; channel = getUniformLocation(uniform); @@ -995,6 +1017,8 @@ S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LL S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if (uniform < 0 || uniform >= (S32)mTexture.size()) { LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; @@ -1005,7 +1029,7 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextu if (uniform > -1) { - gGL.getTexUnit(uniform)->bind(texture, mode); + gGL.getTexUnit(uniform)->bindFast(texture); gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace); } @@ -1014,6 +1038,8 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextu S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + S32 channel = 0; channel = getUniformLocation(uniform); @@ -1022,6 +1048,8 @@ S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureT S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if (uniform < 0 || uniform >= (S32)mTexture.size()) { LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; @@ -1032,7 +1060,7 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) if (uniform > -1) { - gGL.getTexUnit(uniform)->unbind(mode); + gGL.getTexUnit(uniform)->unbindFast(mode); } return uniform; @@ -1040,6 +1068,8 @@ S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode) S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if (uniform < 0 || uniform >= (S32)mTexture.size()) { LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; @@ -1057,6 +1087,8 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if (uniform < 0 || uniform >= (S32)mTexture.size()) { LL_SHADER_UNIFORM_ERRS() << "Uniform out of range: " << uniform << LL_ENDL; @@ -1084,6 +1116,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe void LLGLSLShader::uniform1i(U32 index, GLint x) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER if (mProgramObject) { if (mUniform.size() <= index) @@ -1094,7 +1127,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); if (iter == mValue.end() || iter->second.mV[0] != x) { glUniform1iARB(mUniform[index], x); @@ -1106,6 +1139,7 @@ void LLGLSLShader::uniform1i(U32 index, GLint x) void LLGLSLShader::uniform1f(U32 index, GLfloat x) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER if (mProgramObject) { if (mUniform.size() <= index) @@ -1116,7 +1150,7 @@ void LLGLSLShader::uniform1f(U32 index, GLfloat x) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); if (iter == mValue.end() || iter->second.mV[0] != x) { glUniform1fARB(mUniform[index], x); @@ -1138,7 +1172,7 @@ void LLGLSLShader::uniform2f(U32 index, GLfloat x, GLfloat y) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); LLVector4 vec(x,y,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { @@ -1161,7 +1195,7 @@ void LLGLSLShader::uniform3f(U32 index, GLfloat x, GLfloat y, GLfloat z) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); LLVector4 vec(x,y,z,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { @@ -1184,7 +1218,7 @@ void LLGLSLShader::uniform4f(U32 index, GLfloat x, GLfloat y, GLfloat z, GLfloat if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); LLVector4 vec(x,y,z,w); if (iter == mValue.end() || shouldChange(iter->second,vec)) { @@ -1207,7 +1241,7 @@ void LLGLSLShader::uniform1iv(U32 index, U32 count, const GLint* v) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); LLVector4 vec(v[0],0.f,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { @@ -1230,7 +1264,7 @@ void LLGLSLShader::uniform1fv(U32 index, U32 count, const GLfloat* v) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); LLVector4 vec(v[0],0.f,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { @@ -1253,7 +1287,7 @@ void LLGLSLShader::uniform2fv(U32 index, U32 count, const GLfloat* v) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); LLVector4 vec(v[0],v[1],0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { @@ -1276,7 +1310,7 @@ void LLGLSLShader::uniform3fv(U32 index, U32 count, const GLfloat* v) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); LLVector4 vec(v[0],v[1],v[2],0.f); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { @@ -1299,10 +1333,11 @@ void LLGLSLShader::uniform4fv(U32 index, U32 count, const GLfloat* v) if (mUniform[index] >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(mUniform[index]); + const auto& iter = mValue.find(mUniform[index]); LLVector4 vec(v[0],v[1],v[2],v[3]); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; glUniform4fvARB(mUniform[index], count, v); mValue[mUniform[index]] = vec; } @@ -1346,6 +1381,8 @@ void LLGLSLShader::uniformMatrix3fv(U32 index, U32 count, GLboolean transpose, c void LLGLSLShader::uniformMatrix3x4fv(U32 index, U32 count, GLboolean transpose, const GLfloat *v) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if (mProgramObject) { if (mUniform.size() <= index) @@ -1380,6 +1417,8 @@ void LLGLSLShader::uniformMatrix4fv(U32 index, U32 count, GLboolean transpose, c GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint ret = -1; if (mProgramObject) { @@ -1404,10 +1443,16 @@ GLint LLGLSLShader::getUniformLocation(const LLStaticHashedString& uniform) GLint LLGLSLShader::getUniformLocation(U32 index) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + GLint ret = -1; if (mProgramObject) { - llassert(index < mUniform.size()); + if (index >= mUniform.size()) + { + LL_WARNS_ONCE("Shader") << "Uniform index " << index << " out of bounds " << (S32)mUniform.size() << LL_ENDL; + return ret; + } return mUniform[index]; } @@ -1416,6 +1461,8 @@ GLint LLGLSLShader::getUniformLocation(U32 index) GLint LLGLSLShader::getAttribLocation(U32 attrib) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + if (attrib < mAttribute.size()) { return mAttribute[attrib]; @@ -1432,7 +1479,7 @@ void LLGLSLShader::uniform1i(const LLStaticHashedString& uniform, GLint v) if (location >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); LLVector4 vec(v,0.f,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { @@ -1448,7 +1495,7 @@ void LLGLSLShader::uniform2i(const LLStaticHashedString& uniform, GLint i, GLint if (location >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); LLVector4 vec(i,j,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { @@ -1465,7 +1512,7 @@ void LLGLSLShader::uniform1f(const LLStaticHashedString& uniform, GLfloat v) if (location >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); LLVector4 vec(v,0.f,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { @@ -1481,7 +1528,7 @@ void LLGLSLShader::uniform2f(const LLStaticHashedString& uniform, GLfloat x, GLf if (location >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); LLVector4 vec(x,y,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { @@ -1498,7 +1545,7 @@ void LLGLSLShader::uniform3f(const LLStaticHashedString& uniform, GLfloat x, GLf if (location >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); LLVector4 vec(x,y,z,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec)) { @@ -1514,7 +1561,7 @@ void LLGLSLShader::uniform1fv(const LLStaticHashedString& uniform, U32 count, co if (location >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); LLVector4 vec(v[0],0.f,0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { @@ -1530,7 +1577,7 @@ void LLGLSLShader::uniform2fv(const LLStaticHashedString& uniform, U32 count, co if (location >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); LLVector4 vec(v[0],v[1],0.f,0.f); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { @@ -1546,7 +1593,7 @@ void LLGLSLShader::uniform3fv(const LLStaticHashedString& uniform, U32 count, co if (location >= 0) { - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); LLVector4 vec(v[0],v[1],v[2],0.f); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { @@ -1563,12 +1610,11 @@ void LLGLSLShader::uniform4fv(const LLStaticHashedString& uniform, U32 count, co if (location >= 0) { LLVector4 vec(v); - std::map<GLint, LLVector4>::iterator iter = mValue.find(location); + const auto& iter = mValue.find(location); if (iter == mValue.end() || shouldChange(iter->second,vec) || count != 1) { - stop_glerror(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; glUniform4fvARB(location, count, v); - stop_glerror(); mValue[location] = vec; } } @@ -1608,3 +1654,27 @@ void LLGLSLShader::setMinimumAlpha(F32 minimum) gGL.flush(); uniform1f(LLShaderMgr::MINIMUM_ALPHA, minimum); } + +void LLShaderUniforms::apply(LLGLSLShader* shader) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + for (auto& uniform : mIntegers) + { + shader->uniform1i(uniform.mUniform, uniform.mValue); + } + + for (auto& uniform : mFloats) + { + shader->uniform1f(uniform.mUniform, uniform.mValue); + } + + for (auto& uniform : mVectors) + { + shader->uniform4fv(uniform.mUniform, 1, uniform.mValue.mV); + } + + for (auto& uniform : mVector3s) + { + shader->uniform3fv(uniform.mUniform, 1, uniform.mValue.mV); + } +} diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 7cf6d3c941..85e83dbcb9 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -30,6 +30,7 @@ #include "llgl.h" #include "llrender.h" #include "llstaticstringtable.h" +#include <unordered_map> class LLShaderFeatures { @@ -64,16 +65,79 @@ public: LLShaderFeatures(); }; +// ============= Structure for caching shader uniforms =============== +class LLGLSLShader; + +class LLShaderUniforms +{ +public: + + template<typename T> + struct UniformSetting + { + S32 mUniform; + T mValue; + }; + + typedef UniformSetting<S32> IntSetting; + typedef UniformSetting<F32> FloatSetting; + typedef UniformSetting<LLVector4> VectorSetting; + typedef UniformSetting<LLVector3> Vector3Setting; + + void clear() + { + mIntegers.resize(0); + mFloats.resize(0); + mVectors.resize(0); + mVector3s.resize(0); + } + + void uniform1i(S32 index, S32 value) + { + mIntegers.push_back({ index, value }); + } + + void uniform1f(S32 index, F32 value) + { + mFloats.push_back({ index, value }); + } + + void uniform4fv(S32 index, const LLVector4& value) + { + mVectors.push_back({ index, value }); + } + + void uniform4fv(S32 index, const F32* value) + { + mVectors.push_back({ index, LLVector4(value) }); + } + + void uniform3fv(S32 index, const LLVector3& value) + { + mVector3s.push_back({ index, value }); + } + + void apply(LLGLSLShader* shader); + + + std::vector<IntSetting> mIntegers; + std::vector<FloatSetting> mFloats; + std::vector<VectorSetting> mVectors; + std::vector<Vector3Setting> mVector3s; +}; class LLGLSLShader { public: - enum + // enum primarily used to control application sky settings uniforms + typedef enum { - SG_DEFAULT = 0, - SG_SKY, - SG_WATER - }; + SG_DEFAULT = 0, // not sky or water specific + SG_SKY, // + SG_WATER, + SG_ANY, + SG_COUNT + } eGroup; static std::set<LLGLSLShader*> sInstances; static bool sProfileEnabled; @@ -84,7 +148,6 @@ public: static GLhandleARB sCurBoundShader; static LLGLSLShader* sCurBoundShaderPtr; static S32 sIndexedTextureChannels; - static bool sNoFixedFunction; static void initProfile(); static void finishProfile(bool emit_report = true); @@ -166,6 +229,8 @@ public: BOOL link(BOOL suppress_errors = FALSE); void bind(); + //helper to conditionally bind mRiggedVariant instead of this + void bind(bool rigged); void unbind(); // Unbinds any previously bound shader by explicitly binding no shader. @@ -190,18 +255,21 @@ public: U32 mAttributeMask; //mask of which reserved attributes are set (lines up with LLVertexBuffer::getTypeMask()) std::vector<GLint> mUniform; //lookup table of uniform enum to uniform location LLStaticStringTable<GLint> mUniformMap; //lookup map of uniform name to uniform location - std::map<GLint, std::string> mUniformNameMap; //lookup map of uniform location to uniform name - std::map<GLint, LLVector4> mValue; //lookup map of uniform location to last known value + typedef std::unordered_map<GLint, std::string> uniform_name_map_t; + typedef std::unordered_map<GLint, LLVector4> uniform_value_map_t; + uniform_name_map_t mUniformNameMap; //lookup map of uniform location to uniform name + uniform_value_map_t mValue; //lookup map of uniform location to last known value std::vector<GLint> mTexture; S32 mTotalUniformSize; S32 mActiveTextureChannels; S32 mShaderLevel; - S32 mShaderGroup; + S32 mShaderGroup; // see LLGLSLShader::eGroup BOOL mUniformsDirty; LLShaderFeatures mFeatures; std::vector< std::pair< std::string, GLenum > > mShaderFiles; std::string mName; - boost::unordered_map<std::string, std::string> mDefines; + typedef std::unordered_map<std::string, std::string> defines_map_t; + defines_map_t mDefines; //statistcis for profiling shader performance U32 mTimerQuery; @@ -219,6 +287,9 @@ public: std::vector<U32> mTextureMagFilter; std::vector<U32> mTextureMinFilter; + // this pointer should be set to whichever shader represents this shader's rigged variant + LLGLSLShader* mRiggedVariant = nullptr; + private: void unloadInternal(); }; diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index ad501687ed..e012eb9a62 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -164,11 +164,11 @@ BOOL LLGLTexture::createGLTexture() return mGLTexturep->createGLTexture() ; } -BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category) +BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name) { - llassert(mGLTexturep.notNull()) ; + llassert(mGLTexturep.notNull()); - BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ; + BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category, defer_copy, tex_name) ; if(ret) { @@ -260,18 +260,20 @@ LLTexUnit::eTextureType LLGLTexture::getTarget(void) const return mGLTexturep->getTarget() ; } -BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; llassert(mGLTexturep.notNull()) ; - return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ; + return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height, 0, use_name) ; } -BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; llassert(mGLTexturep.notNull()) ; - return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ; + return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height, 0, use_name) ; } void LLGLTexture::setGLTextureCreated (bool initialized) diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 071912c2c2..8cfe7b62de 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -124,13 +124,22 @@ public: BOOL hasGLTexture() const ; LLGLuint getTexName() const ; BOOL createGLTexture() ; - BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER); + + // Create a GL Texture from an image raw + // discard_level - mip level, 0 for highest resultion mip + // imageraw - the image to copy from + // usename - explicit GL name override + // to_create - set to FALSE to force gl texture to not be created + // category - LLGLTexture category for this LLGLTexture + // defer_copy - set to true to allocate GL texture but NOT initialize with imageraw data + // tex_name - if not null, will be set to the GL name of the texture created + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER, bool defer_copy = false, LLGLuint* tex_name = nullptr); void setFilteringOption(LLTexUnit::eTextureFilterOptions option); void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); void setAddressMode(LLTexUnit::eTextureAddressMode mode); - BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); - BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); + BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name = 0); + BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name = 0); void setGLTextureCreated (bool initialized); void setCategory(S32 category) ; void setTexName(LLGLuint); // for forcing w/ externally created textures only @@ -176,7 +185,7 @@ private: protected: void setTexelsPerImage(); - //note: do not make this function public. +public: /*virtual*/ LLImageGL* getGLTexture() const ; protected: diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 0151d20128..9bd3a0a6b0 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -39,6 +39,12 @@ #include "llgl.h" #include "llglslshader.h" #include "llrender.h" +#include "llwindow.h" +#include "llframetimer.h" + +#if !LL_IMAGEGL_THREAD_CHECK +#define checkActiveThread() +#endif //---------------------------------------------------------------------------- const F32 MIN_TEXTURE_LIFETIME = 10.f; @@ -61,9 +67,11 @@ F32 LLImageGL::sLastFrameTime = 0.f; BOOL LLImageGL::sAllowReadBackRaw = FALSE ; LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; bool LLImageGL::sCompressTextures = false; - std::set<LLImageGL*> LLImageGL::sImageList; + +bool LLImageGLThread::sEnabled = false; + //**************************************************************************************************** //The below for texture auditing use only //**************************************************************************************************** @@ -170,15 +178,24 @@ BOOL is_little_endian() return (*c == 0x78) ; } + //static -void LLImageGL::initClass(S32 num_catagories, BOOL skip_analyze_alpha /* = false */) +void LLImageGL::initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha /* = false */, bool multi_threaded /* = false */) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; sSkipAnalyzeAlpha = skip_analyze_alpha; + + if (multi_threaded) + { + LLImageGLThread::createInstance(window); + } } //static void LLImageGL::cleanupClass() -{ +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + LLImageGLThread::deleteSingleton(); } //static @@ -194,6 +211,7 @@ S32 LLImageGL::dataFormatBits(S32 dataformat) case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 8; case GL_LUMINANCE: return 8; case GL_ALPHA: return 8; + case GL_RED: return 8; case GL_COLOR_INDEX: return 8; case GL_LUMINANCE_ALPHA: return 16; case GL_RGB: return 24; @@ -243,6 +261,7 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: return 4; case GL_LUMINANCE: return 1; case GL_ALPHA: return 1; + case GL_RED: return 1; case GL_COLOR_INDEX: return 1; case GL_LUMINANCE_ALPHA: return 2; case GL_RGB: return 3; @@ -258,11 +277,10 @@ S32 LLImageGL::dataFormatComponents(S32 dataformat) //---------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_IMAGE_UPDATE_STATS("Image Stats"); // static void LLImageGL::updateStats(F32 current_time) { - LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_STATS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; sLastFrameTime = current_time; sBoundTextureMemory = sCurBoundTextureMemory; sCurBoundTextureMemory = S32Bytes(0); @@ -295,10 +313,8 @@ void LLImageGL::destroyGL(BOOL save_state) if (save_state && glimage->isGLTextureCreated() && glimage->mComponents) { glimage->mSaveData = new LLImageRaw; - glimage->claimMem(glimage->mSaveData); if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it. { - glimage->disclaimMem(glimage->mSaveData); glimage->mSaveData = NULL ; } } @@ -372,8 +388,7 @@ BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, B //---------------------------------------------------------------------------- LLImageGL::LLImageGL(BOOL usemipmaps) -: LLTrace::MemTrackable<LLImageGL>("LLImageGL"), - mSaveData(0), mExternalTexture(FALSE) +: mSaveData(0), mExternalTexture(FALSE) { init(usemipmaps); setSize(0, 0, 0); @@ -382,8 +397,7 @@ LLImageGL::LLImageGL(BOOL usemipmaps) } LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps) -: LLTrace::MemTrackable<LLImageGL>("LLImageGL"), - mSaveData(0), mExternalTexture(FALSE) +: mSaveData(0), mExternalTexture(FALSE) { llassert( components <= 4 ); init(usemipmaps); @@ -393,8 +407,7 @@ LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps) } LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps) -: LLTrace::MemTrackable<LLImageGL>("LLImageGL"), - mSaveData(0), mExternalTexture(FALSE) +: mSaveData(0), mExternalTexture(FALSE) { init(usemipmaps); setSize(0, 0, 0); @@ -412,7 +425,6 @@ LLImageGL::LLImageGL( LLGLenum formatPrimary, LLGLenum formatType, LLTexUnit::eTextureAddressMode addressMode) - : LLTrace::MemTrackable<LLImageGL>("LLImageGL"), mSaveData(0), mExternalTexture(TRUE) { init(false); mTexName = texName; @@ -427,7 +439,7 @@ LLImageGL::LLImageGL( LLImageGL::~LLImageGL() { - if (!mExternalTexture) + if (!mExternalTexture && gGLManager.mInited) { LLImageGL::cleanup(); sImageList.erase(this); @@ -438,6 +450,10 @@ LLImageGL::~LLImageGL() void LLImageGL::init(BOOL usemipmaps) { +#if LL_IMAGEGL_THREAD_CHECK + mActiveThread = LLThread::currentID(); +#endif + // keep these members in the same order as declared in llimagehl.h // so that it is obvious by visual inspection if we forgot to // init a field. @@ -493,6 +509,9 @@ void LLImageGL::init(BOOL usemipmaps) #endif mCategory = -1; + + // Sometimes we have to post work for the main thread. + mMainQueue = LL::WorkQueue::getInstance("mainloop"); } void LLImageGL::cleanup() @@ -534,18 +553,12 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve if (width != mWidth || height != mHeight || ncomponents != mComponents) { // Check if dimensions are a power of two! - if (!checkSize(width,height)) + if (!checkSize(width, height)) { LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL; return false; } - if (mTexName) - { -// LL_WARNS() << "Setting Size of LLImageGL with existing mTexName = " << mTexName << LL_ENDL; - destroyGLTexture(); - } - // pickmask validity depends on old image size, delete it freePickMask(); @@ -656,6 +669,7 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for void LLImageGL::setImage(const LLImageRaw* imageraw) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) && (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) && (imageraw->getComponents() == getComponents())); @@ -663,10 +677,9 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) setImage(rawdata, FALSE); } -static LLTrace::BlockTimerStatHandle FTM_SET_IMAGE("setImage"); -BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) +BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 usename /* = 0 */) { - LL_RECORD_BLOCK_TIME(FTM_SET_IMAGE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; bool is_compressed = false; switch (mFormatPrimary) @@ -683,12 +696,11 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) break; } - - if (mUseMipMaps) { //set has mip maps to true before binding image so tex parameters get set properly - gGL.getTexUnit(0)->unbind(mBindTarget); + gGL.getTexUnit(0)->unbind(mBindTarget); + mHasMipMaps = true; mTexOptionsDirty = true; setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); @@ -698,10 +710,16 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) mHasMipMaps = false; } - llverify(gGL.getTexUnit(0)->bind(this)); - - - if (mUseMipMaps) + gGL.getTexUnit(0)->bind(this, false, false, usename); + + if (data_in == nullptr) + { + S32 w = getWidth(); + S32 h = getHeight(); + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, + mFormatPrimary, mFormatType, (GLvoid*)data_in, mAllowCompression); + } + else if (mUseMipMaps) { if (data_hasmips) { @@ -728,8 +746,6 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } else { -// LL_RECORD_BLOCK_TIME(FTM_TEMP4); - if(mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); @@ -760,8 +776,6 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { stop_glerror(); { -// LL_RECORD_BLOCK_TIME(FTM_TEMP4); - if(mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); @@ -781,7 +795,7 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) glTexParameteri(mTarget, GL_GENERATE_MIPMAP, GL_TRUE); } - LLImageGL::setManualImage(mTarget, 0, mFormatInternal, + LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, mFormatPrimary, mFormatType, data_in, mAllowCompression); @@ -871,14 +885,13 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) llassert(w > 0 && h > 0 && cur_mip_data); (void)cur_mip_data; { -// LL_RECORD_BLOCK_TIME(FTM_TEMP4); if(mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); stop_glerror(); } - LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression); + LLImageGL::setManualImage(mTarget, m, mFormatInternal, w, h, mFormatPrimary, mFormatType, cur_mip_data, mAllowCompression); if (m == 0) { analyzeAlpha(data_in, w, h); @@ -1065,13 +1078,15 @@ void LLImageGL::postAddToAtlas() stop_glerror(); } -BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) +BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (!width || !height) { return TRUE; } - if (mTexName == 0) + LLGLuint tex_name = use_name != 0 ? use_name : mTexName; + if (0 == tex_name) { // *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18 //LL_WARNS() << "Setting subimage on image without GL texture" << LL_ENDL; @@ -1087,7 +1102,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 // HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture. if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height) { - setImage(datap, FALSE); + setImage(datap, FALSE, tex_name); } else { @@ -1139,12 +1154,11 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 datap += (y_pos * data_width + x_pos) * getComponents(); // Update the GL texture - BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName); + BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, tex_name); if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL; stop_glerror(); - glTexSubImage2D(mTarget, 0, x_pos, y_pos, - width, height, mFormatPrimary, mFormatType, datap); + glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap); gGL.getTexUnit(0)->disable(); stop_glerror(); @@ -1161,9 +1175,10 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 return TRUE; } -BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) +BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name) { - return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update, use_name); } // Copy sub image from frame buffer @@ -1183,15 +1198,36 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_ } // static -static LLTrace::BlockTimerStatHandle FTM_GENERATE_TEXTURES("generate textures"); void LLImageGL::generateTextures(S32 numTextures, U32 *textures) { - LL_RECORD_BLOCK_TIME(FTM_GENERATE_TEXTURES); - glGenTextures(numTextures, textures); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + static constexpr U32 pool_size = 1024; + static thread_local U32 name_pool[pool_size]; // pool of texture names + static thread_local U32 name_count = 0; // number of available names in the pool + + if (name_count == 0) + { + LL_PROFILE_ZONE_NAMED("iglgt - reup pool"); + // pool is emtpy, refill it + glGenTextures(pool_size, name_pool); + name_count = pool_size; + } + + if (numTextures <= name_count) + { + //copy teture names off the end of the pool + memcpy(textures, name_pool + name_count - numTextures, sizeof(U32) * numTextures); + name_count -= numTextures; + } + else + { + LL_PROFILE_ZONE_NAMED("iglgt - pool miss"); + glGenTextures(numTextures, textures); + } } // static -void LLImageGL::deleteTextures(S32 numTextures, U32 *textures) +void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures) { if (gGLManager.mInited) { @@ -1200,125 +1236,140 @@ void LLImageGL::deleteTextures(S32 numTextures, U32 *textures) } // static -static LLTrace::BlockTimerStatHandle FTM_SET_MANUAL_IMAGE("setManualImage"); -void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression) +void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void* pixels, bool allow_compression) { - LL_RECORD_BLOCK_TIME(FTM_SET_MANUAL_IMAGE); - bool use_scratch = false; - U32* scratch = NULL; - if (LLRender::sGLCoreProfile) - { - if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) - { //GL_ALPHA is deprecated, convert to RGBA - use_scratch = true; - scratch = new U32[width*height]; + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + bool use_scratch = false; + U32* scratch = NULL; + if (LLRender::sGLCoreProfile) + { + if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) + { //GL_ALPHA is deprecated, convert to RGBA + if (pixels != nullptr) + { + use_scratch = true; + scratch = new U32[width * height]; - U32 pixel_count = (U32) (width*height); - for (U32 i = 0; i < pixel_count; i++) - { - U8* pix = (U8*) &scratch[i]; - pix[0] = pix[1] = pix[2] = 0; - pix[3] = ((U8*) pixels)[i]; - } - - pixformat = GL_RGBA; - intformat = GL_RGBA8; - } + U32 pixel_count = (U32)(width * height); + for (U32 i = 0; i < pixel_count; i++) + { + U8* pix = (U8*)&scratch[i]; + pix[0] = pix[1] = pix[2] = 0; + pix[3] = ((U8*)pixels)[i]; + } + } - if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) - { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA - use_scratch = true; - scratch = new U32[width*height]; + pixformat = GL_RGBA; + intformat = GL_RGBA8; + } - U32 pixel_count = (U32) (width*height); - for (U32 i = 0; i < pixel_count; i++) - { - U8 lum = ((U8*) pixels)[i*2+0]; - U8 alpha = ((U8*) pixels)[i*2+1]; + if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA + if (pixels != nullptr) + { + use_scratch = true; + scratch = new U32[width * height]; - U8* pix = (U8*) &scratch[i]; - pix[0] = pix[1] = pix[2] = lum; - pix[3] = alpha; - } - - pixformat = GL_RGBA; - intformat = GL_RGBA8; - } + U32 pixel_count = (U32)(width * height); + for (U32 i = 0; i < pixel_count; i++) + { + U8 lum = ((U8*)pixels)[i * 2 + 0]; + U8 alpha = ((U8*)pixels)[i * 2 + 1]; - if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) - { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB - use_scratch = true; - scratch = new U32[width*height]; + U8* pix = (U8*)&scratch[i]; + pix[0] = pix[1] = pix[2] = lum; + pix[3] = alpha; + } + } - U32 pixel_count = (U32) (width*height); - for (U32 i = 0; i < pixel_count; i++) - { - U8 lum = ((U8*) pixels)[i]; - - U8* pix = (U8*) &scratch[i]; - pix[0] = pix[1] = pix[2] = lum; - pix[3] = 255; - } - - pixformat = GL_RGBA; - intformat = GL_RGB8; - } - } + pixformat = GL_RGBA; + intformat = GL_RGBA8; + } - if (LLImageGL::sCompressTextures && allow_compression) - { - switch (intformat) - { - case GL_RGB: - case GL_RGB8: - intformat = GL_COMPRESSED_RGB; - break; - case GL_SRGB: - case GL_SRGB8: - intformat = GL_COMPRESSED_SRGB; - break; - case GL_RGBA: - case GL_RGBA8: - intformat = GL_COMPRESSED_RGBA; - break; - case GL_SRGB_ALPHA: - case GL_SRGB8_ALPHA8: - intformat = GL_COMPRESSED_SRGB_ALPHA; - break; - case GL_LUMINANCE: - case GL_LUMINANCE8: - intformat = GL_COMPRESSED_LUMINANCE; - break; - case GL_LUMINANCE_ALPHA: - case GL_LUMINANCE8_ALPHA8: - intformat = GL_COMPRESSED_LUMINANCE_ALPHA; - break; - case GL_ALPHA: - case GL_ALPHA8: - intformat = GL_COMPRESSED_ALPHA; - break; - default: - LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL; - break; - } - } + if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) + { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB + if (pixels != nullptr) + { + use_scratch = true; + scratch = new U32[width * height]; - stop_glerror(); - glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); - stop_glerror(); + U32 pixel_count = (U32)(width * height); + for (U32 i = 0; i < pixel_count; i++) + { + U8 lum = ((U8*)pixels)[i]; - if (use_scratch) - { - delete [] scratch; - } + U8* pix = (U8*)&scratch[i]; + pix[0] = pix[1] = pix[2] = lum; + pix[3] = 255; + } + } + pixformat = GL_RGBA; + intformat = GL_RGB8; + } + } + + if (LLImageGL::sCompressTextures && allow_compression) + { + switch (intformat) + { + case GL_RGB: + case GL_RGB8: + intformat = GL_COMPRESSED_RGB; + break; + case GL_SRGB: + case GL_SRGB8: + intformat = GL_COMPRESSED_SRGB; + break; + case GL_RGBA: + case GL_RGBA8: + intformat = GL_COMPRESSED_RGBA; + break; + case GL_SRGB_ALPHA: + case GL_SRGB8_ALPHA8: + intformat = GL_COMPRESSED_SRGB_ALPHA; + break; + case GL_LUMINANCE: + case GL_LUMINANCE8: + intformat = GL_COMPRESSED_LUMINANCE; + break; + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE8_ALPHA8: + intformat = GL_COMPRESSED_LUMINANCE_ALPHA; + break; + case GL_ALPHA: + case GL_ALPHA8: + intformat = GL_COMPRESSED_ALPHA; + break; + case GL_RED: + case GL_R8: + intformat = GL_COMPRESSED_RED; + break; + default: + LL_WARNS() << "Could not compress format: " << std::hex << intformat << LL_ENDL; + break; + } + } + + stop_glerror(); + { + LL_PROFILE_ZONE_NAMED("glTexImage2D"); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); + } + stop_glerror(); + + if (use_scratch) + { + delete[] scratch; + } } //create an empty GL texture: just create a texture name //the texture is assiciate with some image by calling glTexImage outside LLImageGL -static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE1("createGLTexture()"); BOOL LLImageGL::createGLTexture() { - LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE1); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + checkActiveThread(); + if (gGLManager.mIsDisabled) { LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; @@ -1333,6 +1384,7 @@ BOOL LLImageGL::createGLTexture() if(mTexName) { LLImageGL::deleteTextures(1, (reinterpret_cast<GLuint*>(&mTexName))) ; + mTexName = 0; } @@ -1347,23 +1399,24 @@ BOOL LLImageGL::createGLTexture() return TRUE ; } -static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE2("createGLTexture(raw)"); -BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category) +BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name) { - LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE2); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + checkActiveThread(); + if (gGLManager.mIsDisabled) { LL_WARNS() << "Trying to create a texture while GL is disabled!" << LL_ENDL; return FALSE; } - mGLTextureCreated = false ; llassert(gGLManager.mInited); stop_glerror(); if (!imageraw || imageraw->isBufferInvalid()) { LL_WARNS() << "Trying to create a texture from invalid image data" << LL_ENDL; + mGLTextureCreated = false; return FALSE; } @@ -1376,6 +1429,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S // Actual image width/height = raw image width/height * 2^discard_level S32 raw_w = imageraw->getWidth() ; S32 raw_h = imageraw->getHeight() ; + S32 w = raw_w << discard_level; S32 h = raw_h << discard_level; @@ -1383,6 +1437,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S if (!setSize(w, h, imageraw->getComponents(), discard_level)) { LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL; + mGLTextureCreated = false; return FALSE; } @@ -1451,115 +1506,236 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S destroyGLTexture(); mCurrentDiscardLevel = discard_level; mLastBindTime = sLastFrameTime; + mGLTextureCreated = false; return TRUE ; } setCategory(category); const U8* rawdata = imageraw->getData(); - return createGLTexture(discard_level, rawdata, FALSE, usename); + return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy, tex_name); } -static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)"); -BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) +BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename, bool defer_copy, LLGLuint* tex_name) +// Call with void data, vmem is allocated but unitialized { - LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE3); - llassert(data_in); - stop_glerror(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + checkActiveThread(); - if (discard_level < 0) - { - llassert(mCurrentDiscardLevel >= 0); - discard_level = mCurrentDiscardLevel; - } - discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); + bool main_thread = on_main_thread(); - if (mTexName != 0 && discard_level == mCurrentDiscardLevel) - { - // This will only be true if the size has not changed - return setImage(data_in, data_hasmips); - } - - U32 old_name = mTexName; -// S32 old_discard = mCurrentDiscardLevel; - - if (usename != 0) - { - mTexName = usename; - } - else - { - LLImageGL::generateTextures(1, &mTexName); - stop_glerror(); - { - llverify(gGL.getTexUnit(0)->bind(this)); - stop_glerror(); - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0); - stop_glerror(); - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level); - stop_glerror(); - } - } - if (!mTexName) - { - if (old_name) - { - sGlobalTextureMemory -= mTextureMemory; - LLImageGL::deleteTextures(1, &old_name); - disclaimMem(mTextureMemory); - stop_glerror(); - } + if (defer_copy) + { + data_in = nullptr; + } + else + { + llassert(data_in); + } - LL_WARNS() << "LLImageGL::createGLTexture failed to make texture" << LL_ENDL; - return FALSE; - } + stop_glerror(); - if (mUseMipMaps) - { - mAutoGenMips = gGLManager.mHasMipMapGeneration; -#if LL_DARWIN - // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures. - if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA)) - { - mAutoGenMips = FALSE; - } -#endif - } + if (discard_level < 0) + { + llassert(mCurrentDiscardLevel >= 0); + discard_level = mCurrentDiscardLevel; + } + discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); - mCurrentDiscardLevel = discard_level; + if (main_thread // <--- always force creation of new_texname when not on main thread ... + && !defer_copy // <--- ... or defer copy is set + && mTexName != 0 && discard_level == mCurrentDiscardLevel) + { + LL_PROFILE_ZONE_NAMED("cglt - early setImage"); + // This will only be true if the size has not changed + if (tex_name != nullptr) + { + *tex_name = mTexName; + } + return setImage(data_in, data_hasmips); + } - if (!setImage(data_in, data_hasmips)) - { - stop_glerror(); - return FALSE; - } + GLuint old_texname = mTexName; + GLuint new_texname = 0; + if (usename != 0) + { + llassert(main_thread); + new_texname = usename; + } + else + { + LLImageGL::generateTextures(1, &new_texname); + { + gGL.getTexUnit(0)->bind(this, false, false, new_texname); + glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel - discard_level); + } + } + + if (tex_name != nullptr) + { + *tex_name = new_texname; + } - // Set texture options to our defaults. - gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps); - gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode); - gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); + if (mUseMipMaps) + { + mAutoGenMips = gGLManager.mHasMipMapGeneration; + } - // things will break if we don't unbind after creation - gGL.getTexUnit(0)->unbind(mBindTarget); - stop_glerror(); + mCurrentDiscardLevel = discard_level; - if (old_name != 0) - { - sGlobalTextureMemory -= mTextureMemory; + { + LL_PROFILE_ZONE_NAMED("cglt - late setImage"); + if (!setImage(data_in, data_hasmips, new_texname)) + { + return FALSE; + } + } - LLImageGL::deleteTextures(1, &old_name); + // Set texture options to our defaults. + gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps); + gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode); + gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); - stop_glerror(); - } + // things will break if we don't unbind after creation + gGL.getTexUnit(0)->unbind(mBindTarget); - disclaimMem(mTextureMemory); - mTextureMemory = (S32Bytes)getMipBytes(discard_level); - claimMem(mTextureMemory); - sGlobalTextureMemory += mTextureMemory; - mTexelsInGLTexture = getWidth() * getHeight() ; + if (old_texname != 0) + { + sGlobalTextureMemory -= mTextureMemory; + } - // mark this as bound at this point, so we don't throw it out immediately - mLastBindTime = sLastFrameTime; - return TRUE; + //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread + if (!defer_copy) + { + if (!main_thread) + { + syncToMainThread(new_texname); + } + else + { + //not on background thread, immediately set mTexName + if (old_texname != 0 && old_texname != new_texname) + { + LLImageGL::deleteTextures(1, &old_texname); + } + mTexName = new_texname; + } + } + + + mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel); + sGlobalTextureMemory += mTextureMemory; + mTexelsInGLTexture = getWidth() * getHeight(); + + // mark this as bound at this point, so we don't throw it out immediately + mLastBindTime = sLastFrameTime; + + checkActiveThread(); + return TRUE; +} + +void LLImageGLThread::updateClass() +{ + LL_PROFILE_ZONE_SCOPED; + + // update available vram one per second + static LLFrameTimer sTimer; + + if (sTimer.getElapsedSeconds() < 1.f) + { + return; + } + + sTimer.reset(); + + auto func = []() + { + if (gGLManager.mHasATIMemInfo) + { + S32 meminfo[4]; + glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); + LLImageGLThread::sFreeVRAMMegabytes = meminfo[0]; + + } + else if (gGLManager.mHasNVXMemInfo) + { + S32 free_memory; + glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); + LLImageGLThread::sFreeVRAMMegabytes = free_memory / 1024; + } + }; + + + // post update to background thread if available, otherwise execute immediately + auto queue = LL::WorkQueue::getInstance("LLImageGL"); + if (sEnabled) + { + queue->post(func); + } + else + { + llassert(queue == nullptr); + func(); + } +} + +void LLImageGL::syncToMainThread(LLGLuint new_tex_name) +{ + LL_PROFILE_ZONE_SCOPED; + llassert(!on_main_thread()); + + { + LL_PROFILE_ZONE_NAMED("cglt - sync"); + if (gGLManager.mHasSync) + { + // post a sync to the main thread (will execute before tex name swap lambda below) + // glFlush calls here are partly superstitious and partly backed by observation + // on AMD hardware + glFlush(); + auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); + glFlush(); + LL::WorkQueue::postMaybe( + mMainQueue, + [=]() + { + LL_PROFILE_ZONE_NAMED("cglt - wait sync"); + { + LL_PROFILE_ZONE_NAMED("glWaitSync"); + glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); + } + { + LL_PROFILE_ZONE_NAMED("glDeleteSync"); + glDeleteSync(sync); + } + }); + } + else + { + glFinish(); + } + } + + ref(); + LL::WorkQueue::postMaybe( + mMainQueue, + [=]() + { + LL_PROFILE_ZONE_NAMED("cglt - delete callback"); + syncTexName(new_tex_name); + unref(); + }); +} + +void LLImageGL::syncTexName(LLGLuint texname) +{ + if (texname != 0) + { + if (mTexName != 0 && mTexName != texname) + { + LLImageGL::deleteTextures(1, &mTexName); + } + mTexName = texname; + } } BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const @@ -1673,37 +1849,29 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre return TRUE ; } -void LLImageGL::deleteDeadTextures() -{ - bool reset = false; - - if (reset) - { - gGL.getTexUnit(0)->activate(); - } -} - void LLImageGL::destroyGLTexture() { + checkActiveThread(); + if (mTexName != 0) { if(mTextureMemory != S32Bytes(0)) { sGlobalTextureMemory -= mTextureMemory; - disclaimMem(mTextureMemory); mTextureMemory = (S32Bytes)0; } - LLImageGL::deleteTextures(1, &mTexName); + LLImageGL::deleteTextures(1, &mTexName); mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mTexName = 0; mGLTextureCreated = FALSE ; - } + } } //force to invalidate the gl texture, most likely a sculpty texture void LLImageGL::forceToInvalidateGLTexture() { + checkActiveThread(); if (mTexName != 0) { destroyGLTexture(); @@ -1878,6 +2046,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride() case GL_LUMINANCE_ALPHA: mAlphaStride = 2; break; + case GL_RED: case GL_RGB: case GL_SRGB: mNeedsAlphaAndPickMask = FALSE; @@ -2043,7 +2212,6 @@ U32 LLImageGL::createPickMask(S32 pWidth, S32 pHeight) U32 size = pick_width * pick_height; size = (size + 7) / 8; // pixelcount-to-bits mPickMask = new U8[size]; - claimMem(size); mPickMaskWidth = pick_width - 1; mPickMaskHeight = pick_height - 1; @@ -2058,7 +2226,6 @@ void LLImageGL::freePickMask() // pickmask validity depends on old image size, delete it if (mPickMask != NULL) { - disclaimMem((mPickMaskWidth * mPickMaskHeight + 7) / 8); delete [] mPickMask; } mPickMask = NULL; @@ -2182,6 +2349,12 @@ void LLImageGL::resetCurTexSizebar() sCurTexPickSize = -1 ; } //---------------------------------------------------------------------------- +#if LL_IMAGEGL_THREAD_CHECK +void LLImageGL::checkActiveThread() +{ + llassert(mActiveThread == LLThread::currentID()); +} +#endif //---------------------------------------------------------------------------- @@ -2235,3 +2408,38 @@ void LLImageGL::resetCurTexSizebar() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips); */ + +std::atomic<S32> LLImageGLThread::sFreeVRAMMegabytes(4096); //if free vram is unknown, default to 4GB + +LLImageGLThread::LLImageGLThread(LLWindow* window) + // We want exactly one thread, but a very large capacity: we never want + // anyone, especially inner-loop render code, to have to block on post() + // because we're full. + : ThreadPool("LLImageGL", 1, 1024*1024) + , mWindow(window) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + sEnabled = true; + mFinished = false; + + mContext = mWindow->createSharedContext(); + ThreadPool::start(); +} + +void LLImageGLThread::run() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + // We must perform setup on this thread before actually servicing our + // WorkQueue, likewise cleanup afterwards. + mWindow->makeContextCurrent(mContext); + gGL.init(); + ThreadPool::run(); + gGL.shutdown(); + mWindow->destroySharedContext(mContext); +} + +S32 LLImageGLThread::getFreeVRAMMegabytes() +{ + return sFreeVRAMMegabytes; +} + diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 61ddc8d59b..4d5b60d6bc 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -35,21 +35,26 @@ #include "llrefcount.h" #include "v2math.h" #include "llunits.h" - +#include "llthreadsafequeue.h" #include "llrender.h" -class LLTextureAtlas ; +#include "threadpool.h" +#include "workqueue.h" + +#define LL_IMAGEGL_THREAD_CHECK 0 //set to 1 to enable thread debugging for ImageGL + +class LLWindow; + #define BYTES_TO_MEGA_BYTES(x) ((x) >> 20) #define MEGA_BYTES_TO_BYTES(x) ((x) << 20) //============================================================================ -class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL> +class LLImageGL : public LLRefCount { friend class LLTexUnit; public: // These 2 functions replace glGenTextures() and glDeleteTextures() static void generateTextures(S32 numTextures, U32 *textures); - static void deleteTextures(S32 numTextures, U32 *textures); - static void deleteDeadTextures(); + static void deleteTextures(S32 numTextures, const U32 *textures); // Size calculation static S32 dataFormatBits(S32 dataformat); @@ -102,17 +107,21 @@ public: void setAllowCompression(bool allow) { mAllowCompression = allow; } static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); - + BOOL createGLTexture() ; BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, - S32 category = sMaxCategories-1); - BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); + S32 category = sMaxCategories-1, bool defer_copy = false, LLGLuint* tex_name = nullptr); + BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false, LLGLuint* tex_name = nullptr); void setImage(const LLImageRaw* imageraw); - BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE); - BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); - BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); + BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE, S32 usename = 0); + BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0); + BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0); BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); - + + // wait for gl commands to finish on current thread and push + // a lambda to main thread to swap mNewTexName and mTexName + void syncToMainThread(LLGLuint new_tex_name); + // Read back a raw image for this discard level, if it exists BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const; void destroyGLTexture(); @@ -184,6 +193,12 @@ public: BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image); void postAddToAtlas() ; +#if LL_IMAGEGL_THREAD_CHECK + // thread debugging + std::thread::id mActiveThread; + void checkActiveThread(); +#endif + public: // Various GL/Rendering options S32Bytes mTextureMemory; @@ -194,6 +209,7 @@ private: void freePickMask(); LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL + LL::WorkQueue::weak_t mMainQueue; U8* mPickMask; //downsampled bitmap approximation of alpha channel. NULL if no alpha channel U16 mPickMaskWidth; U16 mPickMaskHeight; @@ -208,8 +224,9 @@ private: bool mGLTextureCreated ; LLGLuint mTexName; + //LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread U16 mWidth; - U16 mHeight; + U16 mHeight; S8 mCurrentDiscardLevel; S8 mDiscardLevelInAtlas; @@ -265,7 +282,7 @@ public: #endif public: - static void initClass(S32 num_catagories, BOOL skip_analyze_alpha = false); + static void initClass(LLWindow* window, S32 num_catagories, BOOL skip_analyze_alpha = false, bool multi_threaded = false); static void cleanupClass() ; private: @@ -287,6 +304,9 @@ public: void setTexName(GLuint texName) { mTexName = texName; } + //similar to setTexName, but will call deleteTextures on mTexName if mTexName is not 0 or texname + void syncTexName(LLGLuint texname); + //for debug use: show texture size distribution //---------------------------------------- static S32 sCurTexSizeBar ; @@ -301,4 +321,36 @@ public: }; +class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool +{ +public: + // follows gSavedSettings "RenderGLMultiThreaded" + static bool sEnabled; + + // app should call this function periodically + static void updateClass(); + + // free video memory in megabytes + static std::atomic<S32> sFreeVRAMMegabytes; + + LLImageGLThread(LLWindow* window); + + // post a function to be executed on the LLImageGL background thread + template <typename CALLABLE> + bool post(CALLABLE&& func) + { + return getQueue().postIfOpen(std::forward<CALLABLE>(func)); + } + + void run() override; + + static S32 getFreeVRAMMegabytes(); + +private: + LLWindow* mWindow; + void* mContext = nullptr; + LLAtomicBool mFinished; +}; + + #endif // LL_LLIMAGEGL_H diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 03b6aac20c..a03a27cf94 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -36,7 +36,18 @@ #include "lltexture.h" #include "llshadermgr.h" -LLRender gGL; +#if LL_WINDOWS +extern void APIENTRY gl_debug_callback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + GLvoid* userParam) +; +#endif + +thread_local LLRender gGL; // Handy copies of last good GL matrices F32 gGLModelView[16]; @@ -71,18 +82,6 @@ static const GLint sGLAddressMode[] = GL_CLAMP_TO_EDGE }; -static const GLenum sGLCompareFunc[] = -{ - GL_NEVER, - GL_ALWAYS, - GL_LESS, - GL_LEQUAL, - GL_EQUAL, - GL_NOTEQUAL, - GL_GEQUAL, - GL_GREATER -}; - const U32 immediate_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXCOORD0; static const GLenum sGLBlendFactor[] = @@ -102,10 +101,7 @@ static const GLenum sGLBlendFactor[] = }; LLTexUnit::LLTexUnit(S32 index) - : mCurrTexType(TT_NONE), mCurrBlendType(TB_MULT), - mCurrColorOp(TBO_MULT), mCurrAlphaOp(TBO_MULT), - mCurrColorSrc1(TBS_TEX_COLOR), mCurrColorSrc2(TBS_PREV_COLOR), - mCurrAlphaSrc1(TBS_TEX_ALPHA), mCurrAlphaSrc2(TBS_PREV_ALPHA), + : mCurrTexType(TT_NONE), mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mTexColorSpace(TCS_LINEAR), mHasMipMaps(false), mIndex(index) @@ -128,42 +124,15 @@ void LLTexUnit::refreshState(void) glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); - // - // Per apple spec, don't call glEnable/glDisable when index exceeds max texture units - // http://www.mailinglistarchive.com/html/mac-opengl@lists.apple.com/2008-07/msg00653.html - // - bool enableDisable = !LLGLSLShader::sNoFixedFunction && - (mIndex < gGLManager.mNumTextureUnits) && mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE; - if (mCurrTexType != TT_NONE) { - if (enableDisable) - { - glEnable(sGLTextureType[mCurrTexType]); - } - glBindTexture(sGLTextureType[mCurrTexType], mCurrTexture); } else { - if (enableDisable) - { - glDisable(GL_TEXTURE_2D); - } - glBindTexture(GL_TEXTURE_2D, 0); } - if (mCurrBlendType != TB_COMBINE) - { - setTextureBlendType(mCurrBlendType); - } - else - { - setTextureCombiner(mCurrColorOp, mCurrColorSrc1, mCurrColorSrc2, false); - setTextureCombiner(mCurrAlphaOp, mCurrAlphaSrc1, mCurrAlphaSrc2, true); - } - setTextureColorSpace(mTexColorSpace); } @@ -196,14 +165,6 @@ void LLTexUnit::enable(eTextureType type) mCurrTexType = type; gGL.flush(); - if (!LLGLSLShader::sNoFixedFunction && - type != LLTexUnit::TT_MULTISAMPLE_TEXTURE && - mIndex < gGLManager.mNumTextureUnits) - { - stop_glerror(); - glEnable(sGLTextureType[type]); - stop_glerror(); - } } } @@ -216,21 +177,34 @@ void LLTexUnit::disable(void) activate(); unbind(mCurrTexType); gGL.flush(); - if (!LLGLSLShader::sNoFixedFunction && - mCurrTexType != LLTexUnit::TT_MULTISAMPLE_TEXTURE && - mIndex < gGLManager.mNumTextureUnits) - { - glDisable(sGLTextureType[mCurrTexType]); - } - setTextureColorSpace(TCS_LINEAR); mCurrTexType = TT_NONE; } } +void LLTexUnit::bindFast(LLTexture* texture) +{ + LLImageGL* gl_tex = texture->getGLTexture(); + + glActiveTextureARB(GL_TEXTURE0_ARB + mIndex); + gGL.mCurrTextureUnitIndex = mIndex; + mCurrTexture = gl_tex->getTexName(); + if (!mCurrTexture) + { + LL_PROFILE_ZONE_NAMED("MISSING TEXTURE"); + //if deleted, will re-generate it immediately + texture->forceImmediateUpdate(); + gl_tex->forceUpdateBindStats(); + texture->bindDefaultImage(mIndex); + } + glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture); + mHasMipMaps = gl_tex->mHasMipMaps; +} + bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; stop_glerror(); if (mIndex >= 0) { @@ -294,18 +268,20 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) return true; } -bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) +bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32 usename) { stop_glerror(); if (mIndex < 0) return false; + U32 texname = usename ? usename : texture->getTexName(); + if(!texture) { LL_DEBUGS() << "NULL LLTexUnit::bind texture" << LL_ENDL; return false; } - if(!texture->getTexName()) + if(!texname) { if(LLImageGL::sDefaultGLTexture && LLImageGL::sDefaultGLTexture->getTexName()) { @@ -315,7 +291,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) return false ; } - if ((mCurrTexture != texture->getTexName()) || forceBind) + if ((mCurrTexture != texname) || forceBind) { gGL.flush(); stop_glerror(); @@ -323,7 +299,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind) stop_glerror(); enable(texture->getTarget()); stop_glerror(); - mCurrTexture = texture->getTexName(); + mCurrTexture = texname; glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); stop_glerror(); texture->updateBindStats(texture->mTextureMemory); @@ -447,7 +423,7 @@ void LLTexUnit::unbind(eTextureType type) // Always make sure our texture color space is reset to linear. SRGB sampling should be opt-in in the vast majority of cases. Also prevents color space "popping". mTexColorSpace = TCS_LINEAR; - if (LLGLSLShader::sNoFixedFunction && type == LLTexUnit::TT_TEXTURE) + if (type == LLTexUnit::TT_TEXTURE) { glBindTexture(sGLTextureType[type], sWhiteTexture); } @@ -459,6 +435,28 @@ void LLTexUnit::unbind(eTextureType type) } } +void LLTexUnit::unbindFast(eTextureType type) +{ + activate(); + + // Disabled caching of binding state. + if (mCurrTexType == type) + { + mCurrTexture = 0; + + // Always make sure our texture color space is reset to linear. SRGB sampling should be opt-in in the vast majority of cases. Also prevents color space "popping". + mTexColorSpace = TCS_LINEAR; + if (type == LLTexUnit::TT_TEXTURE) + { + glBindTexture(sGLTextureType[type], sWhiteTexture); + } + else + { + glBindTexture(sGLTextureType[type], 0); + } + } +} + void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode) { if (mIndex < 0 || mCurrTexture == 0) return; @@ -537,55 +535,6 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio } } -void LLTexUnit::setTextureBlendType(eTextureBlendType type) -{ - if (LLGLSLShader::sNoFixedFunction) - { //texture blend type means nothing when using shaders - return; - } - - if (mIndex < 0) return; - - // Do nothing if it's already correctly set. - if (mCurrBlendType == type && !gGL.mDirty) - { - return; - } - - gGL.flush(); - - activate(); - mCurrBlendType = type; - S32 scale_amount = 1; - switch (type) - { - case TB_REPLACE: - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - break; - case TB_ADD: - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_ADD); - break; - case TB_MULT: - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - break; - case TB_MULT_X2: - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - scale_amount = 2; - break; - case TB_ALPHA_BLEND: - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); - break; - case TB_COMBINE: - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - break; - default: - LL_ERRS() << "Unknown Texture Blend Type: " << type << LL_ENDL; - break; - } - setColorScale(scale_amount); - setAlphaScale(1); -} - GLint LLTexUnit::getTextureSource(eTextureBlendSrc src) { switch(src) @@ -662,159 +611,6 @@ GLint LLTexUnit::getTextureSourceType(eTextureBlendSrc src, bool isAlpha) } } -void LLTexUnit::setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha) -{ - if (LLGLSLShader::sNoFixedFunction) - { //register combiners do nothing when not using fixed function - return; - } - - if (mIndex < 0) return; - - activate(); - if (mCurrBlendType != TB_COMBINE || gGL.mDirty) - { - mCurrBlendType = TB_COMBINE; - gGL.flush(); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - } - - // We want an early out, because this function does a LOT of stuff. - if ( ( (isAlpha && (mCurrAlphaOp == op) && (mCurrAlphaSrc1 == src1) && (mCurrAlphaSrc2 == src2)) - || (!isAlpha && (mCurrColorOp == op) && (mCurrColorSrc1 == src1) && (mCurrColorSrc2 == src2)) ) && !gGL.mDirty) - { - return; - } - - gGL.flush(); - - // Get the gl source enums according to the eTextureBlendSrc sources passed in - GLint source1 = getTextureSource(src1); - GLint source2 = getTextureSource(src2); - // Get the gl operand enums according to the eTextureBlendSrc sources passed in - GLint operand1 = getTextureSourceType(src1, isAlpha); - GLint operand2 = getTextureSourceType(src2, isAlpha); - // Default the scale amount to 1 - S32 scale_amount = 1; - GLenum comb_enum, src0_enum, src1_enum, src2_enum, operand0_enum, operand1_enum, operand2_enum; - - if (isAlpha) - { - // Set enums to ALPHA ones - comb_enum = GL_COMBINE_ALPHA_ARB; - src0_enum = GL_SOURCE0_ALPHA_ARB; - src1_enum = GL_SOURCE1_ALPHA_ARB; - src2_enum = GL_SOURCE2_ALPHA_ARB; - operand0_enum = GL_OPERAND0_ALPHA_ARB; - operand1_enum = GL_OPERAND1_ALPHA_ARB; - operand2_enum = GL_OPERAND2_ALPHA_ARB; - - // cache current combiner - mCurrAlphaOp = op; - mCurrAlphaSrc1 = src1; - mCurrAlphaSrc2 = src2; - } - else - { - // Set enums to RGB ones - comb_enum = GL_COMBINE_RGB_ARB; - src0_enum = GL_SOURCE0_RGB_ARB; - src1_enum = GL_SOURCE1_RGB_ARB; - src2_enum = GL_SOURCE2_RGB_ARB; - operand0_enum = GL_OPERAND0_RGB_ARB; - operand1_enum = GL_OPERAND1_RGB_ARB; - operand2_enum = GL_OPERAND2_RGB_ARB; - - // cache current combiner - mCurrColorOp = op; - mCurrColorSrc1 = src1; - mCurrColorSrc2 = src2; - } - - switch(op) - { - case TBO_REPLACE: - // Slightly special syntax (no second sources), just set all and return. - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1); - glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1); - (isAlpha) ? setAlphaScale(1) : setColorScale(1); - return; - - case TBO_MULT: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE); - break; - - case TBO_MULT_X2: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE); - scale_amount = 2; - break; - - case TBO_MULT_X4: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_MODULATE); - scale_amount = 4; - break; - - case TBO_ADD: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_ADD); - break; - - case TBO_ADD_SIGNED: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_ADD_SIGNED_ARB); - break; - - case TBO_SUBTRACT: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_SUBTRACT_ARB); - break; - - case TBO_LERP_VERT_ALPHA: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE); - glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PRIMARY_COLOR_ARB); - glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA); - break; - - case TBO_LERP_TEX_ALPHA: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE); - glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA); - break; - - case TBO_LERP_PREV_ALPHA: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE); - glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PREVIOUS_ARB); - glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA); - break; - - case TBO_LERP_CONST_ALPHA: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE); - glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_CONSTANT_ARB); - glTexEnvi(GL_TEXTURE_ENV, operand2_enum, GL_SRC_ALPHA); - break; - - case TBO_LERP_VERT_COLOR: - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_INTERPOLATE); - glTexEnvi(GL_TEXTURE_ENV, src2_enum, GL_PRIMARY_COLOR_ARB); - glTexEnvi(GL_TEXTURE_ENV, operand2_enum, (isAlpha) ? GL_SRC_ALPHA : GL_SRC_COLOR); - break; - - default: - LL_WARNS() << "Unknown eTextureBlendOp: " << op << ". Setting op to replace." << LL_ENDL; - // Slightly special syntax (no second sources), just set all and return. - glTexEnvi(GL_TEXTURE_ENV, comb_enum, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1); - glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1); - (isAlpha) ? setAlphaScale(1) : setColorScale(1); - return; - } - - // Set sources, operands, and scale accordingly - glTexEnvi(GL_TEXTURE_ENV, src0_enum, source1); - glTexEnvi(GL_TEXTURE_ENV, operand0_enum, operand1); - glTexEnvi(GL_TEXTURE_ENV, src1_enum, source2); - glTexEnvi(GL_TEXTURE_ENV, operand1_enum, operand2); - (isAlpha) ? setAlphaScale(scale_amount) : setColorScale(scale_amount); -} - void LLTexUnit::setColorScale(S32 scale) { if (mCurrColorScale != scale || gGL.mDirty) @@ -903,26 +699,12 @@ LLLightState::LLLightState(S32 index) void LLLightState::enable() { - if (!mEnabled) - { - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHT0+mIndex); - } - mEnabled = true; - } + mEnabled = true; } void LLLightState::disable() { - if (mEnabled) - { - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHT0+mIndex); - } - mEnabled = false; - } + mEnabled = false; } void LLLightState::setDiffuse(const LLColor4& diffuse) @@ -931,10 +713,6 @@ void LLLightState::setDiffuse(const LLColor4& diffuse) { ++gGL.mLightHash; mDiffuse = diffuse; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_DIFFUSE, mDiffuse.mV); - } } } @@ -962,10 +740,6 @@ void LLLightState::setAmbient(const LLColor4& ambient) { ++gGL.mLightHash; mAmbient = ambient; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_AMBIENT, mAmbient.mV); - } } } @@ -975,10 +749,6 @@ void LLLightState::setSpecular(const LLColor4& specular) { ++gGL.mLightHash; mSpecular = specular; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_SPECULAR, mSpecular.mV); - } } } @@ -987,20 +757,11 @@ void LLLightState::setPosition(const LLVector4& position) //always set position because modelview matrix may have changed ++gGL.mLightHash; mPosition = position; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_POSITION, mPosition.mV); - } - else - { //transform position by current modelview matrix - glh::vec4f pos(position.mV); - - const glh::matrix4f& mat = gGL.getModelviewMatrix(); - mat.mult_matrix_vec(pos); - - mPosition.set(pos.v); - } - + //transform position by current modelview matrix + glh::vec4f pos(position.mV); + const glh::matrix4f& mat = gGL.getModelviewMatrix(); + mat.mult_matrix_vec(pos); + mPosition.set(pos.v); } void LLLightState::setConstantAttenuation(const F32& atten) @@ -1009,10 +770,6 @@ void LLLightState::setConstantAttenuation(const F32& atten) { mConstantAtten = atten; ++gGL.mLightHash; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_CONSTANT_ATTENUATION, atten); - } } } @@ -1022,10 +779,6 @@ void LLLightState::setLinearAttenuation(const F32& atten) { ++gGL.mLightHash; mLinearAtten = atten; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_LINEAR_ATTENUATION, atten); - } } } @@ -1035,10 +788,6 @@ void LLLightState::setQuadraticAttenuation(const F32& atten) { ++gGL.mLightHash; mQuadraticAtten = atten; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_QUADRATIC_ATTENUATION, atten); - } } } @@ -1048,10 +797,6 @@ void LLLightState::setSpotExponent(const F32& exponent) { ++gGL.mLightHash; mSpotExponent = exponent; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_SPOT_EXPONENT, exponent); - } } } @@ -1061,10 +806,6 @@ void LLLightState::setSpotCutoff(const F32& cutoff) { ++gGL.mLightHash; mSpotCutoff = cutoff; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightf(GL_LIGHT0+mIndex, GL_SPOT_CUTOFF, cutoff); - } } } @@ -1073,19 +814,12 @@ void LLLightState::setSpotDirection(const LLVector3& direction) //always set direction because modelview matrix may have changed ++gGL.mLightHash; mSpotDirection = direction; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightfv(GL_LIGHT0+mIndex, GL_SPOT_DIRECTION, direction.mV); - } - else - { //transform direction by current modelview matrix - glh::vec3f dir(direction.mV); - - const glh::matrix4f& mat = gGL.getModelviewMatrix(); - mat.mult_matrix_dir(dir); + //transform direction by current modelview matrix + glh::vec3f dir(direction.mV); + const glh::matrix4f& mat = gGL.getModelviewMatrix(); + mat.mult_matrix_dir(dir); - mSpotDirection.set(dir.v); - } + mSpotDirection.set(dir.v); } LLRender::LLRender() @@ -1113,8 +847,6 @@ LLRender::LLRender() mCurrColorMask[i] = true; } - mCurrAlphaFunc = CF_DEFAULT; - mCurrAlphaFuncVal = 0.01f; mCurrBlendColorSFactor = BF_UNDEF; mCurrBlendAlphaSFactor = BF_UNDEF; mCurrBlendColorDFactor = BF_UNDEF; @@ -1139,6 +871,23 @@ LLRender::~LLRender() void LLRender::init() { +#if LL_WINDOWS + if (gGLManager.mHasDebugOutput && gDebugGL) + { //setup debug output callback + //glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE); + glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + } +#endif + + glPixelStorei(GL_PACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + gGL.setAmbientLightColor(LLColor4::black); + + glCullFace(GL_BACK); + if (sGLCoreProfile && !LLVertexBuffer::sUseVAO) { //bind a dummy vertex array object so we're core profile compliant #ifdef GL_ARB_vertex_array_object @@ -1192,7 +941,7 @@ void LLRender::refreshState(void) setColorMask(mCurrColorMask[0], mCurrColorMask[1], mCurrColorMask[2], mCurrColorMask[3]); - setAlphaRejectSettings(mCurrAlphaFunc, mCurrAlphaFuncVal); + flush(); mDirty = false; } @@ -1243,9 +992,7 @@ void LLRender::syncLightState() void LLRender::syncMatrices() { - stop_glerror(); - - static const U32 name[] = + static const U32 name[] = { LLShaderMgr::MODELVIEW_MATRIX, LLShaderMgr::PROJECTION_MATRIX, @@ -1382,41 +1129,6 @@ void LLRender::syncMatrices() syncLightState(); } } - else if (!LLGLSLShader::sNoFixedFunction) - { - static const GLenum mode[] = - { - GL_MODELVIEW, - GL_PROJECTION, - GL_TEXTURE, - GL_TEXTURE, - GL_TEXTURE, - GL_TEXTURE, - }; - - for (U32 i = 0; i < MM_TEXTURE0; ++i) - { - if (mMatHash[i] != mCurMatHash[i]) - { - glMatrixMode(mode[i]); - glLoadMatrixf(mMatrix[i][mMatIdx[i]].m); - mCurMatHash[i] = mMatHash[i]; - } - } - - for (U32 i = MM_TEXTURE0; i < NUM_MATRIX_MODES; ++i) - { - if (mMatHash[i] != mCurMatHash[i]) - { - gGL.getTexUnit(i-MM_TEXTURE0)->activate(); - glMatrixMode(mode[i]); - glLoadMatrixf(mMatrix[i][mMatIdx[i]].m); - mCurMatHash[i] = mMatHash[i]; - } - } - } - - stop_glerror(); } void LLRender::translatef(const GLfloat& x, const GLfloat& y, const GLfloat& z) @@ -1732,55 +1444,6 @@ void LLRender::setSceneBlendType(eBlendType type) } } -void LLRender::setAlphaRejectSettings(eCompareFunc func, F32 value) -{ - flush(); - - if (LLGLSLShader::sNoFixedFunction) - { //glAlphaFunc is deprecated in OpenGL 3.3 - return; - } - - if (mCurrAlphaFunc != func || - mCurrAlphaFuncVal != value) - { - mCurrAlphaFunc = func; - mCurrAlphaFuncVal = value; - if (func == CF_DEFAULT) - { - glAlphaFunc(GL_GREATER, 0.01f); - } - else - { - glAlphaFunc(sGLCompareFunc[func], value); - } - } - - if (gDebugGL) - { //make sure cached state is correct - GLint cur_func = 0; - glGetIntegerv(GL_ALPHA_TEST_FUNC, &cur_func); - - if (func == CF_DEFAULT) - { - func = CF_GREATER; - } - - if (cur_func != sGLCompareFunc[func]) - { - LL_ERRS() << "Alpha test function corrupted!" << LL_ENDL; - } - - F32 ref = 0.f; - glGetFloatv(GL_ALPHA_TEST_REF, &ref); - - if (ref != value) - { - LL_ERRS() << "Alpha test value corrupted!" << LL_ENDL; - } - } -} - void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor) { llassert(sfactor < BF_UNDEF); @@ -1848,14 +1511,11 @@ LLLightState* LLRender::getLight(U32 index) void LLRender::setAmbientLightColor(const LLColor4& color) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE if (color != mAmbientLightColor) { ++mLightHash; mAmbientLightColor = color; - if (!LLGLSLShader::sNoFixedFunction) - { - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, color.mV); - } } } @@ -1926,6 +1586,7 @@ void LLRender::flush() { if (mCount > 0) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; if (!mUIOffset.empty()) { sUICalls++; @@ -2307,7 +1968,7 @@ void LLRender::color3fv(const GLfloat* c) void LLRender::diffuseColor3f(F32 r, F32 g, F32 b) { LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + llassert(shader != NULL); if (shader) { @@ -2322,7 +1983,7 @@ void LLRender::diffuseColor3f(F32 r, F32 g, F32 b) void LLRender::diffuseColor3fv(const F32* c) { LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + llassert(shader != NULL); if (shader) { @@ -2337,7 +1998,7 @@ void LLRender::diffuseColor3fv(const F32* c) void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) { LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + llassert(shader != NULL); if (shader) { @@ -2352,7 +2013,7 @@ void LLRender::diffuseColor4f(F32 r, F32 g, F32 b, F32 a) void LLRender::diffuseColor4fv(const F32* c) { LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + llassert(shader != NULL); if (shader) { @@ -2367,7 +2028,7 @@ void LLRender::diffuseColor4fv(const F32* c) void LLRender::diffuseColor4ubv(const U8* c) { LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + llassert(shader != NULL); if (shader) { @@ -2382,7 +2043,7 @@ void LLRender::diffuseColor4ubv(const U8* c) void LLRender::diffuseColor4ub(U8 r, U8 g, U8 b, U8 a) { LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - llassert(!LLGLSLShader::sNoFixedFunction || shader != NULL); + llassert(shader != NULL); if (shader) { diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index af8568f8a3..e2489876e4 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -105,10 +105,7 @@ public: TBO_LERP_VERT_ALPHA, // Interpolate based on Vertex Alpha (VA): ( Source1 * VA + Source2 * (1-VA) ) TBO_LERP_TEX_ALPHA, // Interpolate based on Texture Alpha (TA): ( Source1 * TA + Source2 * (1-TA) ) TBO_LERP_PREV_ALPHA, // Interpolate based on Previous Alpha (PA): ( Source1 * PA + Source2 * (1-PA) ) - TBO_LERP_CONST_ALPHA, // Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) ) - TBO_LERP_VERT_COLOR // Interpolate based on Vertex Col (VC): ( Source1 * VC + Source2 * (1-VC) ) - // *Note* TBO_LERP_VERTEX_COLOR only works with setTextureColorBlend(), - // and falls back to TBO_LERP_VERTEX_ALPHA for setTextureAlphaBlend(). + TBO_LERP_CONST_ALPHA // Interpolate based on Const Alpha (CA): ( Source1 * CA + Source2 * (1-CA) ) } eTextureBlendOp; typedef enum @@ -158,9 +155,20 @@ public: // Binds the LLImageGL to this texture unit // (automatically enables the unit for the LLImageGL's texture type) - bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false); + bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false, S32 usename = 0); bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false); + // bind implementation for inner loops + // makes the following assumptions: + // - No need for gGL.flush() + // - texture is not null + // - gl_tex->getTexName() is not zero + // - This texture is not being bound redundantly + // - USE_SRGB_DECODE is disabled + // - mTexOptionsDirty is false + // - + void bindFast(LLTexture* texture); + // Binds a cubemap to this texture unit // (automatically enables the texture unit for cubemaps) bool bind(LLCubeMap* cubeMap); @@ -177,6 +185,9 @@ public: // (only if there's a texture of the given type currently bound) void unbind(eTextureType type); + // Fast but unsafe version of unbind + void unbindFast(eTextureType type); + // Sets the addressing mode used to sample the texture // Warning: this stays set for the bound texture forever, // make sure you want to permanently change the address mode for the bound texture. @@ -187,15 +198,6 @@ public: // make sure you want to permanently change the filtering for the bound texture. void setTextureFilteringOption(LLTexUnit::eTextureFilterOptions option); - void setTextureBlendType(eTextureBlendType type); - - inline void setTextureColorBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_COLOR) - { setTextureCombiner(op, src1, src2, false); } - - // NOTE: If *_COLOR enums are passed to src1 or src2, the corresponding *_ALPHA enum will be used instead. - inline void setTextureAlphaBlend(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2 = TBS_PREV_ALPHA) - { setTextureCombiner(op, src1, src2, true); } - static U32 getInternalType(eTextureType type); U32 getCurrTexture(void) { return mCurrTexture; } @@ -212,13 +214,6 @@ protected: const S32 mIndex; U32 mCurrTexture; eTextureType mCurrTexType; - eTextureBlendType mCurrBlendType; - eTextureBlendOp mCurrColorOp; - eTextureBlendSrc mCurrColorSrc1; - eTextureBlendSrc mCurrColorSrc2; - eTextureBlendOp mCurrAlphaOp; - eTextureBlendSrc mCurrAlphaSrc1; - eTextureBlendSrc mCurrAlphaSrc2; eTextureColorSpace mTexColorSpace; S32 mCurrColorScale; S32 mCurrAlphaScale; @@ -229,7 +224,6 @@ protected: void setAlphaScale(S32 scale); GLint getTextureSource(eTextureBlendSrc src); GLint getTextureSourceType(eTextureBlendSrc src, bool isAlpha = false); - void setTextureCombiner(eTextureBlendOp op, eTextureBlendSrc src1, eTextureBlendSrc src2, bool isAlpha = false); }; class LLLightState @@ -430,8 +424,6 @@ public: void setColorMask(bool writeColorR, bool writeColorG, bool writeColorB, bool writeAlpha); void setSceneBlendType(eBlendType type); - void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f); - // applies blend func to both color and alpha void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor); // applies separate blend functions to color and alpha @@ -482,8 +474,6 @@ private: U32 mMode; U32 mCurrTextureUnitIndex; bool mCurrColorMask[4]; - eCompareFunc mCurrAlphaFunc; - F32 mCurrAlphaFuncVal; LLPointer<LLVertexBuffer> mBuffer; LLStrider<LLVector3> mVerticesp; @@ -511,7 +501,7 @@ extern F32 gGLLastProjection[16]; extern F32 gGLProjection[16]; extern S32 gGLViewport[4]; -extern LLRender gGL; +extern thread_local LLRender gGL; // This rotation matrix moves the default OpenGL reference frame // (-Z at, Y up) to Cory's favorite reference frame (X at, Z up) diff --git a/indra/llrender/llrender2dutils.cpp b/indra/llrender/llrender2dutils.cpp index dd34f3e383..5cb1dc6b25 100644 --- a/indra/llrender/llrender2dutils.cpp +++ b/indra/llrender/llrender2dutils.cpp @@ -132,40 +132,15 @@ void gl_rect_2d(S32 left, S32 top, S32 right, S32 bottom, BOOL filled ) } else { - if( gGLManager.mATIOffsetVerticalLines ) - { - // Work around bug in ATI driver: vertical lines are offset by (-1,-1) - gGL.begin( LLRender::LINES ); - - // Verticals - gGL.vertex2i(left + 1, top); - gGL.vertex2i(left + 1, bottom); - - gGL.vertex2i(right, bottom); - gGL.vertex2i(right, top); - - // Horizontals - top--; - right--; - gGL.vertex2i(left, bottom); - gGL.vertex2i(right, bottom); - - gGL.vertex2i(left, top); - gGL.vertex2i(right, top); - gGL.end(); - } - else - { - top--; - right--; - gGL.begin( LLRender::LINE_STRIP ); - gGL.vertex2i(left, top); - gGL.vertex2i(left, bottom); - gGL.vertex2i(right, bottom); - gGL.vertex2i(right, top); - gGL.vertex2i(left, top); - gGL.end(); - } + top--; + right--; + gGL.begin( LLRender::LINE_STRIP ); + gGL.vertex2i(left, top); + gGL.vertex2i(left, bottom); + gGL.vertex2i(right, bottom); + gGL.vertex2i(right, top); + gGL.vertex2i(left, top); + gGL.end(); } stop_glerror(); } @@ -250,15 +225,6 @@ void gl_drop_shadow(S32 left, S32 top, S32 right, S32 bottom, const LLColor4 &st void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 ) { - // Work around bug in ATI driver: vertical lines are offset by (-1,-1) - if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines ) - { - x1++; - x2++; - y1++; - y2++; - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.begin(LLRender::LINES); @@ -269,15 +235,6 @@ void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2 ) void gl_line_2d(S32 x1, S32 y1, S32 x2, S32 y2, const LLColor4 &color ) { - // Work around bug in ATI driver: vertical lines are offset by (-1,-1) - if( (x1 == x2) && gGLManager.mATIOffsetVerticalLines ) - { - x1++; - x2++; - y1++; - y2++; - } - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4fv( color.mV ); @@ -395,15 +352,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex if (solid_color) { - if (LLGLSLShader::sNoFixedFunction) - { - gSolidColorProgram.bind(); - } - else - { - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_VERT_ALPHA); - } + gSolidColorProgram.bind(); } if (center_rect.mLeft == 0.f @@ -650,14 +599,7 @@ void gl_draw_scaled_image_with_border(S32 x, S32 y, S32 width, S32 height, LLTex if (solid_color) { - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - else - { - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } + gUIProgram.bind(); } } @@ -774,10 +716,6 @@ void gl_draw_scaled_rotated_image(S32 x, S32 y, S32 width, S32 height, F32 degre void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LLColor4& color, F32 phase ) { - phase = fmod(phase, 1.f); - - S32 shift = S32(phase * 4.f) % 4; - // Stippled line LLGLEnable stipple(GL_LINE_STIPPLE); @@ -786,11 +724,6 @@ void gl_stippled_line_3d( const LLVector3& start, const LLVector3& end, const LL gGL.flush(); glLineWidth(2.5f); - if (!LLGLSLShader::sNoFixedFunction) - { - glLineStipple(2, 0x3333 << shift); - } - gGL.begin(LLRender::LINES); { gGL.vertex3fv( start.mV ); @@ -930,52 +863,16 @@ void gl_ring( F32 radius, F32 width, const LLColor4& center_color, const LLColor // Draw gray and white checkerboard with black border void gl_rect_2d_checkerboard(const LLRect& rect, GLfloat alpha) { - if (!LLGLSLShader::sNoFixedFunction) - { - // Initialize the first time this is called. - const S32 PIXELS = 32; - static GLubyte checkerboard[PIXELS * PIXELS]; - static BOOL first = TRUE; - if( first ) - { - for( S32 i = 0; i < PIXELS; i++ ) - { - for( S32 j = 0; j < PIXELS; j++ ) - { - checkerboard[i * PIXELS + j] = ((i & 1) ^ (j & 1)) * 0xFF; - } - } - first = FALSE; - } - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - // ...white squares - gGL.color4f( 1.f, 1.f, 1.f, alpha ); - gl_rect_2d(rect); - - // ...gray squares - gGL.color4f( .7f, .7f, .7f, alpha ); - gGL.flush(); + //polygon stipple is deprecated, use "Checker" texture + LLPointer<LLUIImage> img = LLRender2D::getInstance()->getUIImage("Checker"); + gGL.getTexUnit(0)->bind(img->getImage()); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - glPolygonStipple( checkerboard ); + LLColor4 color(1.f, 1.f, 1.f, alpha); + LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f); - LLGLEnable polygon_stipple(GL_POLYGON_STIPPLE); - gl_rect_2d(rect); - } - else - { //polygon stipple is deprecated, use "Checker" texture - LLPointer<LLUIImage> img = LLRender2D::getInstance()->getUIImage("Checker"); - gGL.getTexUnit(0)->bind(img->getImage()); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - - LLColor4 color(1.f, 1.f, 1.f, alpha); - LLRectf uv_rect(0, 0, rect.getWidth()/32.f, rect.getHeight()/32.f); - - gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), - img->getImage(), color, uv_rect); - } + gl_draw_scaled_image(rect.mLeft, rect.mBottom, rect.getWidth(), rect.getHeight(), img->getImage(), color, uv_rect); gGL.flush(); } @@ -1083,8 +980,6 @@ void gl_rect_2d_simple( S32 width, S32 height ) gGL.end(); } -static LLTrace::BlockTimerStatHandle FTM_RENDER_SEGMENTED_RECT ("Render segmented rectangle"); - void gl_segmented_rect_2d_tex(const S32 left, const S32 top, const S32 right, @@ -1094,7 +989,7 @@ void gl_segmented_rect_2d_tex(const S32 left, const S32 border_size, const U32 edges) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; S32 width = llabs(right - left); S32 height = llabs(top - bottom); @@ -1253,7 +1148,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect, const F32 end_fragment, const U32 edges) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; const S32 left = rect.mLeft; const S32 right = rect.mRight; const S32 top = rect.mTop; @@ -1440,7 +1335,7 @@ void gl_segmented_rect_2d_fragment_tex(const LLRect& rect, void gl_segmented_rect_3d_tex(const LLRectf& clip_rect, const LLRectf& center_uv_rect, const LLRectf& center_draw_rect, const LLVector3& width_vec, const LLVector3& height_vec) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SEGMENTED_RECT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; gGL.begin(LLRender::QUADS); { diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index e3c0255290..0408010513 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -170,6 +170,53 @@ bool LLRenderTarget::allocate(U32 resx, U32 resy, U32 color_fmt, bool depth, boo return addColorAttachment(color_fmt); } +void LLRenderTarget::setColorAttachment(LLImageGL* img, LLGLuint use_name) +{ + LL_PROFILE_ZONE_SCOPED; + llassert(img != nullptr); // img must not be null + llassert(sUseFBO); // FBO support must be enabled + llassert(mDepth == 0); // depth buffers not supported with this mode + llassert(mTex.empty()); // mTex must be empty with this mode (binding target should be done via LLImageGL) + + if (mFBO == 0) + { + glGenFramebuffers(1, (GLuint*)&mFBO); + } + + mResX = img->getWidth(); + mResY = img->getHeight(); + mUsage = img->getTarget(); + + if (use_name == 0) + { + use_name = img->getTexName(); + } + + mTex.push_back(use_name); + + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + LLTexUnit::getInternalType(mUsage), use_name, 0); + stop_glerror(); + + check_framebuffer_status(); + + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); +} + +void LLRenderTarget::releaseColorAttachment() +{ + LL_PROFILE_ZONE_SCOPED; + llassert(mTex.size() == 1); //cannot use releaseColorAttachment with LLRenderTarget managed color targets + llassert(mFBO != 0); // mFBO must be valid + + glBindFramebuffer(GL_FRAMEBUFFER, mFBO); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, LLTexUnit::getInternalType(mUsage), 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, sCurFBO); + + mTex.clear(); +} + bool LLRenderTarget::addColorAttachment(U32 color_fmt) { if (color_fmt == 0) @@ -437,11 +484,13 @@ void LLRenderTarget::bindTarget() GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3}; + LL_PROFILER_GPU_ZONEC( "gl.DrawBuffersARB", 0x4000FF ) glDrawBuffersARB(mTex.size(), drawbuffers); } if (mTex.empty()) { //no color buffer to draw to + LL_PROFILER_GPU_ZONEC( "gl.DrawBuffer", 0x0000FF ) glDrawBuffer(GL_NONE); glReadBuffer(GL_NONE); } diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 6c07ac5b1c..584f224dca 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -81,6 +81,24 @@ public: // DO use for render targets that resize often and aren't likely to ruin someone's day if they break void resize(U32 resx, U32 resy); + //point this render target at a particular LLImageGL + // Intended usage: + // LLRenderTarget target; + // target.addColorAttachment(image); + // target.bindTarget(); + // < issue GL calls> + // target.flush(); + // target.releaseColorAttachment(); + // + // attachment -- LLImageGL to render into + // use_name -- optional texture name to target instead of attachment->getTexName() + // NOTE: setColorAttachment and releaseColorAttachment cannot be used in conjuction with + // addColorAttachment, allocateDepth, resize, etc. + void setColorAttachment(LLImageGL* attachment, LLGLuint use_name = 0); + + // detach from current color attachment + void releaseColorAttachment(); + //add color buffer attachment //limit of 4 color attachments per render target bool addColorAttachment(U32 color_fmt); diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index e8c6295930..c100c182dd 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -165,6 +165,7 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) if (features->hasObjectSkinning) { + shader->mRiggedVariant = shader; if (!shader->attachVertexObject("avatar/objectSkinV.glsl")) { return FALSE; @@ -599,7 +600,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns, const std::string& } } -GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines, S32 texture_index_channels) +GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::unordered_map<std::string, std::string>* defines, S32 texture_index_channels) { // endsure work-around for missing GLSL funcs gets propogated to feature shader files (e.g. srgbF.glsl) @@ -774,14 +775,14 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade if (defines) { - for (boost::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter) + for (std::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter) { std::string define = "#define " + iter->first + " " + iter->second + "\n"; extra_code_text[extra_code_count++] = (GLcharARB *) strdup(define.c_str()); } } - if( gGLManager.mIsATI ) + if( gGLManager.mIsAMD ) { extra_code_text[extra_code_count++] = strdup( "#define IS_AMD_CARD 1\n" ); } @@ -1053,43 +1054,6 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) LL_SHADER_LOADING_WARNS() << "GLSL Linker Error:" << LL_ENDL; } -#if LL_DARWIN - - // For some reason this absolutely kills the frame rate when VBO's are enabled - if (0) - { - // Force an evaluation of the gl state so the driver can tell if the shader will run in hardware or software - // per Apple's suggestion - LLGLSLShader::sNoFixedFunction = false; - - glUseProgramObjectARB(obj); - - gGL.begin(LLRender::TRIANGLES); - gGL.vertex3f(0.0f, 0.0f, 0.0f); - gGL.vertex3f(0.0f, 0.0f, 0.0f); - gGL.vertex3f(0.0f, 0.0f, 0.0f); - gGL.end(); - gGL.flush(); - - glUseProgramObjectARB(0); - - LLGLSLShader::sNoFixedFunction = true; - - // Query whether the shader can or cannot run in hardware - // http://developer.apple.com/qa/qa2007/qa1502.html - GLint vertexGPUProcessing, fragmentGPUProcessing; - CGLContextObj ctx = CGLGetCurrentContext(); - CGLGetParameter(ctx, kCGLCPGPUVertexProcessing, &vertexGPUProcessing); - CGLGetParameter(ctx, kCGLCPGPUFragmentProcessing, &fragmentGPUProcessing); - if (!fragmentGPUProcessing || !vertexGPUProcessing) - { - LL_SHADER_LOADING_WARNS() << "GLSL Linker: Running in Software:" << LL_ENDL; - success = GL_FALSE; - suppress_errors = FALSE; - } - } - -#else std::string log = get_object_log(obj); LLStringUtil::toLower(log); if (log.find("software") != std::string::npos) @@ -1098,7 +1062,6 @@ BOOL LLShaderMgr::linkProgramObject(GLhandleARB obj, BOOL suppress_errors) success = GL_FALSE; suppress_errors = FALSE; } -#endif return success; } diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 3908efd4ec..67c0d6ab10 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -264,7 +264,7 @@ public: void dumpShaderSource(U32 shader_code_count, GLcharARB** shader_code_text); BOOL linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE); BOOL validateProgramObject(GLhandleARB obj); - GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1); + GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, std::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1); // Implemented in the application to actually point to the shader directory. virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h index 41481fb8a7..e890a5a30b 100644 --- a/indra/llrender/lltexture.h +++ b/indra/llrender/lltexture.h @@ -42,7 +42,7 @@ class LLFontGL ; // //this is an abstract class as the parent for the class LLGLTexture // -class LLTexture : public virtual LLRefCount, public LLTrace::MemTrackable<LLTexture> +class LLTexture : public virtual LLRefCount { friend class LLTexUnit ; friend class LLFontGL ; @@ -52,7 +52,6 @@ protected: public: LLTexture() - : LLTrace::MemTrackable<LLTexture>("LLTexture") {} // @@ -67,11 +66,9 @@ public: virtual S32 getWidth(S32 discard_level = -1) const; virtual S32 getHeight(S32 discard_level = -1) const; virtual bool isActiveFetching(); + virtual LLImageGL* getGLTexture() const; private: - //note: do not make this function public. - virtual LLImageGL* getGLTexture() const; - virtual void updateBindStatsForTester(); }; #endif diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 7d2b09ca4a..6338cab96a 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -91,6 +91,8 @@ LLVBOPool LLVertexBuffer::sDynamicIBOPool(GL_DYNAMIC_DRAW_ARB, GL_ELEMENT_ARRAY_ U32 LLVBOPool::sBytesPooled = 0; U32 LLVBOPool::sIndexBytesPooled = 0; +U32 LLVBOPool::sNameIdx = 0; +U32 LLVBOPool::sNamePool[1024]; std::list<U32> LLVertexBuffer::sAvailableVAOName; U32 LLVertexBuffer::sCurVAOName = 1; @@ -121,15 +123,20 @@ bool LLVertexBuffer::sPreferStreamDraw = false; U32 LLVBOPool::genBuffer() { - U32 ret = 0; + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX - glGenBuffersARB(1, &ret); - - return ret; + if (sNameIdx == 0) + { + glGenBuffersARB(1024, sNamePool); + sNameIdx = 1024; + } + + return sNamePool[--sNameIdx]; } void LLVBOPool::deleteBuffer(U32 name) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX if (gGLManager.mInited) { LLVertexBuffer::unbind(); @@ -150,11 +157,12 @@ LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType) std::fill(mMissCount.begin(), mMissCount.end(), 0); } -volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) +U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX llassert(vbo_block_size(size) == size); - volatile U8* ret = NULL; + U8* ret = NULL; U32 i = vbo_block_index(size); @@ -248,7 +256,7 @@ volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) return ret; } -void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) +void LLVBOPool::release(U32 name, U8* buffer, U32 size) { llassert(vbo_block_size(size) == size); @@ -267,10 +275,12 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) void LLVBOPool::seedPool() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX U32 dummy_name = 0; if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT) { + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("VBOPool Resize"); mFreeList.resize(LL_VBO_POOL_SEED_COUNT); } @@ -411,6 +421,7 @@ void LLVertexBuffer::releaseVAOName(U32 name) //static void LLVertexBuffer::seedPools() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX sStreamVBOPool.seedPool(); sDynamicVBOPool.seedPool(); sDynamicCopyVBOPool.seedPool(); @@ -430,135 +441,26 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) data_mask = data_mask & ~MAP_TEXTURE_INDEX; } - if (LLGLSLShader::sNoFixedFunction) + for (U32 i = 0; i < TYPE_MAX; ++i) { - for (U32 i = 0; i < TYPE_MAX; ++i) - { - S32 loc = i; + S32 loc = i; - U32 mask = 1 << i; - - if (sLastMask & (1 << i)) - { //was enabled - if (!(data_mask & mask)) - { //needs to be disabled - glDisableVertexAttribArrayARB(loc); - } - } - else - { //was disabled - if (data_mask & mask) - { //needs to be enabled - glEnableVertexAttribArrayARB(loc); - } - } - } - } - else - { - - static const GLenum array[] = - { - GL_VERTEX_ARRAY, - GL_NORMAL_ARRAY, - GL_TEXTURE_COORD_ARRAY, - GL_COLOR_ARRAY, - }; - - static const GLenum mask[] = - { - MAP_VERTEX, - MAP_NORMAL, - MAP_TEXCOORD0, - MAP_COLOR - }; - - - - for (U32 i = 0; i < 4; ++i) - { - if (sLastMask & mask[i]) - { //was enabled - if (!(data_mask & mask[i])) - { //needs to be disabled - glDisableClientState(array[i]); - } - else if (gDebugGL) - { //needs to be enabled, make sure it was (DEBUG) - if (!glIsEnabled(array[i])) - { - if (gDebugSession) - { - gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl; - } - else - { - LL_ERRS() << "Bad client state! " << array[i] << " disabled." << LL_ENDL; - } - } - } - } - else - { //was disabled - if (data_mask & mask[i]) - { //needs to be enabled - glEnableClientState(array[i]); - } - else if (gDebugGL && glIsEnabled(array[i])) - { //needs to be disabled, make sure it was (DEBUG TEMPORARY) - if (gDebugSession) - { - gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl; - } - else - { - LL_ERRS() << "Bad client state! " << array[i] << " enabled." << LL_ENDL; - } - } - } - } - - static const U32 map_tc[] = - { - MAP_TEXCOORD1, - MAP_TEXCOORD2, - MAP_TEXCOORD3 - }; + U32 mask = 1 << i; - for (U32 i = 0; i < 3; i++) - { - if (sLastMask & map_tc[i]) - { - if (!(data_mask & map_tc[i])) - { //disable - glClientActiveTextureARB(GL_TEXTURE1_ARB+i); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - } - else if (data_mask & map_tc[i]) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB+i); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); + if (sLastMask & (1 << i)) + { //was enabled + if (!(data_mask & mask)) + { //needs to be disabled + glDisableVertexAttribArrayARB(loc); } } - - if (sLastMask & MAP_TANGENT) - { - if (!(data_mask & MAP_TANGENT)) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); + else + { //was disabled + if (data_mask & mask) + { //needs to be enabled + glEnableVertexAttribArrayARB(loc); } } - else if (data_mask & MAP_TANGENT) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } } sLastMask = data_mask; @@ -566,63 +468,23 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } //static -static LLTrace::BlockTimerStatHandle FTM_VB_DRAW_ARRAYS("drawArrays"); -void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm) +void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos) { - LL_RECORD_BLOCK_TIME(FTM_VB_DRAW_ARRAYS); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - gGL.syncMatrices(); - - U32 count = pos.size(); - - llassert(norm.size() >= pos.size()); - llassert(count > 0); - - if( count == 0 ) - { - LL_WARNS() << "Called drawArrays with 0 vertices" << LL_ENDL; - return; - } - - if( norm.size() < pos.size() ) - { - LL_WARNS() << "Called drawArrays with #" << norm.size() << " normals and #" << pos.size() << " vertices" << LL_ENDL; - return; - } - - unbind(); - - setupClientArrays(MAP_VERTEX | MAP_NORMAL); - - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - - if (shader) - { - S32 loc = LLVertexBuffer::TYPE_VERTEX; - if (loc > -1) - { - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, pos[0].mV); - } - loc = LLVertexBuffer::TYPE_NORMAL; - if (loc > -1) - { - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 0, norm[0].mV); - } - } - else - { - glVertexPointer(3, GL_FLOAT, 0, pos[0].mV); - glNormalPointer(GL_FLOAT, 0, norm[0].mV); - } - LLGLSLShader::startProfile(); - glDrawArrays(sGLMode[mode], 0, count); - LLGLSLShader::stopProfile(count, mode); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + gGL.begin(mode); + for (auto& v : pos) + { + gGL.vertex3fv(v.mV); + } + gGL.end(); + gGL.flush(); } //static void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp) { - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + llassert(LLGLSLShader::sCurBoundShaderPtr != NULL); gGL.syncMatrices(); @@ -634,28 +496,27 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto unbind(); - setupClientArrays(mask); - - if (LLGLSLShader::sNoFixedFunction) - { - S32 loc = LLVertexBuffer::TYPE_VERTEX; - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, 16, pos); - - if (tc) - { - loc = LLVertexBuffer::TYPE_TEXCOORD0; - glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, 0, tc); - } - } - else - { - glTexCoordPointer(2, GL_FLOAT, 0, tc); - glVertexPointer(3, GL_FLOAT, 16, pos); - } - - LLGLSLShader::startProfile(); - glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp); - LLGLSLShader::stopProfile(num_indices, mode); + gGL.begin(mode); + + if (tc != nullptr) + { + for (int i = 0; i < num_indices; ++i) + { + U16 idx = indicesp[i]; + gGL.texCoord2fv(tc[idx].mV); + gGL.vertex3fv(pos[idx].getF32ptr()); + } + } + else + { + for (int i = 0; i < num_indices; ++i) + { + U16 idx = indicesp[i]; + gGL.vertex3fv(pos[idx].getF32ptr()); + } + } + gGL.end(); + gGL.flush(); } void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const @@ -720,7 +581,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi gGL.syncMatrices(); llassert(mNumVerts >= 0); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + llassert(LLGLSLShader::sCurBoundShaderPtr != NULL); if (mGLArray) { @@ -763,6 +624,7 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi stop_glerror(); LLGLSLShader::startProfile(); + LL_PROFILER_GPU_ZONEC( "gl.DrawRangeElements", 0xFFFF00 ) glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, idx); LLGLSLShader::stopProfile(count, mode); @@ -773,9 +635,21 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi placeFence(); } +void LLVertexBuffer::drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const +{ + mMappable = false; + gGL.syncMatrices(); + + U16* idx = ((U16*)getIndicesPointer()) + indices_offset; + + LL_PROFILER_GPU_ZONEC("gl.DrawRangeElements", 0xFFFF00) + glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, + idx); +} + void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const { - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); + llassert(LLGLSLShader::sCurBoundShaderPtr != NULL); mMappable = false; gGL.syncMatrices(); @@ -814,6 +688,7 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const stop_glerror(); LLGLSLShader::startProfile(); + LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0xA0FFA0 ) glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT, ((U16*) getIndicesPointer()) + indices_offset); LLGLSLShader::stopProfile(count, mode); @@ -821,53 +696,53 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const placeFence(); } -static LLTrace::BlockTimerStatHandle FTM_GL_DRAW_ARRAYS("GL draw arrays"); + void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const { - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShaderPtr != NULL); - mMappable = false; - gGL.syncMatrices(); - - llassert(mNumVerts >= 0); - if (first >= (U32) mNumVerts || - first + count > (U32) mNumVerts) - { - LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first+count << "]" << LL_ENDL; - } - - if (mGLArray) - { - if (mGLArray != sGLRenderArray) - { - LL_ERRS() << "Wrong vertex array bound." << LL_ENDL; - } - } - else - { - if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive) - { - LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL; - } - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; + llassert(LLGLSLShader::sCurBoundShaderPtr != NULL); + mMappable = false; + gGL.syncMatrices(); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + llassert(mNumVerts >= 0); + if (first >= (U32)mNumVerts || + first + count > (U32)mNumVerts) + { + LL_ERRS() << "Bad vertex buffer draw range: [" << first << ", " << first + count << "]" << LL_ENDL; + } + + if (mGLArray) + { + if (mGLArray != sGLRenderArray) + { + LL_ERRS() << "Wrong vertex array bound." << LL_ENDL; + } + } + else + { + if (mGLBuffer != sGLRenderBuffer || useVBOs() != sVBOActive) + { + LL_ERRS() << "Wrong vertex buffer bound." << LL_ENDL; + } + } + + if (mode >= LLRender::NUM_MODES) + { + LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL; + return; + } +#endif - if (mode >= LLRender::NUM_MODES) - { - LL_ERRS() << "Invalid draw mode: " << mode << LL_ENDL; - return; - } + LLGLSLShader::startProfile(); + { + LL_PROFILER_GPU_ZONEC("gl.DrawArrays", 0xFF4040) + glDrawArrays(sGLMode[mode], first, count); + } + LLGLSLShader::stopProfile(count, mode); - { - LL_RECORD_BLOCK_TIME(FTM_GL_DRAW_ARRAYS); - stop_glerror(); - LLGLSLShader::startProfile(); - stop_glerror(); - glDrawArrays(sGLMode[mode], first, count); - stop_glerror(); - LLGLSLShader::stopProfile(count, mode); - } - - stop_glerror(); - placeFence(); + stop_glerror(); + placeFence(); } //static @@ -964,8 +839,7 @@ S32 LLVertexBuffer::determineUsage(S32 usage) } LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) -: LLTrace::MemTrackable<LLVertexBuffer>("LLVertexBuffer"), - LLRefCount(), +: LLRefCount(), mNumVerts(0), mNumIndices(0), @@ -1110,9 +984,7 @@ void LLVertexBuffer::waitFence() const void LLVertexBuffer::genBuffer(U32 size) { - disclaimMem(mSize); mSize = vbo_block_size(size); - claimMem(mSize); if (mUsage == GL_STREAM_DRAW_ARB) { @@ -1208,9 +1080,7 @@ bool LLVertexBuffer::createGLBuffer(U32 size) static int gl_buffer_idx = 0; mGLBuffer = ++gl_buffer_idx; mMappedData = (U8*)ll_aligned_malloc_16(size); - disclaimMem(mSize); mSize = size; - claimMem(mSize); } if (!mMappedData) @@ -1380,8 +1250,6 @@ bool LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) return success; } -static LLTrace::BlockTimerStatHandle FTM_SETUP_VERTEX_ARRAY("Setup VAO"); - void LLVertexBuffer::setupVertexArray() { if (!mGLArray) @@ -1389,7 +1257,7 @@ void LLVertexBuffer::setupVertexArray() return; } - LL_RECORD_BLOCK_TIME(FTM_SETUP_VERTEX_ARRAY); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; #if GL_ARB_vertex_array_object glBindVertexArray(mGLArray); #endif @@ -1562,12 +1430,11 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 index, S32 count) return true; } -static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_BUFFER_RANGE("VBO Map Range"); -static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_BUFFER("VBO Map"); // Map for data access -volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) +U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; bindGLBuffer(true); if (mFinal) { @@ -1627,14 +1494,13 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo } else { - volatile U8* src = NULL; + U8* src = NULL; waitFence(); if (gGLManager.mHasMapBufferRange) { if (map_range) { #ifdef GL_ARB_map_buffer_range - LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_BUFFER_RANGE); S32 offset = mOffsets[type] + sTypeSize[type]*index; S32 length = (sTypeSize[type]*count+0xF) & ~0xF; src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, offset, length, @@ -1658,7 +1524,6 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo } } - LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_BUFFER); src = (U8*) glMapBufferRange(GL_ARRAY_BUFFER_ARB, 0, mSize, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); @@ -1688,7 +1553,7 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo llassert(src != NULL); - mMappedData = LL_NEXT_ALIGNED_ADDRESS<volatile U8>(src); + mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src); mAlignedOffset = mMappedData - src; stop_glerror(); @@ -1744,11 +1609,9 @@ volatile U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, boo } -static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_INDEX_RANGE("IBO Map Range"); -static LLTrace::BlockTimerStatHandle FTM_VBO_MAP_INDEX("IBO Map"); - -volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) +U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; bindGLIndices(true); if (mFinal) { @@ -1816,14 +1679,13 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range } else { - volatile U8* src = NULL; + U8* src = NULL; waitFence(); if (gGLManager.mHasMapBufferRange) { if (map_range) { #ifdef GL_ARB_map_buffer_range - LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX_RANGE); S32 offset = sizeof(U16)*index; S32 length = sizeof(U16)*count; src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length, @@ -1835,7 +1697,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range else { #ifdef GL_ARB_map_buffer_range - LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX); src = (U8*) glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, 0, sizeof(U16)*mNumIndices, GL_MAP_WRITE_BIT | GL_MAP_FLUSH_EXPLICIT_BIT); @@ -1859,7 +1720,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range } else { - LL_RECORD_BLOCK_TIME(FTM_VBO_MAP_INDEX); map_range = false; src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); } @@ -1910,13 +1770,6 @@ volatile U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range } } -static LLTrace::BlockTimerStatHandle FTM_VBO_UNMAP("VBO Unmap"); -static LLTrace::BlockTimerStatHandle FTM_VBO_FLUSH_RANGE("Flush VBO Range"); - - -static LLTrace::BlockTimerStatHandle FTM_IBO_UNMAP("IBO Unmap"); -static LLTrace::BlockTimerStatHandle FTM_IBO_FLUSH_RANGE("Flush IBO Range"); - void LLVertexBuffer::unmapBuffer() { if (!useVBOs()) @@ -1925,10 +1778,10 @@ void LLVertexBuffer::unmapBuffer() } bool updated_all = false; - + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; if (mMappedData && mVertexLocked) { - LL_RECORD_BLOCK_TIME(FTM_VBO_UNMAP); + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - vertex"); bindGLBuffer(true); updated_all = mIndexLocked; //both vertex and index buffers done updating @@ -1975,7 +1828,7 @@ void LLVertexBuffer::unmapBuffer() { if (!mMappedVertexRegions.empty()) { - stop_glerror(); + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - flush vertex"); for (U32 i = 0; i < mMappedVertexRegions.size(); ++i) { const MappedRegion& region = mMappedVertexRegions[i]; @@ -1983,18 +1836,16 @@ void LLVertexBuffer::unmapBuffer() S32 length = sTypeSize[region.mType]*region.mCount; if (gGLManager.mHasMapBufferRange) { - LL_RECORD_BLOCK_TIME(FTM_VBO_FLUSH_RANGE); #ifdef GL_ARB_map_buffer_range glFlushMappedBufferRange(GL_ARRAY_BUFFER_ARB, offset, length); #endif } else if (gGLManager.mHasFlushBufferRange) - { + { #ifndef LL_MESA_HEADLESS glFlushMappedBufferRangeAPPLE(GL_ARRAY_BUFFER_ARB, offset, length); #endif } - stop_glerror(); } mMappedVertexRegions.clear(); @@ -2013,7 +1864,7 @@ void LLVertexBuffer::unmapBuffer() if (mMappedIndexData && mIndexLocked) { - LL_RECORD_BLOCK_TIME(FTM_IBO_UNMAP); + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - index"); bindGLIndices(); if(!mMappable) { @@ -2059,12 +1910,12 @@ void LLVertexBuffer::unmapBuffer() { for (U32 i = 0; i < mMappedIndexRegions.size(); ++i) { + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("unmapBuffer - flush index"); const MappedRegion& region = mMappedIndexRegions[i]; S32 offset = region.mIndex >= 0 ? sizeof(U16)*region.mIndex : 0; S32 length = sizeof(U16)*region.mCount; if (gGLManager.mHasMapBufferRange) { - LL_RECORD_BLOCK_TIME(FTM_IBO_FLUSH_RANGE); #ifdef GL_ARB_map_buffer_range glFlushMappedBufferRange(GL_ELEMENT_ARRAY_BUFFER_ARB, offset, length); #endif @@ -2083,9 +1934,8 @@ void LLVertexBuffer::unmapBuffer() mMappedIndexRegions.clear(); } } - stop_glerror(); - glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); - stop_glerror(); + + glUnmapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB); mMappedIndexData = NULL; } @@ -2111,7 +1961,7 @@ template <class T,S32 type> struct VertexBufferStrider { if (type == LLVertexBuffer::TYPE_INDEX) { - volatile U8* ptr = vbo.mapIndexBuffer(index, count, map_range); + U8* ptr = vbo.mapIndexBuffer(index, count, map_range); if (ptr == NULL) { @@ -2127,7 +1977,7 @@ template <class T,S32 type> struct VertexBufferStrider { S32 stride = LLVertexBuffer::sTypeSize[type]; - volatile U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); + U8* ptr = vbo.mapVertexBuffer(type, index, count, map_range); if (ptr == NULL) { @@ -2208,13 +2058,12 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 in //---------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_BIND_GL_ARRAY("Bind Array"); bool LLVertexBuffer::bindGLArray() { if (mGLArray && sGLRenderArray != mGLArray) { { - LL_RECORD_BLOCK_TIME(FTM_BIND_GL_ARRAY); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; #if GL_ARB_vertex_array_object glBindVertexArray(mGLArray); #endif @@ -2231,8 +2080,6 @@ bool LLVertexBuffer::bindGLArray() return false; } -static LLTrace::BlockTimerStatHandle FTM_BIND_GL_BUFFER("Bind Buffer"); - bool LLVertexBuffer::bindGLBuffer(bool force_bind) { bindGLArray(); @@ -2241,8 +2088,7 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind) if (useVBOs() && (force_bind || (mGLBuffer && (mGLBuffer != sGLRenderBuffer || !sVBOActive)))) { - //LL_RECORD_BLOCK_TIME(FTM_BIND_GL_BUFFER); - + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); sGLRenderBuffer = mGLBuffer; sBindCount++; @@ -2256,16 +2102,29 @@ bool LLVertexBuffer::bindGLBuffer(bool force_bind) return ret; } -static LLTrace::BlockTimerStatHandle FTM_BIND_GL_INDICES("Bind Indices"); +bool LLVertexBuffer::bindGLBufferFast() +{ + if (mGLBuffer != sGLRenderBuffer || !sVBOActive) + { + glBindBufferARB(GL_ARRAY_BUFFER_ARB, mGLBuffer); + sGLRenderBuffer = mGLBuffer; + sBindCount++; + sVBOActive = true; + + return true; + } + + return false; +} bool LLVertexBuffer::bindGLIndices(bool force_bind) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; bindGLArray(); bool ret = false; if (useVBOs() && (force_bind || (mGLIndices && (mGLIndices != sGLRenderIndices || !sIBOActive)))) { - LL_RECORD_BLOCK_TIME(FTM_BIND_GL_INDICES); /*if (sMapped) { LL_ERRS() << "VBO bound while another VBO mapped!" << LL_ENDL; @@ -2281,6 +2140,21 @@ bool LLVertexBuffer::bindGLIndices(bool force_bind) return ret; } +bool LLVertexBuffer::bindGLIndicesFast() +{ + if (mGLIndices != sGLRenderIndices || !sIBOActive) + { + glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mGLIndices); + sGLRenderIndices = mGLIndices; + sBindCount++; + sIBOActive = true; + + return true; + } + + return false; +} + void LLVertexBuffer::flush() { if (useVBOs()) @@ -2471,11 +2345,39 @@ void LLVertexBuffer::setBuffer(U32 data_mask) } } +void LLVertexBuffer::setBufferFast(U32 data_mask) +{ + if (useVBOs()) + { + //set up pointers if the data mask is different ... + bool setup = (sLastMask != data_mask); + + const bool bindBuffer = bindGLBufferFast(); + const bool bindIndices = bindGLIndicesFast(); + + setup = setup || bindBuffer || bindIndices; + + setupClientArrays(data_mask); + + if (data_mask && setup) + { + setupVertexBufferFast(data_mask); + sSetCount++; + } + } + else + { + //fallback to slow path when not using VBOs + setBuffer(data_mask); + } +} + + // virtual (default) void LLVertexBuffer::setupVertexBuffer(U32 data_mask) { stop_glerror(); - volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; + U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; if (gDebugGL && ((data_mask & mTypeMask) != data_mask)) { @@ -2490,144 +2392,191 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL; } - if (LLGLSLShader::sNoFixedFunction) + if (data_mask & MAP_NORMAL) { - if (data_mask & MAP_NORMAL) - { - S32 loc = TYPE_NORMAL; - void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]); - glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr); - } - if (data_mask & MAP_TEXCOORD3) - { - S32 loc = TYPE_TEXCOORD3; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr); - } - if (data_mask & MAP_TEXCOORD2) - { - S32 loc = TYPE_TEXCOORD2; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr); - } - if (data_mask & MAP_TEXCOORD1) - { - S32 loc = TYPE_TEXCOORD1; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); - } - if (data_mask & MAP_TANGENT) - { - S32 loc = TYPE_TANGENT; - void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]); - glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr); - } - if (data_mask & MAP_TEXCOORD0) - { - S32 loc = TYPE_TEXCOORD0; - void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]); - glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr); - } - if (data_mask & MAP_COLOR) - { - S32 loc = TYPE_COLOR; - //bind emissive instead of color pointer if emissive is present - void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]); - glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); - } - if (data_mask & MAP_EMISSIVE) - { - S32 loc = TYPE_EMISSIVE; - void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]); - glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); + S32 loc = TYPE_NORMAL; + void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]); + glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr); + } + if (data_mask & MAP_TEXCOORD3) + { + S32 loc = TYPE_TEXCOORD3; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]); + glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr); + } + if (data_mask & MAP_TEXCOORD2) + { + S32 loc = TYPE_TEXCOORD2; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]); + glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr); + } + if (data_mask & MAP_TEXCOORD1) + { + S32 loc = TYPE_TEXCOORD1; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); + glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); + } + if (data_mask & MAP_TANGENT) + { + S32 loc = TYPE_TANGENT; + void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]); + glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr); + } + if (data_mask & MAP_TEXCOORD0) + { + S32 loc = TYPE_TEXCOORD0; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]); + glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr); + } + if (data_mask & MAP_COLOR) + { + S32 loc = TYPE_COLOR; + //bind emissive instead of color pointer if emissive is present + void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]); + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); + } + if (data_mask & MAP_EMISSIVE) + { + S32 loc = TYPE_EMISSIVE; + void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]); + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); - if (!(data_mask & MAP_COLOR)) - { //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps - loc = TYPE_COLOR; - glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); - } - } - if (data_mask & MAP_WEIGHT) - { - S32 loc = TYPE_WEIGHT; - void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]); - glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr); - } - if (data_mask & MAP_WEIGHT4) - { - S32 loc = TYPE_WEIGHT4; - void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]); - glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); - } - if (data_mask & MAP_CLOTHWEIGHT) - { - S32 loc = TYPE_CLOTHWEIGHT; - void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]); - glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr); + if (!(data_mask & MAP_COLOR)) + { //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps + loc = TYPE_COLOR; + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); } - if (data_mask & MAP_TEXTURE_INDEX && - (gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30)) //indexed texture rendering requires GLSL 1.30 or later - { + } + if (data_mask & MAP_WEIGHT) + { + S32 loc = TYPE_WEIGHT; + void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]); + glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr); + } + if (data_mask & MAP_WEIGHT4) + { + S32 loc = TYPE_WEIGHT4; + void* ptr = (void*)(base+mOffsets[TYPE_WEIGHT4]); + glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); + } + if (data_mask & MAP_CLOTHWEIGHT) + { + S32 loc = TYPE_CLOTHWEIGHT; + void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]); + glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr); + } + if (data_mask & MAP_TEXTURE_INDEX && + (gGLManager.mGLSLVersionMajor >= 2 || gGLManager.mGLSLVersionMinor >= 30)) //indexed texture rendering requires GLSL 1.30 or later + { #if !LL_DARWIN - S32 loc = TYPE_TEXTURE_INDEX; - void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12); - glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); + S32 loc = TYPE_TEXTURE_INDEX; + void *ptr = (void*) (base + mOffsets[TYPE_VERTEX] + 12); + glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); #endif - } - if (data_mask & MAP_VERTEX) - { - S32 loc = TYPE_VERTEX; - void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]); - glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); - } - } - else - { - if (data_mask & MAP_NORMAL) - { - glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); - } - if (data_mask & MAP_TEXCOORD3) - { - glClientActiveTextureARB(GL_TEXTURE3_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD2) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD1) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TANGENT) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD0) - { - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); - } - if (data_mask & MAP_COLOR) - { - glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); - } - if (data_mask & MAP_VERTEX) - { - glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0)); - } } + if (data_mask & MAP_VERTEX) + { + S32 loc = TYPE_VERTEX; + void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]); + glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); + } llglassertok(); } +void LLVertexBuffer::setupVertexBufferFast(U32 data_mask) +{ + U8* base = (U8*)mAlignedOffset; + + if (data_mask & MAP_NORMAL) + { + S32 loc = TYPE_NORMAL; + void* ptr = (void*)(base + mOffsets[TYPE_NORMAL]); + glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_NORMAL], ptr); + } + if (data_mask & MAP_TEXCOORD3) + { + S32 loc = TYPE_TEXCOORD3; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD3]); + glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD3], ptr); + } + if (data_mask & MAP_TEXCOORD2) + { + S32 loc = TYPE_TEXCOORD2; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD2]); + glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD2], ptr); + } + if (data_mask & MAP_TEXCOORD1) + { + S32 loc = TYPE_TEXCOORD1; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]); + glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr); + } + if (data_mask & MAP_TANGENT) + { + S32 loc = TYPE_TANGENT; + void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]); + glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr); + } + if (data_mask & MAP_TEXCOORD0) + { + S32 loc = TYPE_TEXCOORD0; + void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD0]); + glVertexAttribPointerARB(loc, 2, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], ptr); + } + if (data_mask & MAP_COLOR) + { + S32 loc = TYPE_COLOR; + //bind emissive instead of color pointer if emissive is present + void* ptr = (data_mask & MAP_EMISSIVE) ? (void*)(base + mOffsets[TYPE_EMISSIVE]) : (void*)(base + mOffsets[TYPE_COLOR]); + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_COLOR], ptr); + } + if (data_mask & MAP_EMISSIVE) + { + S32 loc = TYPE_EMISSIVE; + void* ptr = (void*)(base + mOffsets[TYPE_EMISSIVE]); + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); + + if (!(data_mask & MAP_COLOR)) + { //map emissive to color channel when color is not also being bound to avoid unnecessary shader swaps + loc = TYPE_COLOR; + glVertexAttribPointerARB(loc, 4, GL_UNSIGNED_BYTE, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_EMISSIVE], ptr); + } + } + if (data_mask & MAP_WEIGHT) + { + S32 loc = TYPE_WEIGHT; + void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT]); + glVertexAttribPointerARB(loc, 1, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT], ptr); + } + if (data_mask & MAP_WEIGHT4) + { + S32 loc = TYPE_WEIGHT4; + void* ptr = (void*)(base + mOffsets[TYPE_WEIGHT4]); + glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_WEIGHT4], ptr); + } + if (data_mask & MAP_CLOTHWEIGHT) + { + S32 loc = TYPE_CLOTHWEIGHT; + void* ptr = (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]); + glVertexAttribPointerARB(loc, 4, GL_FLOAT, GL_TRUE, LLVertexBuffer::sTypeSize[TYPE_CLOTHWEIGHT], ptr); + } + if (data_mask & MAP_TEXTURE_INDEX) + { +#if !LL_DARWIN + S32 loc = TYPE_TEXTURE_INDEX; + void* ptr = (void*)(base + mOffsets[TYPE_VERTEX] + 12); + glVertexAttribIPointer(loc, 1, GL_UNSIGNED_INT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); +#endif + } + if (data_mask & MAP_VERTEX) + { + S32 loc = TYPE_VERTEX; + void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]); + glVertexAttribPointerARB(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr); + } +} + LLVertexBuffer::MappedRegion::MappedRegion(S32 type, S32 index, S32 count) : mType(type), mIndex(index), mCount(count) { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index dbe1a3687f..baf8407fc6 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -64,10 +64,10 @@ public: const U32 mType; //size MUST be a power of 2 - volatile U8* allocate(U32& name, U32 size, bool for_seed = false); + U8* allocate(U32& name, U32 size, bool for_seed = false); //size MUST be the size provided to allocate that returned the given name - void release(U32 name, volatile U8* buffer, U32 size); + void release(U32 name, U8* buffer, U32 size); //batch allocate buffers to be provided to the application on demand void seedPool(); @@ -82,20 +82,23 @@ public: { public: U32 mGLName; - volatile U8* mClientData; + U8* mClientData; }; typedef std::list<Record> record_list_t; std::vector<record_list_t> mFreeList; std::vector<U32> mMissCount; + //used to avoid calling glGenBuffers for every VBO creation + static U32 sNamePool[1024]; + static U32 sNameIdx; }; //============================================================================ // base class class LLPrivateMemoryPool; -class LLVertexBuffer : public LLRefCount, public LLTrace::MemTrackable<LLVertexBuffer> +class LLVertexBuffer : public LLRefCount { public: class MappedRegion @@ -110,8 +113,7 @@ public: }; LLVertexBuffer(const LLVertexBuffer& rhs) - : LLTrace::MemTrackable<LLVertexBuffer>("LLVertexBuffer"), - mUsage(rhs.mUsage) + : mUsage(rhs.mUsage) { *this = rhs; } @@ -127,7 +129,7 @@ public: static LLVBOPool sDynamicCopyVBOPool; static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; - + static std::list<U32> sAvailableVAOName; static U32 sCurVAOName; @@ -143,8 +145,7 @@ public: static void initClass(bool use_vbo, bool no_vbo_mapping); static void cleanupClass(); static void setupClientArrays(U32 data_mask); - static void pushPositions(U32 mode, const LLVector4a* pos, U32 count); - static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm); + static void drawArrays(U32 mode, const std::vector<LLVector3>& pos); static void drawElements(U32 mode, const LLVector4a* pos, const LLVector2* tc, S32 num_indices, const U16* indicesp); static void unbind(); //unbind any bound vertex buffer @@ -207,13 +208,17 @@ protected: virtual ~LLVertexBuffer(); // use unref() - virtual void setupVertexBuffer(U32 data_mask); // pure virtual, called from mapBuffer() + virtual void setupVertexBuffer(U32 data_mask); + void setupVertexBufferFast(U32 data_mask); + void setupVertexArray(); void genBuffer(U32 size); void genIndices(U32 size); bool bindGLBuffer(bool force_bind = false); + bool bindGLBufferFast(); bool bindGLIndices(bool force_bind = false); + bool bindGLIndicesFast(); bool bindGLArray(); void releaseBuffer(); void releaseIndices(); @@ -229,13 +234,15 @@ public: LLVertexBuffer(U32 typemask, S32 usage); // map for data access - volatile U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); - volatile U8* mapIndexBuffer(S32 index, S32 count, bool map_range); + U8* mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range); + U8* mapIndexBuffer(S32 index, S32 count, bool map_range); void bindForFeedback(U32 channel, U32 type, U32 index, U32 count); // set for rendering virtual void setBuffer(U32 data_mask); // calls setupVertexBuffer() if data_mask is not 0 + void setBufferFast(U32 data_mask); // calls setupVertexBufferFast(), assumes data_mask is not 0 among other assumptions + void flush(); //flush pending data to GL memory // allocate buffer bool allocateBuffer(S32 nverts, S32 nindices, bool create); @@ -271,14 +278,14 @@ public: S32 getNumVerts() const { return mNumVerts; } S32 getNumIndices() const { return mNumIndices; } - volatile U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } - volatile U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } + U8* getIndicesPointer() const { return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; } + U8* getVerticesPointer() const { return useVBOs() ? (U8*) mAlignedOffset : mMappedData; } U32 getTypeMask() const { return mTypeMask; } bool hasDataType(S32 type) const { return ((1 << type) & getTypeMask()); } S32 getSize() const; S32 getIndicesSize() const { return mIndicesSize; } - volatile U8* getMappedData() const { return mMappedData; } - volatile U8* getMappedIndices() const { return mMappedIndexData; } + U8* getMappedData() const { return mMappedData; } + U8* getMappedIndices() const { return mMappedIndexData; } S32 getOffset(S32 type) const { return mOffsets[type]; } S32 getUsage() const { return mUsage; } bool isWriteable() const { return (mMappable || mUsage == GL_STREAM_DRAW_ARB) ? true : false; } @@ -287,6 +294,9 @@ public: void drawArrays(U32 mode, U32 offset, U32 count) const; void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const; + //implementation for inner loops that does no safety checking + void drawRangeFast(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const; + //for debugging, validate data in given range is valid void validateRange(U32 start, U32 end, U32 count, U32 offset) const; @@ -308,8 +318,8 @@ protected: U32 mGLIndices; // GL IBO handle U32 mGLArray; // GL VAO handle - volatile U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) - volatile U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) + U8* mMappedData; // pointer to currently mapped data (NULL if unmapped) + U8* mMappedIndexData; // pointer to currently mapped indices (NULL if unmapped) U32 mMappedDataUsingVBOs : 1; U32 mMappedIndexDataUsingVBOs : 1; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index d96824bbf8..e0579352d3 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -308,6 +308,10 @@ if(LL_TESTS) ${BOOST_FIBER_LIBRARY} ${BOOST_CONTEXT_LIBRARY} ${BOOST_SYSTEM_LIBRARY} ${WINDOWS_LIBRARIES}) if(NOT LINUX) - LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}") + if(WINDOWS) + LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "imm32;${test_libs}") + else(WINDOWS) + LL_ADD_INTEGRATION_TEST(llurlentry llurlentry.cpp "${test_libs}") + endif(WINDOWS) endif(NOT LINUX) endif(LL_TESTS) diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index bcc653a602..9ca05a16f3 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -113,6 +113,10 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p) } mArrowImage = button_params.image_unselected; + if (mArrowImage.notNull()) + { + mImageLoadedConnection = mArrowImage->addLoadedCallback(boost::bind(&LLComboBox::imageLoaded, this)); + } mButton = LLUICtrlFactory::create<LLButton>(button_params); @@ -183,6 +187,7 @@ LLComboBox::~LLComboBox() // explicitly disconect this signal, since base class destructor might fire top lost mTopLostSignalConnection.disconnect(); + mImageLoadedConnection.disconnect(); } @@ -1074,6 +1079,30 @@ void LLComboBox::onSetHighlight() const } } +void LLComboBox::imageLoaded() +{ + static LLUICachedControl<S32> drop_shadow_button("DropShadowButton", 0); + + if (mAllowTextEntry) + { + LLRect rect = getLocalRect(); + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + S32 shadow_size = drop_shadow_button; + mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size, + rect.mTop, rect.mRight, rect.mBottom)); + if (mButton->getVisible()) + { + // recalculate field size + if (mTextEntry) + { + LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button; + mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); + } + } + } +} + //============================================================================ // LLCtrlListInterface functions diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index e17d6cdfb4..cac8850a25 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -105,6 +105,8 @@ protected: virtual std::string _getSearchText() const; virtual void onSetHighlight() const; + void imageLoaded(); + public: // LLView interface virtual void onFocusLost(); @@ -244,6 +246,7 @@ private: commit_callback_t mTextChangedCallback; commit_callback_t mSelectionCallback; boost::signals2::connection mTopLostSignalConnection; + boost::signals2::connection mImageLoadedConnection; commit_signal_t mOnReturnSignal; S32 mLastSelectedIndex; }; diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 0e42922543..03efd09689 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -3268,11 +3268,9 @@ boost::signals2::connection LLFloater::setCloseCallback( const commit_signal_t:: return mCloseSignal.connect(cb); } -LLTrace::BlockTimerStatHandle POST_BUILD("Floater Post Build"); -static LLTrace::BlockTimerStatHandle FTM_EXTERNAL_FLOATER_LOAD("Load Extern Floater Reference"); - bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::string& filename, LLXMLNodePtr output_node) { + LL_PROFILE_ZONE_SCOPED; Params default_params(LLUICtrlFactory::getDefaultParams<LLFloater>()); Params params(default_params); @@ -3299,7 +3297,6 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str LLUICtrlFactory::instance().pushFileName(xml_filename); - LL_RECORD_BLOCK_TIME(FTM_EXTERNAL_FLOATER_LOAD); if (!LLUICtrlFactory::getLayeredXMLNode(xml_filename, referenced_xml)) { LL_WARNS() << "Couldn't parse panel from: " << xml_filename << LL_ENDL; @@ -3375,12 +3372,8 @@ bool LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, const std::str } BOOL result; - { - LL_RECORD_BLOCK_TIME(POST_BUILD); - - result = postBuild(); - } - + result = postBuild(); + if (!result) { LL_ERRS() << "Failed to construct floater " << getName() << LL_ENDL; @@ -3424,11 +3417,9 @@ bool LLFloater::isVisible(const LLFloater* floater) return floater && floater->getVisible(); } -static LLTrace::BlockTimerStatHandle FTM_BUILD_FLOATERS("Build Floaters"); - bool LLFloater::buildFromFile(const std::string& filename) { - LL_RECORD_BLOCK_TIME(FTM_BUILD_FLOATERS); + LL_PROFILE_ZONE_SCOPED; LLXMLNodePtr root; if (!LLUICtrlFactory::getLayeredXMLNode(filename, root)) diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 2672d600c6..306760b7fb 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -346,6 +346,8 @@ public: // handle refocusing. static void closeFrontmostFloater(); + static bool isQuitRequested() { return sQuitting; } + // LLNotification::Params contextualNotification(const std::string& name) // { // return LLNotification::Params(name).context(mNotificationContext); diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 54fdee6901..ea2ca68e47 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -189,7 +189,6 @@ LLFolderView::LLFolderView(const Params& p) mViewModel(p.view_model), mGroupedItemModel(p.grouped_item_model) { - claimMem(mViewModel); LLPanel* panel = p.parent_panel; mParentPanel = panel->getHandle(); mViewModel->setFolderView(this); @@ -339,11 +338,9 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height ) return ll_round(mTargetHeight); } -static LLTrace::BlockTimerStatHandle FTM_FILTER("Filter Folder View"); - void LLFolderView::filter( LLFolderViewFilter& filter ) { - LL_RECORD_BLOCK_TIME(FTM_FILTER); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; static LLCachedControl<S32> time_visible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameVisible", 10); static LLCachedControl<S32> time_invisible(*LLUI::getInstance()->mSettingGroups["config"], "FilterItemsMaxTimePerFrameUnvisible", 1); filter.resetTime(llclamp((mParentPanel.get()->getVisible() ? time_visible() : time_invisible()), 1, 100)); @@ -505,10 +502,9 @@ BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) return rv; } -static LLTrace::BlockTimerStatHandle FTM_SANITIZE_SELECTION("Sanitize Selection"); void LLFolderView::sanitizeSelection() { - LL_RECORD_BLOCK_TIME(FTM_SANITIZE_SELECTION); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // store off current item in case it is automatically deselected // and we want to preserve context LLFolderViewItem* original_selected_item = getCurSelectedItem(); @@ -1623,7 +1619,6 @@ void LLFolderView::setShowSingleSelection(bool show) } } -static LLTrace::BlockTimerStatHandle FTM_AUTO_SELECT("Open and Select"); static LLTrace::BlockTimerStatHandle FTM_INVENTORY("Inventory"); // Main idle routine @@ -1631,7 +1626,7 @@ void LLFolderView::update() { // If this is associated with the user's inventory, don't do anything // until that inventory is loaded up. - LL_RECORD_BLOCK_TIME(FTM_INVENTORY); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_INVENTORY); // If there's no model, the view is in suspended state (being deleted) and shouldn't be updated if (getFolderViewModel() == NULL) @@ -1659,7 +1654,6 @@ void LLFolderView::update() // automatically show matching items, and select first one if we had a selection if (mNeedsAutoSelect) { - LL_RECORD_BLOCK_TIME(FTM_AUTO_SELECT); // select new item only if a filtered item not currently selected and there was a selection LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back(); if (!mAutoSelectOverride && selected_itemp && !selected_itemp->getViewModelItem()->potentiallyVisible()) diff --git a/indra/llui/llfolderviewmodel.h b/indra/llui/llfolderviewmodel.h index e62b2779dd..093e213be3 100644 --- a/indra/llui/llfolderviewmodel.h +++ b/indra/llui/llfolderviewmodel.h @@ -108,11 +108,10 @@ public: virtual S32 getFirstRequiredGeneration() const = 0; }; -class LLFolderViewModelInterface : public LLTrace::MemTrackable<LLFolderViewModelInterface> +class LLFolderViewModelInterface { public: LLFolderViewModelInterface() - : LLTrace::MemTrackable<LLFolderViewModelInterface>("LLFolderViewModelInterface") {} virtual ~LLFolderViewModelInterface() {} @@ -133,11 +132,10 @@ public: // This is an abstract base class that users of the folderview classes // would use to bridge the folder view with the underlying data -class LLFolderViewModelItem : public LLRefCount, public LLTrace::MemTrackable<LLFolderViewModelItem> +class LLFolderViewModelItem : public LLRefCount { public: LLFolderViewModelItem() - : LLTrace::MemTrackable<LLFolderViewModelItem>("LLFolderViewModelItem") {} virtual ~LLFolderViewModelItem() { } diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp index 29a156e933..aac28e04b9 100644 --- a/indra/llui/lllayoutstack.cpp +++ b/indra/llui/lllayoutstack.cpp @@ -340,8 +340,6 @@ void LLLayoutStack::collapsePanel(LLPanel* panel, BOOL collapsed) mNeedsLayout = true; } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_LAYOUT("Update LayoutStacks"); - class LLImagePanel : public LLPanel { public: @@ -369,7 +367,7 @@ private: void LLLayoutStack::updateLayout() { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_LAYOUT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (!mNeedsLayout) return; diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index a1f0e78bf3..7c381161c9 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -1387,7 +1387,7 @@ bool LLNotifications::failedUniquenessTest(const LLSD& payload) LLNotificationChannelPtr LLNotifications::getChannel(const std::string& channelName) { - return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName)); + return LLNotificationChannelPtr(LLNotificationChannel::getInstance(channelName).get()); } diff --git a/indra/llui/llpanel.cpp b/indra/llui/llpanel.cpp index 00da0f5fec..f770920c4a 100644 --- a/indra/llui/llpanel.cpp +++ b/indra/llui/llpanel.cpp @@ -800,14 +800,12 @@ boost::signals2::connection LLPanel::setVisibleCallback( const commit_signal_t:: return mVisibleSignal->connect(cb); } -static LLTrace::BlockTimerStatHandle FTM_BUILD_PANELS("Build Panels"); - //----------------------------------------------------------------------------- // buildPanel() //----------------------------------------------------------------------------- BOOL LLPanel::buildFromFile(const std::string& filename, const LLPanel::Params& default_params) { - LL_RECORD_BLOCK_TIME(FTM_BUILD_PANELS); + LL_PROFILE_ZONE_SCOPED; BOOL didPost = FALSE; LLXMLNodePtr root; diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp index cd87c44dc2..11b0eb9f80 100644 --- a/indra/llui/llscrolllistctrl.cpp +++ b/indra/llui/llscrolllistctrl.cpp @@ -3056,10 +3056,9 @@ LLScrollListColumn* LLScrollListCtrl::getColumn(const std::string& name) return NULL; } -LLTrace::BlockTimerStatHandle FTM_ADD_SCROLLLIST_ELEMENT("Add Scroll List Item"); LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata) { - LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; LLScrollListItem::Params item_params; LLParamSDParser parser; parser.readSD(element, item_params); @@ -3069,14 +3068,14 @@ LLScrollListItem* LLScrollListCtrl::addElement(const LLSD& element, EAddPosition LLScrollListItem* LLScrollListCtrl::addRow(const LLScrollListItem::Params& item_p, EAddPosition pos) { - LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; LLScrollListItem *new_item = new LLScrollListItem(item_p); return addRow(new_item, item_p, pos); } LLScrollListItem* LLScrollListCtrl::addRow(LLScrollListItem *new_item, const LLScrollListItem::Params& item_p, EAddPosition pos) { - LL_RECORD_BLOCK_TIME(FTM_ADD_SCROLLLIST_ELEMENT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (!item_p.validateBlock() || !new_item) return NULL; new_item->setNumColumns(mColumns.size()); diff --git a/indra/llui/llstatbar.cpp b/indra/llui/llstatbar.cpp index 6c8e63442b..2449100952 100644 --- a/indra/llui/llstatbar.cpp +++ b/indra/llui/llstatbar.cpp @@ -160,6 +160,7 @@ LLStatBar::Params::Params() tick_spacing("tick_spacing", 0.f), decimal_digits("decimal_digits", 3), show_bar("show_bar", false), + show_median("show_median", false), show_history("show_history", false), scale_range("scale_range", true), num_frames("num_frames", 200), @@ -186,6 +187,7 @@ LLStatBar::LLStatBar(const Params& p) mNumShortHistoryFrames(p.num_frames_short), mMaxHeight(p.max_height), mDisplayBar(p.show_bar), + mShowMedian(p.show_median), mDisplayHistory(p.show_history), mOrientation(p.orientation), mAutoScaleMax(!p.bar_max.isProvided()), @@ -318,7 +320,14 @@ void LLStatBar::draw() min = frame_recording.getPeriodMinPerSec(count_stat, num_frames); max = frame_recording.getPeriodMaxPerSec(count_stat, num_frames); mean = frame_recording.getPeriodMeanPerSec(count_stat, num_frames); - display_value = mean; + if (mShowMedian) + { + display_value = frame_recording.getPeriodMedianPerSec(count_stat, num_frames); + } + else + { + display_value = mean; + } } break; case STAT_EVENT: @@ -344,7 +353,11 @@ void LLStatBar::draw() mean = frame_recording.getPeriodMean(sample_stat, num_frames); num_rapid_changes = calc_num_rapid_changes(frame_recording, sample_stat, RAPID_CHANGE_WINDOW); - if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC) + if (mShowMedian) + { + display_value = frame_recording.getPeriodMedian(sample_stat, num_frames); + } + else if (num_rapid_changes / RAPID_CHANGE_WINDOW.value() > MAX_RAPID_CHANGES_PER_SEC) { display_value = mean; } @@ -554,29 +567,25 @@ void LLStatBar::draw() void LLStatBar::setStat(const std::string& stat_name) { using namespace LLTrace; - const StatType<CountAccumulator>* count_stat; - const StatType<EventAccumulator>* event_stat; - const StatType<SampleAccumulator>* sample_stat; - const StatType<MemAccumulator>* mem_stat; - if ((count_stat = StatType<CountAccumulator>::getInstance(stat_name))) + if (auto count_stat = StatType<CountAccumulator>::getInstance(stat_name)) { - mStat.countStatp = count_stat; + mStat.countStatp = count_stat.get(); mStatType = STAT_COUNT; } - else if ((event_stat = StatType<EventAccumulator>::getInstance(stat_name))) + else if (auto event_stat = StatType<EventAccumulator>::getInstance(stat_name)) { - mStat.eventStatp = event_stat; + mStat.eventStatp = event_stat.get(); mStatType = STAT_EVENT; } - else if ((sample_stat = StatType<SampleAccumulator>::getInstance(stat_name))) + else if (auto sample_stat = StatType<SampleAccumulator>::getInstance(stat_name)) { - mStat.sampleStatp = sample_stat; + mStat.sampleStatp = sample_stat.get(); mStatType = STAT_SAMPLE; } - else if ((mem_stat = StatType<MemAccumulator>::getInstance(stat_name))) + else if (auto mem_stat = StatType<MemAccumulator>::getInstance(stat_name)) { - mStat.memStatp = mem_stat; + mStat.memStatp = mem_stat.get(); mStatType = STAT_MEM; } } diff --git a/indra/llui/llstatbar.h b/indra/llui/llstatbar.h index 1ff4c67fc5..6b481ca68f 100644 --- a/indra/llui/llstatbar.h +++ b/indra/llui/llstatbar.h @@ -44,9 +44,10 @@ public: bar_max, tick_spacing; - Optional<bool> show_bar, + Optional<bool> show_bar, show_history, - scale_range; + scale_range, + show_median; // default is mean Optional<S32> decimal_digits, num_frames, @@ -112,6 +113,7 @@ private: bool mDisplayBar, // Display the bar graph. mDisplayHistory, + mShowMedian, mAutoScaleMax, mAutoScaleMin; }; diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp index 0532750dce..0dc99fdde6 100644 --- a/indra/llui/lltextbase.cpp +++ b/indra/llui/lltextbase.cpp @@ -1490,11 +1490,9 @@ S32 LLTextBase::getLeftOffset(S32 width) } } - -static LLTrace::BlockTimerStatHandle FTM_TEXT_REFLOW ("Text Reflow"); void LLTextBase::reflow() { - LL_RECORD_BLOCK_TIME(FTM_TEXT_REFLOW); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; updateSegments(); @@ -1842,10 +1840,9 @@ void LLTextBase::removeDocumentChild(LLView* view) } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_TEXT_SEGMENTS("Update Text Segments"); void LLTextBase::updateSegments() { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_TEXT_SEGMENTS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; createDefaultSegment(); } @@ -2105,19 +2102,16 @@ static LLUIImagePtr image_from_icon_name(const std::string& icon_name) } } -static LLTrace::BlockTimerStatHandle FTM_PARSE_HTML("Parse HTML"); - - void LLTextBase::appendTextImpl(const std::string &new_text, const LLStyle::Params& input_params) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; LLStyle::Params style_params(input_params); style_params.fillFrom(getStyleParams()); S32 part = (S32)LLTextParser::WHOLE; if (mParseHTML && !style_params.is_link) // Don't search for URLs inside a link segment (STORM-358). { - LL_RECORD_BLOCK_TIME(FTM_PARSE_HTML); S32 start=0,end=0; LLUrlMatch match; std::string text = new_text; @@ -2211,11 +2205,9 @@ void LLTextBase::setLastSegmentToolTip(const std::string &tooltip) } } -static LLTrace::BlockTimerStatHandle FTM_APPEND_TEXT("Append Text"); - void LLTextBase::appendText(const std::string &new_text, bool prepend_newline, const LLStyle::Params& input_params) { - LL_RECORD_BLOCK_TIME(FTM_APPEND_TEXT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (new_text.empty()) return; diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp index a1a8feedaa..a1ef34159d 100644 --- a/indra/llui/lltrans.cpp +++ b/indra/llui/lltrans.cpp @@ -147,7 +147,7 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLStringUtil:: { // Don't care about time as much as call count. Make sure we're not // calling LLTrans::getString() in an inner loop. JC - LL_RECORD_BLOCK_TIME(FTM_GET_TRANS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (def_string) { @@ -196,7 +196,7 @@ std::string LLTrans::getString(const std::string &xml_desc, const LLSD& msg_args { // Don't care about time as much as call count. Make sure we're not // calling LLTrans::getString() in an inner loop. JC - LL_RECORD_BLOCK_TIME(FTM_GET_TRANS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (def_string) { @@ -237,7 +237,7 @@ std::string LLTrans::getDefString(const std::string &xml_desc, const LLSD& msg_a //static bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLStringUtil::format_map_t& msg_args) { - LL_RECORD_BLOCK_TIME(FTM_GET_TRANS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; template_map_t::iterator iter = sStringTemplates.find(xml_desc); if (iter != sStringTemplates.end()) @@ -259,7 +259,7 @@ bool LLTrans::findString(std::string &result, const std::string &xml_desc, const //static bool LLTrans::findString(std::string &result, const std::string &xml_desc, const LLSD& msg_args) { - LL_RECORD_BLOCK_TIME(FTM_GET_TRANS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; template_map_t::iterator iter = sStringTemplates.find(xml_desc); if (iter != sStringTemplates.end()) diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 5924542a19..2196ba201b 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -121,7 +121,6 @@ LLUICtrl::LLUICtrl(const LLUICtrl::Params& p, const LLViewModelPtr& viewmodel) mDoubleClickSignal(NULL), mTransparencyType(TT_DEFAULT) { - claimMem(viewmodel.get()); } void LLUICtrl::initFromParams(const Params& p) @@ -476,6 +475,7 @@ LLViewModel* LLUICtrl::getViewModel() const //virtual BOOL LLUICtrl::postBuild() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // // Find all of the children that want to be in front and move them to the front // @@ -781,12 +781,9 @@ BOOL LLUICtrl::getIsChrome() const } - -LLTrace::BlockTimerStatHandle FTM_FOCUS_FIRST_ITEM("Focus First Item"); - BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash) { - LL_RECORD_BLOCK_TIME(FTM_FOCUS_FIRST_ITEM); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // try to select default tab group child LLViewQuery query = getTabOrderQuery(); child_list_t result = query(this); @@ -1005,7 +1002,6 @@ boost::signals2::connection LLUICtrl::setCommitCallback( boost::function<void (L boost::signals2::connection LLUICtrl::setValidateBeforeCommit( boost::function<bool (const LLSD& data)> cb ) { if (!mValidateSignal) mValidateSignal = new enable_signal_t(); - claimMem(mValidateSignal); return mValidateSignal->connect(boost::bind(cb, _2)); } @@ -1070,7 +1066,6 @@ boost::signals2::connection LLUICtrl::setValidateCallback(const EnableCallbackPa boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t::slot_type& cb ) { if (!mCommitSignal) mCommitSignal = new commit_signal_t(); - claimMem(mCommitSignal); return mCommitSignal->connect(cb); } @@ -1078,7 +1073,6 @@ boost::signals2::connection LLUICtrl::setCommitCallback( const commit_signal_t:: boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t::slot_type& cb ) { if (!mValidateSignal) mValidateSignal = new enable_signal_t(); - claimMem(mValidateSignal); return mValidateSignal->connect(cb); } @@ -1086,7 +1080,6 @@ boost::signals2::connection LLUICtrl::setValidateCallback( const enable_signal_t boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal_t::slot_type& cb ) { if (!mMouseEnterSignal) mMouseEnterSignal = new commit_signal_t(); - claimMem(mMouseEnterSignal); return mMouseEnterSignal->connect(cb); } @@ -1094,7 +1087,6 @@ boost::signals2::connection LLUICtrl::setMouseEnterCallback( const commit_signal boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal_t::slot_type& cb ) { if (!mMouseLeaveSignal) mMouseLeaveSignal = new commit_signal_t(); - claimMem(mMouseLeaveSignal); return mMouseLeaveSignal->connect(cb); } @@ -1102,7 +1094,6 @@ boost::signals2::connection LLUICtrl::setMouseLeaveCallback( const commit_signal boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t::slot_type& cb ) { if (!mMouseDownSignal) mMouseDownSignal = new mouse_signal_t(); - claimMem(mMouseDownSignal); return mMouseDownSignal->connect(cb); } @@ -1110,7 +1101,6 @@ boost::signals2::connection LLUICtrl::setMouseDownCallback( const mouse_signal_t boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t::slot_type& cb ) { if (!mMouseUpSignal) mMouseUpSignal = new mouse_signal_t(); - claimMem(mMouseUpSignal); return mMouseUpSignal->connect(cb); } @@ -1118,7 +1108,6 @@ boost::signals2::connection LLUICtrl::setMouseUpCallback( const mouse_signal_t:: boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_signal_t::slot_type& cb ) { if (!mRightMouseDownSignal) mRightMouseDownSignal = new mouse_signal_t(); - claimMem(mRightMouseDownSignal); return mRightMouseDownSignal->connect(cb); } @@ -1126,7 +1115,6 @@ boost::signals2::connection LLUICtrl::setRightMouseDownCallback( const mouse_sig boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signal_t::slot_type& cb ) { if (!mRightMouseUpSignal) mRightMouseUpSignal = new mouse_signal_t(); - claimMem(mRightMouseUpSignal); return mRightMouseUpSignal->connect(cb); } @@ -1134,7 +1122,6 @@ boost::signals2::connection LLUICtrl::setRightMouseUpCallback( const mouse_signa boost::signals2::connection LLUICtrl::setDoubleClickCallback( const mouse_signal_t::slot_type& cb ) { if (!mDoubleClickSignal) mDoubleClickSignal = new mouse_signal_t(); - claimMem(mDoubleClickSignal); return mDoubleClickSignal->connect(cb); } diff --git a/indra/llui/lluictrlfactory.cpp b/indra/llui/lluictrlfactory.cpp index fdefae01b1..a85db17c7f 100644 --- a/indra/llui/lluictrlfactory.cpp +++ b/indra/llui/lluictrlfactory.cpp @@ -44,10 +44,6 @@ // this library includes #include "llpanel.h" -LLTrace::BlockTimerStatHandle FTM_WIDGET_CONSTRUCTION("Widget Construction"); -LLTrace::BlockTimerStatHandle FTM_INIT_FROM_PARAMS("Widget InitFromParams"); -LLTrace::BlockTimerStatHandle FTM_WIDGET_SETUP("Widget Setup"); - //----------------------------------------------------------------------------- // UI Ctrl class for padding @@ -117,12 +113,10 @@ void LLUICtrlFactory::loadWidgetTemplate(const std::string& widget_tag, LLInitPa } } -static LLTrace::BlockTimerStatHandle FTM_CREATE_CHILDREN("Create XUI Children"); - //static void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const widget_registry_t& registry, LLXMLNodePtr output_node) { - LL_RECORD_BLOCK_TIME(FTM_CREATE_CHILDREN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (node.isNull()) return; for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) @@ -159,14 +153,13 @@ void LLUICtrlFactory::createChildren(LLView* viewp, LLXMLNodePtr node, const wid } -static LLTrace::BlockTimerStatHandle FTM_XML_PARSE("XML Reading/Parsing"); //----------------------------------------------------------------------------- // getLayeredXMLNode() //----------------------------------------------------------------------------- bool LLUICtrlFactory::getLayeredXMLNode(const std::string &xui_filename, LLXMLNodePtr& root, LLDir::ESkinConstraint constraint) { - LL_RECORD_BLOCK_TIME(FTM_XML_PARSE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; std::vector<std::string> paths = gDirUtilp->findSkinnedFilenames(LLDir::XUI, xui_filename, constraint); @@ -191,11 +184,9 @@ S32 LLUICtrlFactory::saveToXML(LLView* viewp, const std::string& filename) //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_CREATE_FROM_XML("Create child widget"); - LLView *LLUICtrlFactory::createFromXML(LLXMLNodePtr node, LLView* parent, const std::string& filename, const widget_registry_t& registry, LLXMLNodePtr output_node) { - LL_RECORD_BLOCK_TIME(FTM_CREATE_FROM_XML); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; std::string ctrl_type = node->getName()->mString; LLStringUtil::toLower(ctrl_type); diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index 135ed57a4f..6e585abfc0 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -79,10 +79,6 @@ class LLWidgetNameRegistry // LLSINGLETON(LLDefaultParamBlockRegistry); //}; -extern LLTrace::BlockTimerStatHandle FTM_WIDGET_SETUP; -extern LLTrace::BlockTimerStatHandle FTM_WIDGET_CONSTRUCTION; -extern LLTrace::BlockTimerStatHandle FTM_INIT_FROM_PARAMS; - // Build time optimization, generate this once in .cpp file #ifndef LLUICTRLFACTORY_CPP extern template class LLUICtrlFactory* LLSingleton<class LLUICtrlFactory>::getInstance(); @@ -213,6 +209,7 @@ private: template<typename T> static T* createWidgetImpl(const typename T::Params& params, LLView* parent = NULL) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; T* widget = NULL; if (!params.validateBlock()) @@ -221,12 +218,9 @@ private: //return NULL; } - { LL_RECORD_BLOCK_TIME(FTM_WIDGET_CONSTRUCTION); - widget = new T(params); - } - { LL_RECORD_BLOCK_TIME(FTM_INIT_FROM_PARAMS); - widget->initFromParams(params); - } + widget = new T(params); + + widget->initFromParams(params); if (parent) { @@ -239,7 +233,7 @@ private: template<typename T> static T* defaultBuilder(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) { - LL_RECORD_BLOCK_TIME(FTM_WIDGET_SETUP); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; typename T::Params params(getDefaultParams<T>()); diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index b942be2a4a..9ba71913d0 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -140,8 +140,7 @@ LLView::Params::Params() } LLView::LLView(const LLView::Params& p) -: LLTrace::MemTrackable<LLView>("LLView"), - mVisible(p.visible), +: mVisible(p.visible), mInDraw(false), mName(p.name), mParentView(NULL), @@ -1597,15 +1596,11 @@ LLView* LLView::getChildView(const std::string& name, BOOL recurse) const return getChild<LLView>(name, recurse); } -static LLTrace::BlockTimerStatHandle FTM_FIND_VIEWS("Find Widgets"); - LLView* LLView::findChildView(const std::string& name, BOOL recurse) const { - LL_RECORD_BLOCK_TIME(FTM_FIND_VIEWS); - //richard: should we allow empty names? - //if(name.empty()) - // return NULL; - // Look for direct children *first* + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + // Look for direct children *first* BOOST_FOREACH(LLView* childp, mChildList) { llassert(childp); diff --git a/indra/llui/llview.h b/indra/llui/llview.h index c60dcf3344..bec45df78a 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -100,8 +100,7 @@ class LLView : public LLMouseHandler, // handles mouse events public LLFocusableElement, // handles keyboard events public LLMortician, // lazy deletion - public LLHandleProvider<LLView>, // passes out weak references to self - public LLTrace::MemTrackable<LLView> // track memory usage + public LLHandleProvider<LLView> // passes out weak references to self { public: diff --git a/indra/llui/llviewereventrecorder.h b/indra/llui/llviewereventrecorder.h index 94e66f5dc4..6170005b2b 100644 --- a/indra/llui/llviewereventrecorder.h +++ b/indra/llui/llviewereventrecorder.h @@ -41,12 +41,12 @@ #include "llsingleton.h" // includes llerror which we need here so we can skip the include here -class LLViewerEventRecorder : public LLSingleton<LLViewerEventRecorder> +class LLViewerEventRecorder : public LLSimpleton<LLViewerEventRecorder> { - LLSINGLETON(LLViewerEventRecorder); - ~LLViewerEventRecorder(); - - public: +public: + LLViewerEventRecorder(); + ~LLViewerEventRecorder(); + void updateMouseEventInfo(S32 local_x,S32 local_y, S32 global_x, S32 global_y, std::string mName); void setMouseLocalCoords(S32 x,S32 y); void setMouseGlobalCoords(S32 x,S32 y); diff --git a/indra/llui/llviewmodel.cpp b/indra/llui/llviewmodel.cpp index 282addf692..a400eb70c0 100644 --- a/indra/llui/llviewmodel.cpp +++ b/indra/llui/llviewmodel.cpp @@ -37,15 +37,13 @@ /// LLViewModel::LLViewModel() -: LLTrace::MemTrackable<LLViewModel>("LLViewModel"), - mDirty(false) +: mDirty(false) { } /// Instantiate an LLViewModel with an existing data value LLViewModel::LLViewModel(const LLSD& value) -: LLTrace::MemTrackable<LLViewModel>("LLViewModel"), - mDirty(false) +: mDirty(false) { setValue(value); } @@ -82,15 +80,9 @@ LLTextViewModel::LLTextViewModel(const LLSD& value) void LLTextViewModel::setValue(const LLSD& value) { // approximate LLSD storage usage - disclaimMem(mDisplay.size()); LLViewModel::setValue(value); - disclaimMem(mDisplay); mDisplay = utf8str_to_wstring(value.asString()); - claimMem(mDisplay); - // approximate LLSD storage usage - claimMem(mDisplay.size()); - // mDisplay and mValue agree mUpdateFromDisplay = false; } @@ -101,12 +93,8 @@ void LLTextViewModel::setDisplay(const LLWString& value) // and do the utf8str_to_wstring() to get the corresponding mDisplay // value. But a text editor might want to edit the display string // directly, then convert back to UTF8 on commit. - disclaimMem(mDisplay.size()); - disclaimMem(mDisplay); - mDisplay = value; - claimMem(mDisplay); - claimMem(mDisplay.size()); - mDirty = true; + mDisplay = value; + mDirty = true; // Don't immediately convert to UTF8 -- do it lazily -- we expect many // more setDisplay() calls than getValue() calls. Just flag that it needs // doing. diff --git a/indra/llui/llviewmodel.h b/indra/llui/llviewmodel.h index 49d7c322a3..e7dceb6c31 100644 --- a/indra/llui/llviewmodel.h +++ b/indra/llui/llviewmodel.h @@ -62,8 +62,7 @@ typedef LLPointer<LLListViewModel> LLListViewModelPtr; * last referencing widget is destroyed. */ class LLViewModel -: public LLRefCount, - public LLTrace::MemTrackable<LLViewModel> +: public LLRefCount { public: LLViewModel(); diff --git a/indra/llwindow/GL/glh_extensions.h b/indra/llwindow/GL/glh_extensions.h deleted file mode 100644 index 554cb1731f..0000000000 --- a/indra/llwindow/GL/glh_extensions.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * glh_extensions.h - * $LicenseInfo:firstyear=2006&license=mit$ (mit used here to satisfy validity checker) - * Copyright (C) 2006, NVIDIA - * From nVidia Corporation, downloaded 2006-12-18 from: - * http://developer.nvidia.com/attach/8196 - * ("NVParse Library with Source (.zip) (2390 KB)") - * - * License (quoted from license_info.txt in aforementioned file): - * "The files bison.exe, bison.simple, and flex.exe are covered by - * the GPL. All other files in this distribution can be used however - * you want." - * $/LicenseInfo$ - - */ - -#ifndef GLH_EXTENSIONS -#define GLH_EXTENSIONS - -#include <string.h> -#include <stdio.h> - -#ifdef _WIN32 -# include <windows.h> -#endif - -#ifndef __APPLE__ -#include <GL/gl.h> -#endif - -#ifdef _WIN32 -# include "GL/wglext.h" -#endif - -#define CHECK_MEMORY(ptr) \ - if (NULL == ptr) { \ - printf("Error allocating memory in file %s, line %d\n", __FILE__, __LINE__); \ - exit(-1); \ - } - -#ifdef GLH_EXT_SINGLE_FILE -# define GLH_EXTENSIONS_SINGLE_FILE // have to do this because glh_genext.h unsets GLH_EXT_SINGLE_FILE -#endif - -#include "glh_genext.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef GLH_EXTENSIONS_SINGLE_FILE - -class GLHExts -{ -public: - GLHExts() - { - mSysExts = NULL; -// mUnsupportedExts = NULL; - } - ~GLHExts() - { - if (mSysExts) - { - free(mSysExts); - } -// if (mUnsupportedExts) -// { -// free(mUnsupportedExts); -// } - } - char *mSysExts; -// char *mUnsupportedExts; -}; - -GLHExts gGLHExts; - -static int ExtensionExists(const char* extName, const char* sysExts) -{ - char *padExtName = (char*)malloc(strlen(extName) + 2); - strcat(strcpy(padExtName, extName), " "); - - if (0 == strcmp(extName, "GL_VERSION_1_2")) { - const char *version = (const char*)glGetString(GL_VERSION); - if (strstr(version, "1.0") == version || strstr(version, "1.1") == version) { - return FALSE; - } else { - return TRUE; - } - } - if (strstr(sysExts, padExtName)) { - free(padExtName); - return TRUE; - } else { - free(padExtName); - return FALSE; - } -} - -static const char* EatWhiteSpace(const char *str) -{ - for (; *str && (' ' == *str || '\t' == *str || '\n' == *str); str++); - return str; -} - -static const char* EatNonWhiteSpace(const char *str) -{ - for (; *str && (' ' != *str && '\t' != *str && '\n' != *str); str++); - return str; -} - - -int glh_init_extensions(const char *origReqExts) -{ - // Length of requested extensions string - //unsigned reqExtsLen; - char *reqExts; - // Ptr for individual extensions within reqExts - char *reqExt; - int success = TRUE; - - // build space-padded extension string - if (NULL == gGLHExts.mSysExts) { - const char *extensions = (const char*)glGetString(GL_EXTENSIONS); - int sysExtsLen = (int)strlen(extensions); - const char *winsys_extensions = 0; - int winsysExtsLen = 0; -#ifdef _WIN32 - { - PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB = 0; - wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC)wglGetProcAddress("wglGetExtensionsStringARB"); - if(wglGetExtensionsStringARB) - { - winsys_extensions = wglGetExtensionsStringARB(wglGetCurrentDC()); - winsysExtsLen = (S32)strlen(winsys_extensions); - } - } -#endif - // Add 2 bytes, one for padding space, one for terminating NULL - gGLHExts.mSysExts = (char*)malloc(sysExtsLen + winsysExtsLen + 3); - CHECK_MEMORY(gGLHExts.mSysExts); - strcpy(gGLHExts.mSysExts, extensions); - gGLHExts.mSysExts[sysExtsLen] = ' '; - gGLHExts.mSysExts[sysExtsLen + 1] = 0; - if (winsysExtsLen) - { - strcat(gGLHExts.mSysExts, winsys_extensions); - } - gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen] = ' '; - gGLHExts.mSysExts[sysExtsLen + 1 + winsysExtsLen + 1] = 0; - } - - if (NULL == origReqExts) - { - return TRUE; - } - reqExts = strdup(origReqExts); - /* - reqExtsLen = (S32)strlen(reqExts); - if (NULL == gGLHExts.mUnsupportedExts) - { - gGLHExts.mUnsupportedExts = (char*)malloc(reqExtsLen + 1); - } - else if (reqExtsLen > strlen(gGLHExts.mUnsupportedExts)) - { - gGLHExts.mUnsupportedExts = (char*)realloc(gGLHExts.mUnsupportedExts, reqExtsLen + 1); - } - CHECK_MEMORY(gGLHExts.mUnsupportedExts); - *gGLHExts.mUnsupportedExts = 0; - */ - - // Parse requested extension list - for (reqExt = reqExts; - (reqExt = (char*)EatWhiteSpace(reqExt)) && *reqExt; - reqExt = (char*)EatNonWhiteSpace(reqExt)) - { - char *extEnd = (char*)EatNonWhiteSpace(reqExt); - char saveChar = *extEnd; - *extEnd = (char)0; - - if (!ExtensionExists(reqExt, gGLHExts.mSysExts) || - !glh_init_extension(reqExt)) { - /* - // add reqExt to end of unsupportedExts - strcat(gGLHExts.mUnsupportedExts, reqExt); - strcat(gGLHExts.mUnsupportedExts, " "); - */ - success = FALSE; - } - *extEnd = saveChar; - } - free(reqExts); - return success; -} - -const char* glh_get_unsupported_extensions() -{ - return ""; -// return (const char*)gGLHExts.mUnsupportedExts; -} - -#else -int glh_init_extensions(const char *origReqExts); -const char* glh_get_unsupported_extensions(); -#endif /* GLH_EXT_SINGLE_FILE */ - -#ifdef __cplusplus -} -#endif - -#endif /* GLH_EXTENSIONS */ diff --git a/indra/llwindow/GL/glh_genext.h b/indra/llwindow/GL/glh_genext.h deleted file mode 100644 index cd5d1604a8..0000000000 --- a/indra/llwindow/GL/glh_genext.h +++ /dev/null @@ -1,1674 +0,0 @@ -/* - * glh_genext.h - * $LicenseInfo:firstyear=2008&license=mit$ (mit used here to satisfy validity checker) - * Copyright (C) 2008, NVIDIA - * From nVidia Corporation, downloaded 2006-12-18 from: - * http://developer.nvidia.com/attach/8196 - * ("NVParse Library with Source (.zip) (2390 KB)") - * - * License (quoted from license_info.txt in aforementioned file): - * "The files bison.exe, bison.simple, and flex.exe are covered by - * the GPL. All other files in this distribution can be used however - * you want." - * $/LicenseInfo$ - */ - -/* File generated by extgen.cpp -- do not modify */ -#ifndef GLH_GENEXT_H -#define GLH_GENEXT_H - -// MBW -- None of this is necessary on Mac OS. -#ifndef __APPLE__ - -#include <GL/gl.h> -#include <GL/glext.h> - -#ifdef _WIN32 /* supports windows, x -- need to generalize */ -# include <GL/wglext.h> -# define GLH_EXT_GET_PROC_ADDRESS(p) wglGetProcAddress(p) -#else if GLX_VERSION_1_3 -# include <GL/glxext.h> -# define GLH_EXT_GET_PROC_ADDRESS(p) glXGetProcAddressARB(p) -#endif - -#ifdef GLH_EXT_SINGLE_FILE - #define GLH_EXTERN - #define GLH_INITIALIZER = 0 -#else - #define GLH_EXTERN extern - #define GLH_INITIALIZER -#endif - -#define GLH__PREPROCESSOR_GYMNASTICS2(a,b) a##b -#define GLH__PREPROCESSOR_GYMNASTICS(a,b) GLH__PREPROCESSOR_GYMNASTICS2(a,b) - -#ifndef GLH_EXT_PREFIX -# define GLH_EXT_NAME(a) a -#else -# define GLH_EXT_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_EXT_PREFIX,a) -#endif - -#ifndef _WIN32 -# ifndef GLH_CORE_1_2_PREFIX -# define GLH_CORE_1_2_PREFIX _ -# endif -#endif - -#ifndef GLH_CORE_1_2_PREFIX -# define GLH_CORE_1_2_NAME(a) a -#else -# define GLH_CORE_1_2_NAME(a) GLH__PREPROCESSOR_GYMNASTICS(GLH_CORE_1_2_PREFIX,a) -#endif - -#ifdef GL_ARB_multitexture - GLH_EXTERN PFNGLMULTITEXCOORD1DARBPROC GLH_EXT_NAME(glMultiTexCoord1dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1DVARBPROC GLH_EXT_NAME(glMultiTexCoord1dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1FARBPROC GLH_EXT_NAME(glMultiTexCoord1fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1FVARBPROC GLH_EXT_NAME(glMultiTexCoord1fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1IARBPROC GLH_EXT_NAME(glMultiTexCoord1iARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1IVARBPROC GLH_EXT_NAME(glMultiTexCoord1ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1SARBPROC GLH_EXT_NAME(glMultiTexCoord1sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD1SVARBPROC GLH_EXT_NAME(glMultiTexCoord1svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2DARBPROC GLH_EXT_NAME(glMultiTexCoord2dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2DVARBPROC GLH_EXT_NAME(glMultiTexCoord2dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2FARBPROC GLH_EXT_NAME(glMultiTexCoord2fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2FVARBPROC GLH_EXT_NAME(glMultiTexCoord2fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2IARBPROC GLH_EXT_NAME(glMultiTexCoord2iARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2IVARBPROC GLH_EXT_NAME(glMultiTexCoord2ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2SARBPROC GLH_EXT_NAME(glMultiTexCoord2sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD2SVARBPROC GLH_EXT_NAME(glMultiTexCoord2svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3DARBPROC GLH_EXT_NAME(glMultiTexCoord3dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3DVARBPROC GLH_EXT_NAME(glMultiTexCoord3dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3FARBPROC GLH_EXT_NAME(glMultiTexCoord3fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3FVARBPROC GLH_EXT_NAME(glMultiTexCoord3fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3IARBPROC GLH_EXT_NAME(glMultiTexCoord3iARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3IVARBPROC GLH_EXT_NAME(glMultiTexCoord3ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3SARBPROC GLH_EXT_NAME(glMultiTexCoord3sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD3SVARBPROC GLH_EXT_NAME(glMultiTexCoord3svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4DARBPROC GLH_EXT_NAME(glMultiTexCoord4dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4DVARBPROC GLH_EXT_NAME(glMultiTexCoord4dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4FARBPROC GLH_EXT_NAME(glMultiTexCoord4fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4FVARBPROC GLH_EXT_NAME(glMultiTexCoord4fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4IARBPROC GLH_EXT_NAME(glMultiTexCoord4iARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4IVARBPROC GLH_EXT_NAME(glMultiTexCoord4ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4SARBPROC GLH_EXT_NAME(glMultiTexCoord4sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTITEXCOORD4SVARBPROC GLH_EXT_NAME(glMultiTexCoord4svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLACTIVETEXTUREARBPROC GLH_EXT_NAME(glActiveTextureARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCLIENTACTIVETEXTUREARBPROC GLH_EXT_NAME(glClientActiveTextureARB) GLH_INITIALIZER; -#endif - -#ifdef GL_ARB_texture_border_clamp -#endif - -#ifdef GL_ARB_texture_compression - GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexImage3DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexImage2DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexImage1DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC GLH_EXT_NAME(glCompressedTexSubImage3DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC GLH_EXT_NAME(glCompressedTexSubImage2DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC GLH_EXT_NAME(glCompressedTexSubImage1DARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMPRESSEDTEXIMAGEARBPROC GLH_EXT_NAME(glGetCompressedTexImageARB) GLH_INITIALIZER; -#endif - -#ifdef GL_ARB_texture_cube_map -#endif - -#ifdef GL_ARB_transpose_matrix - GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glLoadTransposeMatrixfARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLLOADTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glLoadTransposeMatrixdARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXFARBPROC GLH_EXT_NAME(glMultTransposeMatrixfARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLMULTTRANSPOSEMATRIXDARBPROC GLH_EXT_NAME(glMultTransposeMatrixdARB) GLH_INITIALIZER; -#endif - -#ifdef GL_ARB_vertex_program - GLH_EXTERN PFNGLVERTEXATTRIB1SARBPROC GLH_EXT_NAME(glVertexAttrib1sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1FARBPROC GLH_EXT_NAME(glVertexAttrib1fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1DARBPROC GLH_EXT_NAME(glVertexAttrib1dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2SARBPROC GLH_EXT_NAME(glVertexAttrib2sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2FARBPROC GLH_EXT_NAME(glVertexAttrib2fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2DARBPROC GLH_EXT_NAME(glVertexAttrib2dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3SARBPROC GLH_EXT_NAME(glVertexAttrib3sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3FARBPROC GLH_EXT_NAME(glVertexAttrib3fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3DARBPROC GLH_EXT_NAME(glVertexAttrib3dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4SARBPROC GLH_EXT_NAME(glVertexAttrib4sARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4FARBPROC GLH_EXT_NAME(glVertexAttrib4fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4DARBPROC GLH_EXT_NAME(glVertexAttrib4dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NUBARBPROC GLH_EXT_NAME(glVertexAttrib4NubARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1SVARBPROC GLH_EXT_NAME(glVertexAttrib1svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1FVARBPROC GLH_EXT_NAME(glVertexAttrib1fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1DVARBPROC GLH_EXT_NAME(glVertexAttrib1dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2SVARBPROC GLH_EXT_NAME(glVertexAttrib2svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2FVARBPROC GLH_EXT_NAME(glVertexAttrib2fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2DVARBPROC GLH_EXT_NAME(glVertexAttrib2dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3SVARBPROC GLH_EXT_NAME(glVertexAttrib3svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3FVARBPROC GLH_EXT_NAME(glVertexAttrib3fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3DVARBPROC GLH_EXT_NAME(glVertexAttrib3dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4BVARBPROC GLH_EXT_NAME(glVertexAttrib4bvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4SVARBPROC GLH_EXT_NAME(glVertexAttrib4svARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4IVARBPROC GLH_EXT_NAME(glVertexAttrib4ivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4UBVARBPROC GLH_EXT_NAME(glVertexAttrib4ubvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4USVARBPROC GLH_EXT_NAME(glVertexAttrib4usvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4UIVARBPROC GLH_EXT_NAME(glVertexAttrib4uivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4FVARBPROC GLH_EXT_NAME(glVertexAttrib4fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4DVARBPROC GLH_EXT_NAME(glVertexAttrib4dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NBVARBPROC GLH_EXT_NAME(glVertexAttrib4NbvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NSVARBPROC GLH_EXT_NAME(glVertexAttrib4NsvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NIVARBPROC GLH_EXT_NAME(glVertexAttrib4NivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NUBVARBPROC GLH_EXT_NAME(glVertexAttrib4NubvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NUSVARBPROC GLH_EXT_NAME(glVertexAttrib4NusvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4NUIVARBPROC GLH_EXT_NAME(glVertexAttrib4NuivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBPOINTERARBPROC GLH_EXT_NAME(glVertexAttribPointerARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLENABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glEnableVertexAttribArrayARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLDISABLEVERTEXATTRIBARRAYARBPROC GLH_EXT_NAME(glDisableVertexAttribArrayARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMSTRINGARBPROC GLH_EXT_NAME(glProgramStringARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLBINDPROGRAMARBPROC GLH_EXT_NAME(glBindProgramARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLDELETEPROGRAMSARBPROC GLH_EXT_NAME(glDeleteProgramsARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGENPROGRAMSARBPROC GLH_EXT_NAME(glGenProgramsARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DARBPROC GLH_EXT_NAME(glProgramEnvParameter4dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMENVPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramEnvParameter4dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FARBPROC GLH_EXT_NAME(glProgramEnvParameter4fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMENVPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramEnvParameter4fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DARBPROC GLH_EXT_NAME(glProgramLocalParameter4dARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4DVARBPROC GLH_EXT_NAME(glProgramLocalParameter4dvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FARBPROC GLH_EXT_NAME(glProgramLocalParameter4fARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMLOCALPARAMETER4FVARBPROC GLH_EXT_NAME(glProgramLocalParameter4fvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterdvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMENVPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramEnvParameterfvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterdvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC GLH_EXT_NAME(glGetProgramLocalParameterfvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMIVARBPROC GLH_EXT_NAME(glGetProgramivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMSTRINGARBPROC GLH_EXT_NAME(glGetProgramStringARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBDVARBPROC GLH_EXT_NAME(glGetVertexAttribdvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBFVARBPROC GLH_EXT_NAME(glGetVertexAttribfvARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBIVARBPROC GLH_EXT_NAME(glGetVertexAttribivARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVARBPROC GLH_EXT_NAME(glGetVertexAttribPointervARB) GLH_INITIALIZER; - GLH_EXTERN PFNGLISPROGRAMARBPROC GLH_EXT_NAME(glIsProgramARB) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_abgr -#endif - -#ifdef GL_EXT_bgra -#endif - -#ifdef GL_EXT_blend_color - GLH_EXTERN PFNGLBLENDCOLOREXTPROC GLH_EXT_NAME(glBlendColorEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_blend_minmax - GLH_EXTERN PFNGLBLENDEQUATIONEXTPROC GLH_EXT_NAME(glBlendEquationEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_blend_subtract -#endif - -#ifdef GL_EXT_compiled_vertex_array - GLH_EXTERN PFNGLLOCKARRAYSEXTPROC GLH_EXT_NAME(glLockArraysEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLUNLOCKARRAYSEXTPROC GLH_EXT_NAME(glUnlockArraysEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_fog_coord - GLH_EXTERN PFNGLFOGCOORDDEXTPROC GLH_EXT_NAME(glFogCoorddEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLFOGCOORDDVEXTPROC GLH_EXT_NAME(glFogCoorddvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLFOGCOORDFEXTPROC GLH_EXT_NAME(glFogCoordfEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLFOGCOORDFVEXTPROC GLH_EXT_NAME(glFogCoordfvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLFOGCOORDPOINTEREXTPROC GLH_EXT_NAME(glFogCoordPointerEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_light_max_exponent -#endif - -#ifdef GL_EXT_packed_pixels -#endif - -#ifdef GL_EXT_paletted_texture - GLH_EXTERN PFNGLCOLORSUBTABLEEXTPROC GLH_EXT_NAME(glColorSubTableEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORTABLEEXTPROC GLH_EXT_NAME(glColorTableEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEEXTPROC GLH_EXT_NAME(glGetColorTableEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVEXTPROC GLH_EXT_NAME(glGetColorTableParameterfvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVEXTPROC GLH_EXT_NAME(glGetColorTableParameterivEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_point_parameters - GLH_EXTERN PFNGLPOINTPARAMETERFEXTPROC GLH_EXT_NAME(glPointParameterfEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLPOINTPARAMETERFVEXTPROC GLH_EXT_NAME(glPointParameterfvEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_rescale_normal -#endif - -#ifdef GL_EXT_secondary_color - GLH_EXTERN PFNGLSECONDARYCOLOR3BEXTPROC GLH_EXT_NAME(glSecondaryColor3bEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3BVEXTPROC GLH_EXT_NAME(glSecondaryColor3bvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3DEXTPROC GLH_EXT_NAME(glSecondaryColor3dEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3DVEXTPROC GLH_EXT_NAME(glSecondaryColor3dvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3FEXTPROC GLH_EXT_NAME(glSecondaryColor3fEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3FVEXTPROC GLH_EXT_NAME(glSecondaryColor3fvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3IEXTPROC GLH_EXT_NAME(glSecondaryColor3iEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3IVEXTPROC GLH_EXT_NAME(glSecondaryColor3ivEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3SEXTPROC GLH_EXT_NAME(glSecondaryColor3sEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3SVEXTPROC GLH_EXT_NAME(glSecondaryColor3svEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3UBEXTPROC GLH_EXT_NAME(glSecondaryColor3ubEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3UBVEXTPROC GLH_EXT_NAME(glSecondaryColor3ubvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3UIEXTPROC GLH_EXT_NAME(glSecondaryColor3uiEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3UIVEXTPROC GLH_EXT_NAME(glSecondaryColor3uivEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3USEXTPROC GLH_EXT_NAME(glSecondaryColor3usEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLOR3USVEXTPROC GLH_EXT_NAME(glSecondaryColor3usvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLSECONDARYCOLORPOINTEREXTPROC GLH_EXT_NAME(glSecondaryColorPointerEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_separate_specular_color -#endif - -#ifdef GL_EXT_shared_texture_palette -#endif - -#ifdef GL_EXT_stencil_wrap -#endif - -#ifdef GL_EXT_texture_compression_s3tc -#endif - -#ifdef GL_EXT_texture_cube_map -#endif - -#ifdef GL_EXT_texture_edge_clamp -#endif - -#ifdef GL_EXT_texture_env_add -#endif - -#ifdef GL_EXT_texture_env_combine -#endif - -#ifdef GL_EXT_texture_filter_anisotropic -#endif - -#ifdef GL_EXT_texture_lod_bias -#endif - -#ifdef GL_EXT_texture_object - GLH_EXTERN PFNGLARETEXTURESRESIDENTEXTPROC GLH_EXT_NAME(glAreTexturesResidentEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLBINDTEXTUREEXTPROC GLH_EXT_NAME(glBindTextureEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLDELETETEXTURESEXTPROC GLH_EXT_NAME(glDeleteTexturesEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGENTEXTURESEXTPROC GLH_EXT_NAME(glGenTexturesEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLISTEXTUREEXTPROC GLH_EXT_NAME(glIsTextureEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLPRIORITIZETEXTURESEXTPROC GLH_EXT_NAME(glPrioritizeTexturesEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_texture3D - GLH_EXTERN PFNGLTEXIMAGE3DEXTPROC GLH_EXT_NAME(glTexImage3DEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_vertex_array - GLH_EXTERN PFNGLARRAYELEMENTEXTPROC GLH_EXT_NAME(glArrayElementEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORPOINTEREXTPROC GLH_EXT_NAME(glColorPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLEDGEFLAGPOINTEREXTPROC GLH_EXT_NAME(glEdgeFlagPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPOINTERVEXTPROC GLH_EXT_NAME(glGetPointervEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLINDEXPOINTEREXTPROC GLH_EXT_NAME(glIndexPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLNORMALPOINTEREXTPROC GLH_EXT_NAME(glNormalPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLTEXCOORDPOINTEREXTPROC GLH_EXT_NAME(glTexCoordPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXPOINTEREXTPROC GLH_EXT_NAME(glVertexPointerEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLDRAWARRAYSEXTPROC GLH_EXT_NAME(glDrawArraysEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_EXT_vertex_weighting - GLH_EXTERN PFNGLVERTEXWEIGHTFEXTPROC GLH_EXT_NAME(glVertexWeightfEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXWEIGHTFVEXTPROC GLH_EXT_NAME(glVertexWeightfvEXT) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXWEIGHTPOINTEREXTPROC GLH_EXT_NAME(glVertexWeightPointerEXT) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_blend_square -#endif - -#ifdef GL_NV_evaluators - GLH_EXTERN PFNGLMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glMapControlPointsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLMAPPARAMETERIVNVPROC GLH_EXT_NAME(glMapParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLMAPPARAMETERFVNVPROC GLH_EXT_NAME(glMapParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPCONTROLPOINTSNVPROC GLH_EXT_NAME(glGetMapControlPointsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERIVNVPROC GLH_EXT_NAME(glGetMapAttribParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETMAPATTRIBPARAMETERFVNVPROC GLH_EXT_NAME(glGetMapAttribParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLEVALMAPSNVPROC GLH_EXT_NAME(glEvalMapsNV) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_fence - GLH_EXTERN PFNGLGENFENCESNVPROC GLH_EXT_NAME(glGenFencesNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLDELETEFENCESNVPROC GLH_EXT_NAME(glDeleteFencesNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLSETFENCENVPROC GLH_EXT_NAME(glSetFenceNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLTESTFENCENVPROC GLH_EXT_NAME(glTestFenceNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLFINISHFENCENVPROC GLH_EXT_NAME(glFinishFenceNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLISFENCENVPROC GLH_EXT_NAME(glIsFenceNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETFENCEIVNVPROC GLH_EXT_NAME(glGetFenceivNV) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_fog_distance -#endif - -#ifdef GL_NV_packed_depth_stencil -#endif - -#ifdef GL_NV_register_combiners - GLH_EXTERN PFNGLCOMBINERPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINERPARAMETERFNVPROC GLH_EXT_NAME(glCombinerParameterfNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINERPARAMETERIVNVPROC GLH_EXT_NAME(glCombinerParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINERPARAMETERINVPROC GLH_EXT_NAME(glCombinerParameteriNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINERINPUTNVPROC GLH_EXT_NAME(glCombinerInputNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOMBINEROUTPUTNVPROC GLH_EXT_NAME(glCombinerOutputNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLFINALCOMBINERINPUTNVPROC GLH_EXT_NAME(glFinalCombinerInputNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerInputParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetCombinerOutputParameterivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_register_combiners2 - GLH_EXTERN PFNGLCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glCombinerStageParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC GLH_EXT_NAME(glGetCombinerStageParameterfvNV) GLH_INITIALIZER; -#endif - -#ifdef GL_NV_texgen_reflection -#endif - -#ifdef GL_NV_texture_env_combine4 -#endif - -#ifdef GL_NV_texture_rectangle -#endif - -#ifdef GL_NV_texture_shader -#endif - -#ifdef GL_NV_vertex_array_range - GLH_EXTERN PFNGLFLUSHVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glFlushVertexArrayRangeNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXARRAYRANGENVPROC GLH_EXT_NAME(glVertexArrayRangeNV) GLH_INITIALIZER; -# ifdef _WIN32 - GLH_EXTERN PFNWGLALLOCATEMEMORYNVPROC GLH_EXT_NAME(wglAllocateMemoryNV) GLH_INITIALIZER; -# endif -# ifdef GLX_VERSION_1_3 - GLH_EXTERN PFNGLXALLOCATEMEMORYNVPROC GLH_EXT_NAME(glXAllocateMemoryNV) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLFREEMEMORYNVPROC GLH_EXT_NAME(wglFreeMemoryNV) GLH_INITIALIZER; -# endif -# ifdef GLX_VERSION_1_3 - GLH_EXTERN PFNGLXFREEMEMORYNVPROC GLH_EXT_NAME(glXFreeMemoryNV) GLH_INITIALIZER; -# endif -#endif - -#ifdef GL_NV_vertex_program - GLH_EXTERN PFNGLAREPROGRAMSRESIDENTNVPROC GLH_EXT_NAME(glAreProgramsResidentNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLBINDPROGRAMNVPROC GLH_EXT_NAME(glBindProgramNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLDELETEPROGRAMSNVPROC GLH_EXT_NAME(glDeleteProgramsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLEXECUTEPROGRAMNVPROC GLH_EXT_NAME(glExecuteProgramNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGENPROGRAMSNVPROC GLH_EXT_NAME(glGenProgramsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMPARAMETERDVNVPROC GLH_EXT_NAME(glGetProgramParameterdvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMPARAMETERFVNVPROC GLH_EXT_NAME(glGetProgramParameterfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMIVNVPROC GLH_EXT_NAME(glGetProgramivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETPROGRAMSTRINGNVPROC GLH_EXT_NAME(glGetProgramStringNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETTRACKMATRIXIVNVPROC GLH_EXT_NAME(glGetTrackMatrixivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBDVNVPROC GLH_EXT_NAME(glGetVertexAttribdvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBFVNVPROC GLH_EXT_NAME(glGetVertexAttribfvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBIVNVPROC GLH_EXT_NAME(glGetVertexAttribivNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETVERTEXATTRIBPOINTERVNVPROC GLH_EXT_NAME(glGetVertexAttribPointervNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLISPROGRAMNVPROC GLH_EXT_NAME(glIsProgramNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLLOADPROGRAMNVPROC GLH_EXT_NAME(glLoadProgramNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETER4DNVPROC GLH_EXT_NAME(glProgramParameter4dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETER4DVNVPROC GLH_EXT_NAME(glProgramParameter4dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETER4FNVPROC GLH_EXT_NAME(glProgramParameter4fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETER4FVNVPROC GLH_EXT_NAME(glProgramParameter4fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETERS4DVNVPROC GLH_EXT_NAME(glProgramParameters4dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLPROGRAMPARAMETERS4FVNVPROC GLH_EXT_NAME(glProgramParameters4fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLREQUESTRESIDENTPROGRAMSNVPROC GLH_EXT_NAME(glRequestResidentProgramsNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLTRACKMATRIXNVPROC GLH_EXT_NAME(glTrackMatrixNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBPOINTERNVPROC GLH_EXT_NAME(glVertexAttribPointerNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1DNVPROC GLH_EXT_NAME(glVertexAttrib1dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1DVNVPROC GLH_EXT_NAME(glVertexAttrib1dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1FNVPROC GLH_EXT_NAME(glVertexAttrib1fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1FVNVPROC GLH_EXT_NAME(glVertexAttrib1fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1SNVPROC GLH_EXT_NAME(glVertexAttrib1sNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB1SVNVPROC GLH_EXT_NAME(glVertexAttrib1svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2DNVPROC GLH_EXT_NAME(glVertexAttrib2dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2DVNVPROC GLH_EXT_NAME(glVertexAttrib2dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2FNVPROC GLH_EXT_NAME(glVertexAttrib2fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2FVNVPROC GLH_EXT_NAME(glVertexAttrib2fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2SNVPROC GLH_EXT_NAME(glVertexAttrib2sNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB2SVNVPROC GLH_EXT_NAME(glVertexAttrib2svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3DNVPROC GLH_EXT_NAME(glVertexAttrib3dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3DVNVPROC GLH_EXT_NAME(glVertexAttrib3dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3FNVPROC GLH_EXT_NAME(glVertexAttrib3fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3FVNVPROC GLH_EXT_NAME(glVertexAttrib3fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3SNVPROC GLH_EXT_NAME(glVertexAttrib3sNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB3SVNVPROC GLH_EXT_NAME(glVertexAttrib3svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4DNVPROC GLH_EXT_NAME(glVertexAttrib4dNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4DVNVPROC GLH_EXT_NAME(glVertexAttrib4dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4FNVPROC GLH_EXT_NAME(glVertexAttrib4fNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4FVNVPROC GLH_EXT_NAME(glVertexAttrib4fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4SNVPROC GLH_EXT_NAME(glVertexAttrib4sNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4SVNVPROC GLH_EXT_NAME(glVertexAttrib4svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIB4UBVNVPROC GLH_EXT_NAME(glVertexAttrib4ubvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS1DVNVPROC GLH_EXT_NAME(glVertexAttribs1dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS1FVNVPROC GLH_EXT_NAME(glVertexAttribs1fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS1SVNVPROC GLH_EXT_NAME(glVertexAttribs1svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS2DVNVPROC GLH_EXT_NAME(glVertexAttribs2dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS2FVNVPROC GLH_EXT_NAME(glVertexAttribs2fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS2SVNVPROC GLH_EXT_NAME(glVertexAttribs2svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS3DVNVPROC GLH_EXT_NAME(glVertexAttribs3dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS3FVNVPROC GLH_EXT_NAME(glVertexAttribs3fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS3SVNVPROC GLH_EXT_NAME(glVertexAttribs3svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS4DVNVPROC GLH_EXT_NAME(glVertexAttribs4dvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS4FVNVPROC GLH_EXT_NAME(glVertexAttribs4fvNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS4SVNVPROC GLH_EXT_NAME(glVertexAttribs4svNV) GLH_INITIALIZER; - GLH_EXTERN PFNGLVERTEXATTRIBS4UBVNVPROC GLH_EXT_NAME(glVertexAttribs4ubvNV) GLH_INITIALIZER; -#endif - -#ifdef GL_SGIS_generate_mipmap -#endif - -#ifdef GL_SGIS_texture_lod -#endif - -#ifdef GL_SGIX_depth_texture -#endif - -#ifdef GL_SGIX_shadow -#endif - -#ifdef GL_VERSION_1_2 - /* These routines are prefixed by the preprocessor constant - GLH_CORE_1_2_PREFIX to avoid colliding with the OpenGL 1.2 namespace. */ - GLH_EXTERN PFNGLBLENDCOLORPROC GLH_CORE_1_2_NAME(glBlendColor) GLH_INITIALIZER; - GLH_EXTERN PFNGLBLENDEQUATIONPROC GLH_CORE_1_2_NAME(glBlendEquation) GLH_INITIALIZER; - GLH_EXTERN PFNGLDRAWRANGEELEMENTSPROC GLH_CORE_1_2_NAME(glDrawRangeElements) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORTABLEPROC GLH_CORE_1_2_NAME(glColorTable) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glColorTableParameterfv) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glColorTableParameteriv) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOPYCOLORTABLEPROC GLH_CORE_1_2_NAME(glCopyColorTable) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPROC GLH_CORE_1_2_NAME(glGetColorTable) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERFVPROC GLH_CORE_1_2_NAME(glGetColorTableParameterfv) GLH_INITIALIZER; - GLH_EXTERN PFNGLGETCOLORTABLEPARAMETERIVPROC GLH_CORE_1_2_NAME(glGetColorTableParameteriv) GLH_INITIALIZER; - GLH_EXTERN PFNGLTEXIMAGE3DPROC GLH_CORE_1_2_NAME(glTexImage3D) GLH_INITIALIZER; - GLH_EXTERN PFNGLTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glTexSubImage3D) GLH_INITIALIZER; - GLH_EXTERN PFNGLCOPYTEXSUBIMAGE3DPROC GLH_CORE_1_2_NAME(glCopyTexSubImage3D) GLH_INITIALIZER; -#endif - -#ifdef GL_WIN_swap_hint - GLH_EXTERN PFNGLADDSWAPHINTRECTWINPROC GLH_EXT_NAME(glAddSwapHintRectWIN) GLH_INITIALIZER; -#endif - -#ifdef WGL_ARB_pbuffer -# ifdef _WIN32 - GLH_EXTERN PFNWGLCREATEPBUFFERARBPROC GLH_EXT_NAME(wglCreatePbufferARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLGETPBUFFERDCARBPROC GLH_EXT_NAME(wglGetPbufferDCARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLRELEASEPBUFFERDCARBPROC GLH_EXT_NAME(wglReleasePbufferDCARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLDESTROYPBUFFERARBPROC GLH_EXT_NAME(wglDestroyPbufferARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLQUERYPBUFFERARBPROC GLH_EXT_NAME(wglQueryPbufferARB) GLH_INITIALIZER; -# endif -#endif - -#ifdef WGL_ARB_render_texture -# ifdef _WIN32 - GLH_EXTERN PFNWGLBINDTEXIMAGEARBPROC GLH_EXT_NAME(wglBindTexImageARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLRELEASETEXIMAGEARBPROC GLH_EXT_NAME(wglReleaseTexImageARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLSETPBUFFERATTRIBARBPROC GLH_EXT_NAME(wglSetPbufferAttribARB) GLH_INITIALIZER; -# endif -#endif - -#ifdef WGL_ARB_pixel_format -# ifdef _WIN32 - GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBIVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribivARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLGETPIXELFORMATATTRIBFVARBPROC GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) GLH_INITIALIZER; -# endif -# ifdef _WIN32 - GLH_EXTERN PFNWGLCHOOSEPIXELFORMATARBPROC GLH_EXT_NAME(wglChoosePixelFormatARB) GLH_INITIALIZER; -# endif -#endif - - -#ifdef GLH_EXT_SINGLE_FILE - -int glh_init_extension(const char* extension) -{ - if (NULL == extension) { - return FALSE; -#ifdef GL_ARB_multitexture - } else if (0 == strcmp(extension, "GL_ARB_multitexture")) { - GLH_EXT_NAME(glMultiTexCoord1dARB) = (PFNGLMULTITEXCOORD1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1dARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1dvARB) = (PFNGLMULTITEXCOORD1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1dvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1dvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1fARB) = (PFNGLMULTITEXCOORD1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1fARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1fvARB) = (PFNGLMULTITEXCOORD1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1fvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1fvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1iARB) = (PFNGLMULTITEXCOORD1IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1iARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1iARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1ivARB) = (PFNGLMULTITEXCOORD1IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1ivARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1ivARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1sARB) = (PFNGLMULTITEXCOORD1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1sARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1sARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord1svARB) = (PFNGLMULTITEXCOORD1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord1svARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord1svARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2dARB) = (PFNGLMULTITEXCOORD2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2dARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2dvARB) = (PFNGLMULTITEXCOORD2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2dvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2dvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2fARB) = (PFNGLMULTITEXCOORD2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2fARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2fvARB) = (PFNGLMULTITEXCOORD2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2fvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2fvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2iARB) = (PFNGLMULTITEXCOORD2IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2iARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2iARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2ivARB) = (PFNGLMULTITEXCOORD2IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2ivARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2ivARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2sARB) = (PFNGLMULTITEXCOORD2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2sARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2sARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord2svARB) = (PFNGLMULTITEXCOORD2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord2svARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord2svARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3dARB) = (PFNGLMULTITEXCOORD3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3dARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3dvARB) = (PFNGLMULTITEXCOORD3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3dvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3dvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3fARB) = (PFNGLMULTITEXCOORD3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3fARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3fvARB) = (PFNGLMULTITEXCOORD3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3fvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3fvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3iARB) = (PFNGLMULTITEXCOORD3IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3iARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3iARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3ivARB) = (PFNGLMULTITEXCOORD3IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3ivARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3ivARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3sARB) = (PFNGLMULTITEXCOORD3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3sARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3sARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord3svARB) = (PFNGLMULTITEXCOORD3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord3svARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord3svARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4dARB) = (PFNGLMULTITEXCOORD4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4dARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4dvARB) = (PFNGLMULTITEXCOORD4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4dvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4dvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4fARB) = (PFNGLMULTITEXCOORD4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4fARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4fvARB) = (PFNGLMULTITEXCOORD4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4fvARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4fvARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4iARB) = (PFNGLMULTITEXCOORD4IARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4iARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4iARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4ivARB) = (PFNGLMULTITEXCOORD4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4ivARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4ivARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4sARB) = (PFNGLMULTITEXCOORD4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4sARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4sARB)) - return FALSE; - GLH_EXT_NAME(glMultiTexCoord4svARB) = (PFNGLMULTITEXCOORD4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultiTexCoord4svARB"); - if (NULL == GLH_EXT_NAME(glMultiTexCoord4svARB)) - return FALSE; - GLH_EXT_NAME(glActiveTextureARB) = (PFNGLACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glActiveTextureARB"); - if (NULL == GLH_EXT_NAME(glActiveTextureARB)) - return FALSE; - GLH_EXT_NAME(glClientActiveTextureARB) = (PFNGLCLIENTACTIVETEXTUREARBPROC)GLH_EXT_GET_PROC_ADDRESS("glClientActiveTextureARB"); - if (NULL == GLH_EXT_NAME(glClientActiveTextureARB)) - return FALSE; -#endif - -#ifdef GL_ARB_texture_border_clamp - } else if (0 == strcmp(extension, "GL_ARB_texture_border_clamp")) { -#endif - -#ifdef GL_ARB_texture_compression - } else if (0 == strcmp(extension, "GL_ARB_texture_compression")) { - GLH_EXT_NAME(glCompressedTexImage3DARB) = (PFNGLCOMPRESSEDTEXIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage3DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexImage3DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexImage2DARB) = (PFNGLCOMPRESSEDTEXIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage2DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexImage2DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexImage1DARB) = (PFNGLCOMPRESSEDTEXIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexImage1DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexImage1DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexSubImage3DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage3DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexSubImage3DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexSubImage2DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage2DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexSubImage2DARB)) - return FALSE; - GLH_EXT_NAME(glCompressedTexSubImage1DARB) = (PFNGLCOMPRESSEDTEXSUBIMAGE1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glCompressedTexSubImage1DARB"); - if (NULL == GLH_EXT_NAME(glCompressedTexSubImage1DARB)) - return FALSE; - GLH_EXT_NAME(glGetCompressedTexImageARB) = (PFNGLGETCOMPRESSEDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCompressedTexImageARB"); - if (NULL == GLH_EXT_NAME(glGetCompressedTexImageARB)) - return FALSE; -#endif - -#ifdef GL_ARB_texture_cube_map - } else if (0 == strcmp(extension, "GL_ARB_texture_cube_map")) { -#endif - -#ifdef GL_ARB_transpose_matrix - } else if (0 == strcmp(extension, "GL_ARB_transpose_matrix")) { - GLH_EXT_NAME(glLoadTransposeMatrixfARB) = (PFNGLLOADTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixfARB"); - if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixfARB)) - return FALSE; - GLH_EXT_NAME(glLoadTransposeMatrixdARB) = (PFNGLLOADTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadTransposeMatrixdARB"); - if (NULL == GLH_EXT_NAME(glLoadTransposeMatrixdARB)) - return FALSE; - GLH_EXT_NAME(glMultTransposeMatrixfARB) = (PFNGLMULTTRANSPOSEMATRIXFARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixfARB"); - if (NULL == GLH_EXT_NAME(glMultTransposeMatrixfARB)) - return FALSE; - GLH_EXT_NAME(glMultTransposeMatrixdARB) = (PFNGLMULTTRANSPOSEMATRIXDARBPROC)GLH_EXT_GET_PROC_ADDRESS("glMultTransposeMatrixdARB"); - if (NULL == GLH_EXT_NAME(glMultTransposeMatrixdARB)) - return FALSE; -#endif - -#ifdef GL_ARB_vertex_program - } else if (0 == strcmp(extension, "GL_ARB_vertex_program")) { - GLH_EXT_NAME(glVertexAttrib1sARB) = (PFNGLVERTEXATTRIB1SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1sARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1fARB) = (PFNGLVERTEXATTRIB1FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1fARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1dARB) = (PFNGLVERTEXATTRIB1DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1dARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2sARB) = (PFNGLVERTEXATTRIB2SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2sARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2fARB) = (PFNGLVERTEXATTRIB2FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2fARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2dARB) = (PFNGLVERTEXATTRIB2DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2dARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3sARB) = (PFNGLVERTEXATTRIB3SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3sARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3fARB) = (PFNGLVERTEXATTRIB3FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3fARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3dARB) = (PFNGLVERTEXATTRIB3DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3dARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4sARB) = (PFNGLVERTEXATTRIB4SARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4sARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4fARB) = (PFNGLVERTEXATTRIB4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4fARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4dARB) = (PFNGLVERTEXATTRIB4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4dARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NubARB) = (PFNGLVERTEXATTRIB4NUBARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NubARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1svARB) = (PFNGLVERTEXATTRIB1SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1svARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1fvARB) = (PFNGLVERTEXATTRIB1FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib1dvARB) = (PFNGLVERTEXATTRIB1DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2svARB) = (PFNGLVERTEXATTRIB2SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2svARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2fvARB) = (PFNGLVERTEXATTRIB2FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib2dvARB) = (PFNGLVERTEXATTRIB2DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3svARB) = (PFNGLVERTEXATTRIB3SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3svARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3fvARB) = (PFNGLVERTEXATTRIB3FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib3dvARB) = (PFNGLVERTEXATTRIB3DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4bvARB) = (PFNGLVERTEXATTRIB4BVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4bvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4bvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4svARB) = (PFNGLVERTEXATTRIB4SVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4svARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4ivARB) = (PFNGLVERTEXATTRIB4IVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ivARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4ivARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4ubvARB) = (PFNGLVERTEXATTRIB4UBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4usvARB) = (PFNGLVERTEXATTRIB4USVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4usvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4usvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4uivARB) = (PFNGLVERTEXATTRIB4UIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4uivARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4uivARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4fvARB) = (PFNGLVERTEXATTRIB4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4dvARB) = (PFNGLVERTEXATTRIB4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NbvARB) = (PFNGLVERTEXATTRIB4NBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NbvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NbvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NsvARB) = (PFNGLVERTEXATTRIB4NSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NsvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NsvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NivARB) = (PFNGLVERTEXATTRIB4NIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NivARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NivARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NubvARB) = (PFNGLVERTEXATTRIB4NUBVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NubvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NubvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NusvARB) = (PFNGLVERTEXATTRIB4NUSVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NusvARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NusvARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttrib4NuivARB) = (PFNGLVERTEXATTRIB4NUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4NuivARB"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4NuivARB)) - return GL_FALSE; - GLH_EXT_NAME(glVertexAttribPointerARB) = (PFNGLVERTEXATTRIBPOINTERARBPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerARB"); - if (NULL == GLH_EXT_NAME(glVertexAttribPointerARB)) - return GL_FALSE; - GLH_EXT_NAME(glEnableVertexAttribArrayARB) = (PFNGLENABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glEnableVertexAttribArrayARB"); - if (NULL == GLH_EXT_NAME(glEnableVertexAttribArrayARB)) - return GL_FALSE; - GLH_EXT_NAME(glDisableVertexAttribArrayARB) = (PFNGLDISABLEVERTEXATTRIBARRAYARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDisableVertexAttribArrayARB"); - if (NULL == GLH_EXT_NAME(glDisableVertexAttribArrayARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramStringARB) = (PFNGLPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramStringARB"); - if (NULL == GLH_EXT_NAME(glProgramStringARB)) - return GL_FALSE; - GLH_EXT_NAME(glBindProgramARB) = (PFNGLBINDPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramARB"); - if (NULL == GLH_EXT_NAME(glBindProgramARB)) - return GL_FALSE; - GLH_EXT_NAME(glDeleteProgramsARB) = (PFNGLDELETEPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsARB"); - if (NULL == GLH_EXT_NAME(glDeleteProgramsARB)) - return GL_FALSE; - GLH_EXT_NAME(glGenProgramsARB) = (PFNGLGENPROGRAMSARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsARB"); - if (NULL == GLH_EXT_NAME(glGenProgramsARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramEnvParameter4dARB) = (PFNGLPROGRAMENVPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dARB"); - if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramEnvParameter4dvARB) = (PFNGLPROGRAMENVPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4dvARB"); - if (NULL == GLH_EXT_NAME(glProgramEnvParameter4dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramEnvParameter4fARB) = (PFNGLPROGRAMENVPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fARB"); - if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramEnvParameter4fvARB) = (PFNGLPROGRAMENVPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramEnvParameter4fvARB"); - if (NULL == GLH_EXT_NAME(glProgramEnvParameter4fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramLocalParameter4dARB) = (PFNGLPROGRAMLOCALPARAMETER4DARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dARB"); - if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramLocalParameter4dvARB) = (PFNGLPROGRAMLOCALPARAMETER4DVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4dvARB"); - if (NULL == GLH_EXT_NAME(glProgramLocalParameter4dvARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramLocalParameter4fARB) = (PFNGLPROGRAMLOCALPARAMETER4FARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fARB"); - if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fARB)) - return GL_FALSE; - GLH_EXT_NAME(glProgramLocalParameter4fvARB) = (PFNGLPROGRAMLOCALPARAMETER4FVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramLocalParameter4fvARB"); - if (NULL == GLH_EXT_NAME(glProgramLocalParameter4fvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramEnvParameterdvARB) = (PFNGLGETPROGRAMENVPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterdvARB"); - if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterdvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramEnvParameterfvARB) = (PFNGLGETPROGRAMENVPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramEnvParameterfvARB"); - if (NULL == GLH_EXT_NAME(glGetProgramEnvParameterfvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramLocalParameterdvARB) = (PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterdvARB"); - if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterdvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramLocalParameterfvARB) = (PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramLocalParameterfvARB"); - if (NULL == GLH_EXT_NAME(glGetProgramLocalParameterfvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramivARB) = (PFNGLGETPROGRAMIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivARB"); - if (NULL == GLH_EXT_NAME(glGetProgramivARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetProgramStringARB) = (PFNGLGETPROGRAMSTRINGARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringARB"); - if (NULL == GLH_EXT_NAME(glGetProgramStringARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetVertexAttribdvARB) = (PFNGLGETVERTEXATTRIBDVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvARB"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribdvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetVertexAttribfvARB) = (PFNGLGETVERTEXATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvARB"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribfvARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetVertexAttribivARB) = (PFNGLGETVERTEXATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivARB"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribivARB)) - return GL_FALSE; - GLH_EXT_NAME(glGetVertexAttribPointervARB) = (PFNGLGETVERTEXATTRIBPOINTERVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervARB"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervARB)) - return GL_FALSE; - GLH_EXT_NAME(glIsProgramARB) = (PFNGLISPROGRAMARBPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramARB"); - if (NULL == GLH_EXT_NAME(glIsProgramARB)) - return GL_FALSE; -#endif - -#ifdef GL_EXT_abgr - } else if (0 == strcmp(extension, "GL_EXT_abgr")) { -#endif - -#ifdef GL_EXT_bgra - } else if (0 == strcmp(extension, "GL_EXT_bgra")) { -#endif - -#ifdef GL_EXT_blend_color - } else if (0 == strcmp(extension, "GL_EXT_blend_color")) { - GLH_EXT_NAME(glBlendColorEXT) = (PFNGLBLENDCOLOREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColorEXT"); - if (NULL == GLH_EXT_NAME(glBlendColorEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_blend_minmax - } else if (0 == strcmp(extension, "GL_EXT_blend_minmax")) { - GLH_EXT_NAME(glBlendEquationEXT) = (PFNGLBLENDEQUATIONEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquationEXT"); - if (NULL == GLH_EXT_NAME(glBlendEquationEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_blend_subtract - } else if (0 == strcmp(extension, "GL_EXT_blend_subtract")) { -#endif - -#ifdef GL_EXT_compiled_vertex_array - } else if (0 == strcmp(extension, "GL_EXT_compiled_vertex_array")) { - GLH_EXT_NAME(glLockArraysEXT) = (PFNGLLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glLockArraysEXT"); - if (NULL == GLH_EXT_NAME(glLockArraysEXT)) - return FALSE; - GLH_EXT_NAME(glUnlockArraysEXT) = (PFNGLUNLOCKARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glUnlockArraysEXT"); - if (NULL == GLH_EXT_NAME(glUnlockArraysEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_fog_coord - } else if (0 == strcmp(extension, "GL_EXT_fog_coord")) { - GLH_EXT_NAME(glFogCoorddEXT) = (PFNGLFOGCOORDDEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddEXT"); - if (NULL == GLH_EXT_NAME(glFogCoorddEXT)) - return FALSE; - GLH_EXT_NAME(glFogCoorddvEXT) = (PFNGLFOGCOORDDVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoorddvEXT"); - if (NULL == GLH_EXT_NAME(glFogCoorddvEXT)) - return FALSE; - GLH_EXT_NAME(glFogCoordfEXT) = (PFNGLFOGCOORDFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfEXT"); - if (NULL == GLH_EXT_NAME(glFogCoordfEXT)) - return FALSE; - GLH_EXT_NAME(glFogCoordfvEXT) = (PFNGLFOGCOORDFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordfvEXT"); - if (NULL == GLH_EXT_NAME(glFogCoordfvEXT)) - return FALSE; - GLH_EXT_NAME(glFogCoordPointerEXT) = (PFNGLFOGCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glFogCoordPointerEXT"); - if (NULL == GLH_EXT_NAME(glFogCoordPointerEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_light_max_exponent - } else if (0 == strcmp(extension, "GL_EXT_light_max_exponent")) { -#endif - -#ifdef GL_EXT_packed_pixels - } else if (0 == strcmp(extension, "GL_EXT_packed_pixels")) { -#endif - -#ifdef GL_EXT_paletted_texture - } else if (0 == strcmp(extension, "GL_EXT_paletted_texture")) { - GLH_EXT_NAME(glColorSubTableEXT) = (PFNGLCOLORSUBTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorSubTableEXT"); - if (NULL == GLH_EXT_NAME(glColorSubTableEXT)) - return FALSE; - GLH_EXT_NAME(glColorTableEXT) = (PFNGLCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableEXT"); - if (NULL == GLH_EXT_NAME(glColorTableEXT)) - return FALSE; - GLH_EXT_NAME(glGetColorTableEXT) = (PFNGLGETCOLORTABLEEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableEXT"); - if (NULL == GLH_EXT_NAME(glGetColorTableEXT)) - return FALSE; - GLH_EXT_NAME(glGetColorTableParameterfvEXT) = (PFNGLGETCOLORTABLEPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfvEXT"); - if (NULL == GLH_EXT_NAME(glGetColorTableParameterfvEXT)) - return FALSE; - GLH_EXT_NAME(glGetColorTableParameterivEXT) = (PFNGLGETCOLORTABLEPARAMETERIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterivEXT"); - if (NULL == GLH_EXT_NAME(glGetColorTableParameterivEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_point_parameters - } else if (0 == strcmp(extension, "GL_EXT_point_parameters")) { - GLH_EXT_NAME(glPointParameterfEXT) = (PFNGLPOINTPARAMETERFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfEXT"); - if (NULL == GLH_EXT_NAME(glPointParameterfEXT)) - return FALSE; - GLH_EXT_NAME(glPointParameterfvEXT) = (PFNGLPOINTPARAMETERFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPointParameterfvEXT"); - if (NULL == GLH_EXT_NAME(glPointParameterfvEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_rescale_normal - } else if (0 == strcmp(extension, "GL_EXT_rescale_normal")) { -#endif - -#ifdef GL_EXT_secondary_color - } else if (0 == strcmp(extension, "GL_EXT_secondary_color")) { - GLH_EXT_NAME(glSecondaryColor3bEXT) = (PFNGLSECONDARYCOLOR3BEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3bEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3bvEXT) = (PFNGLSECONDARYCOLOR3BVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3bvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3bvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3dEXT) = (PFNGLSECONDARYCOLOR3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3dEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3dvEXT) = (PFNGLSECONDARYCOLOR3DVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3dvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3dvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3fEXT) = (PFNGLSECONDARYCOLOR3FEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3fEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3fvEXT) = (PFNGLSECONDARYCOLOR3FVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3fvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3fvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3iEXT) = (PFNGLSECONDARYCOLOR3IEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3iEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3iEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3ivEXT) = (PFNGLSECONDARYCOLOR3IVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ivEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3ivEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3sEXT) = (PFNGLSECONDARYCOLOR3SEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3sEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3sEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3svEXT) = (PFNGLSECONDARYCOLOR3SVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3svEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3svEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3ubEXT) = (PFNGLSECONDARYCOLOR3UBEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3ubEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3ubvEXT) = (PFNGLSECONDARYCOLOR3UBVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3ubvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3ubvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3uiEXT) = (PFNGLSECONDARYCOLOR3UIEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uiEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3uiEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3uivEXT) = (PFNGLSECONDARYCOLOR3UIVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3uivEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3uivEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3usEXT) = (PFNGLSECONDARYCOLOR3USEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3usEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColor3usvEXT) = (PFNGLSECONDARYCOLOR3USVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColor3usvEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColor3usvEXT)) - return FALSE; - GLH_EXT_NAME(glSecondaryColorPointerEXT) = (PFNGLSECONDARYCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glSecondaryColorPointerEXT"); - if (NULL == GLH_EXT_NAME(glSecondaryColorPointerEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_separate_specular_color - } else if (0 == strcmp(extension, "GL_EXT_separate_specular_color")) { -#endif - -#ifdef GL_EXT_shared_texture_palette - } else if (0 == strcmp(extension, "GL_EXT_shared_texture_palette")) { -#endif - -#ifdef GL_EXT_stencil_wrap - } else if (0 == strcmp(extension, "GL_EXT_stencil_wrap")) { -#endif - -#ifdef GL_EXT_texture_compression_s3tc - } else if (0 == strcmp(extension, "GL_EXT_texture_compression_s3tc")) { -#endif - -#ifdef GL_EXT_texture_cube_map - } else if (0 == strcmp(extension, "GL_EXT_texture_cube_map")) { -#endif - -#ifdef GL_EXT_texture_edge_clamp - } else if (0 == strcmp(extension, "GL_EXT_texture_edge_clamp")) { -#endif - -#ifdef GL_EXT_texture_env_add - } else if (0 == strcmp(extension, "GL_EXT_texture_env_add")) { -#endif - -#ifdef GL_EXT_texture_env_combine - } else if (0 == strcmp(extension, "GL_EXT_texture_env_combine")) { -#endif - -#ifdef GL_EXT_texture_filter_anisotropic - } else if (0 == strcmp(extension, "GL_EXT_texture_filter_anisotropic")) { -#endif - -#ifdef GL_EXT_texture_lod_bias - } else if (0 == strcmp(extension, "GL_EXT_texture_lod_bias")) { -#endif - -#ifdef GL_EXT_texture_object - } else if (0 == strcmp(extension, "GL_EXT_texture_object")) { - GLH_EXT_NAME(glAreTexturesResidentEXT) = (PFNGLARETEXTURESRESIDENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glAreTexturesResidentEXT"); - if (NULL == GLH_EXT_NAME(glAreTexturesResidentEXT)) - return FALSE; - GLH_EXT_NAME(glBindTextureEXT) = (PFNGLBINDTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glBindTextureEXT"); - if (NULL == GLH_EXT_NAME(glBindTextureEXT)) - return FALSE; - GLH_EXT_NAME(glDeleteTexturesEXT) = (PFNGLDELETETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteTexturesEXT"); - if (NULL == GLH_EXT_NAME(glDeleteTexturesEXT)) - return FALSE; - GLH_EXT_NAME(glGenTexturesEXT) = (PFNGLGENTEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGenTexturesEXT"); - if (NULL == GLH_EXT_NAME(glGenTexturesEXT)) - return FALSE; - GLH_EXT_NAME(glIsTextureEXT) = (PFNGLISTEXTUREEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIsTextureEXT"); - if (NULL == GLH_EXT_NAME(glIsTextureEXT)) - return FALSE; - GLH_EXT_NAME(glPrioritizeTexturesEXT) = (PFNGLPRIORITIZETEXTURESEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glPrioritizeTexturesEXT"); - if (NULL == GLH_EXT_NAME(glPrioritizeTexturesEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_texture3D - } else if (0 == strcmp(extension, "GL_EXT_texture3D")) { - GLH_EXT_NAME(glTexImage3DEXT) = (PFNGLTEXIMAGE3DEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3DEXT"); - if (NULL == GLH_EXT_NAME(glTexImage3DEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_vertex_array - } else if (0 == strcmp(extension, "GL_EXT_vertex_array")) { - GLH_EXT_NAME(glArrayElementEXT) = (PFNGLARRAYELEMENTEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glArrayElementEXT"); - if (NULL == GLH_EXT_NAME(glArrayElementEXT)) - return FALSE; - GLH_EXT_NAME(glColorPointerEXT) = (PFNGLCOLORPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glColorPointerEXT"); - if (NULL == GLH_EXT_NAME(glColorPointerEXT)) - return FALSE; - GLH_EXT_NAME(glEdgeFlagPointerEXT) = (PFNGLEDGEFLAGPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glEdgeFlagPointerEXT"); - if (NULL == GLH_EXT_NAME(glEdgeFlagPointerEXT)) - return FALSE; - GLH_EXT_NAME(glGetPointervEXT) = (PFNGLGETPOINTERVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glGetPointervEXT"); - if (NULL == GLH_EXT_NAME(glGetPointervEXT)) - return FALSE; - GLH_EXT_NAME(glIndexPointerEXT) = (PFNGLINDEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glIndexPointerEXT"); - if (NULL == GLH_EXT_NAME(glIndexPointerEXT)) - return FALSE; - GLH_EXT_NAME(glNormalPointerEXT) = (PFNGLNORMALPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glNormalPointerEXT"); - if (NULL == GLH_EXT_NAME(glNormalPointerEXT)) - return FALSE; - GLH_EXT_NAME(glTexCoordPointerEXT) = (PFNGLTEXCOORDPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glTexCoordPointerEXT"); - if (NULL == GLH_EXT_NAME(glTexCoordPointerEXT)) - return FALSE; - GLH_EXT_NAME(glVertexPointerEXT) = (PFNGLVERTEXPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexPointerEXT"); - if (NULL == GLH_EXT_NAME(glVertexPointerEXT)) - return FALSE; - GLH_EXT_NAME(glDrawArraysEXT) = (PFNGLDRAWARRAYSEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawArraysEXT"); - if (NULL == GLH_EXT_NAME(glDrawArraysEXT)) - return FALSE; -#endif - -#ifdef GL_EXT_vertex_weighting - } else if (0 == strcmp(extension, "GL_EXT_vertex_weighting")) { - GLH_EXT_NAME(glVertexWeightfEXT) = (PFNGLVERTEXWEIGHTFEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfEXT"); - if (NULL == GLH_EXT_NAME(glVertexWeightfEXT)) - return FALSE; - GLH_EXT_NAME(glVertexWeightfvEXT) = (PFNGLVERTEXWEIGHTFVEXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightfvEXT"); - if (NULL == GLH_EXT_NAME(glVertexWeightfvEXT)) - return FALSE; - GLH_EXT_NAME(glVertexWeightPointerEXT) = (PFNGLVERTEXWEIGHTPOINTEREXTPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexWeightPointerEXT"); - if (NULL == GLH_EXT_NAME(glVertexWeightPointerEXT)) - return FALSE; -#endif - -#ifdef GL_NV_blend_square - } else if (0 == strcmp(extension, "GL_NV_blend_square")) { -#endif - -#ifdef GL_NV_evaluators - } else if (0 == strcmp(extension, "GL_NV_evaluators")) { - GLH_EXT_NAME(glMapControlPointsNV) = (PFNGLMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapControlPointsNV"); - if (NULL == GLH_EXT_NAME(glMapControlPointsNV)) - return FALSE; - GLH_EXT_NAME(glMapParameterivNV) = (PFNGLMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterivNV"); - if (NULL == GLH_EXT_NAME(glMapParameterivNV)) - return FALSE; - GLH_EXT_NAME(glMapParameterfvNV) = (PFNGLMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glMapParameterfvNV"); - if (NULL == GLH_EXT_NAME(glMapParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetMapControlPointsNV) = (PFNGLGETMAPCONTROLPOINTSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapControlPointsNV"); - if (NULL == GLH_EXT_NAME(glGetMapControlPointsNV)) - return FALSE; - GLH_EXT_NAME(glGetMapParameterivNV) = (PFNGLGETMAPPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetMapParameterivNV)) - return FALSE; - GLH_EXT_NAME(glGetMapParameterfvNV) = (PFNGLGETMAPPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetMapParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetMapAttribParameterivNV) = (PFNGLGETMAPATTRIBPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetMapAttribParameterivNV)) - return FALSE; - GLH_EXT_NAME(glGetMapAttribParameterfvNV) = (PFNGLGETMAPATTRIBPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetMapAttribParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetMapAttribParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glEvalMapsNV) = (PFNGLEVALMAPSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glEvalMapsNV"); - if (NULL == GLH_EXT_NAME(glEvalMapsNV)) - return FALSE; -#endif - -#ifdef GL_NV_fence - } else if (0 == strcmp(extension, "GL_NV_fence")) { - GLH_EXT_NAME(glGenFencesNV) = (PFNGLGENFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenFencesNV"); - if (NULL == GLH_EXT_NAME(glGenFencesNV)) - return FALSE; - GLH_EXT_NAME(glDeleteFencesNV) = (PFNGLDELETEFENCESNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteFencesNV"); - if (NULL == GLH_EXT_NAME(glDeleteFencesNV)) - return FALSE; - GLH_EXT_NAME(glSetFenceNV) = (PFNGLSETFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glSetFenceNV"); - if (NULL == GLH_EXT_NAME(glSetFenceNV)) - return FALSE; - GLH_EXT_NAME(glTestFenceNV) = (PFNGLTESTFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glTestFenceNV"); - if (NULL == GLH_EXT_NAME(glTestFenceNV)) - return FALSE; - GLH_EXT_NAME(glFinishFenceNV) = (PFNGLFINISHFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinishFenceNV"); - if (NULL == GLH_EXT_NAME(glFinishFenceNV)) - return FALSE; - GLH_EXT_NAME(glIsFenceNV) = (PFNGLISFENCENVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsFenceNV"); - if (NULL == GLH_EXT_NAME(glIsFenceNV)) - return FALSE; - GLH_EXT_NAME(glGetFenceivNV) = (PFNGLGETFENCEIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFenceivNV"); - if (NULL == GLH_EXT_NAME(glGetFenceivNV)) - return FALSE; -#endif - -#ifdef GL_NV_fog_distance - } else if (0 == strcmp(extension, "GL_NV_fog_distance")) { -#endif - -#ifdef GL_NV_packed_depth_stencil - } else if (0 == strcmp(extension, "GL_NV_packed_depth_stencil")) { -#endif - -#ifdef GL_NV_register_combiners - } else if (0 == strcmp(extension, "GL_NV_register_combiners")) { - GLH_EXT_NAME(glCombinerParameterfvNV) = (PFNGLCOMBINERPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfvNV"); - if (NULL == GLH_EXT_NAME(glCombinerParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glCombinerParameterfNV) = (PFNGLCOMBINERPARAMETERFNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterfNV"); - if (NULL == GLH_EXT_NAME(glCombinerParameterfNV)) - return FALSE; - GLH_EXT_NAME(glCombinerParameterivNV) = (PFNGLCOMBINERPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameterivNV"); - if (NULL == GLH_EXT_NAME(glCombinerParameterivNV)) - return FALSE; - GLH_EXT_NAME(glCombinerParameteriNV) = (PFNGLCOMBINERPARAMETERINVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerParameteriNV"); - if (NULL == GLH_EXT_NAME(glCombinerParameteriNV)) - return FALSE; - GLH_EXT_NAME(glCombinerInputNV) = (PFNGLCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerInputNV"); - if (NULL == GLH_EXT_NAME(glCombinerInputNV)) - return FALSE; - GLH_EXT_NAME(glCombinerOutputNV) = (PFNGLCOMBINEROUTPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerOutputNV"); - if (NULL == GLH_EXT_NAME(glCombinerOutputNV)) - return FALSE; - GLH_EXT_NAME(glFinalCombinerInputNV) = (PFNGLFINALCOMBINERINPUTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glFinalCombinerInputNV"); - if (NULL == GLH_EXT_NAME(glFinalCombinerInputNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerInputParameterfvNV) = (PFNGLGETCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerInputParameterivNV) = (PFNGLGETCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerInputParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerInputParameterivNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerOutputParameterfvNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerOutputParameterivNV) = (PFNGLGETCOMBINEROUTPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerOutputParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerOutputParameterivNV)) - return FALSE; - GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV) = (PFNGLGETFINALCOMBINERINPUTPARAMETERIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetFinalCombinerInputParameterivNV"); - if (NULL == GLH_EXT_NAME(glGetFinalCombinerInputParameterivNV)) - return FALSE; -#endif - -#ifdef GL_NV_register_combiners2 - } else if (0 == strcmp(extension, "GL_NV_register_combiners2")) { - GLH_EXT_NAME(glCombinerStageParameterfvNV) = (PFNGLCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glCombinerStageParameterfvNV"); - if (NULL == GLH_EXT_NAME(glCombinerStageParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetCombinerStageParameterfvNV) = (PFNGLGETCOMBINERSTAGEPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetCombinerStageParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetCombinerStageParameterfvNV)) - return FALSE; -#endif - -#ifdef GL_NV_texgen_reflection - } else if (0 == strcmp(extension, "GL_NV_texgen_reflection")) { -#endif - -#ifdef GL_NV_texture_env_combine4 - } else if (0 == strcmp(extension, "GL_NV_texture_env_combine4")) { -#endif - -#ifdef GL_NV_texture_rectangle - } else if (0 == strcmp(extension, "GL_NV_texture_rectangle")) { -#endif - -#ifdef GL_NV_texture_shader - } else if (0 == strcmp(extension, "GL_NV_texture_shader")) { -#endif - -#ifdef GL_NV_vertex_array_range - } else if (0 == strcmp(extension, "GL_NV_vertex_array_range")) { - GLH_EXT_NAME(glFlushVertexArrayRangeNV) = (PFNGLFLUSHVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glFlushVertexArrayRangeNV"); - if (NULL == GLH_EXT_NAME(glFlushVertexArrayRangeNV)) - return FALSE; - GLH_EXT_NAME(glVertexArrayRangeNV) = (PFNGLVERTEXARRAYRANGENVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexArrayRangeNV"); - if (NULL == GLH_EXT_NAME(glVertexArrayRangeNV)) - return FALSE; -# ifdef _WIN32 - GLH_EXT_NAME(wglAllocateMemoryNV) = (PFNWGLALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglAllocateMemoryNV"); - if (NULL == GLH_EXT_NAME(wglAllocateMemoryNV)) - return FALSE; -# endif -# ifdef GLX_VERSION_1_3 - GLH_EXT_NAME(glXAllocateMemoryNV) = (PFNGLXALLOCATEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXAllocateMemoryNV"); - if (NULL == GLH_EXT_NAME(glXAllocateMemoryNV)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglFreeMemoryNV) = (PFNWGLFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("wglFreeMemoryNV"); - if (NULL == GLH_EXT_NAME(wglFreeMemoryNV)) - return FALSE; -# endif -# ifdef GLX_VERSION_1_3 - GLH_EXT_NAME(glXFreeMemoryNV) = (PFNGLXFREEMEMORYNVPROC)GLH_EXT_GET_PROC_ADDRESS("glXFreeMemoryNV"); - if (NULL == GLH_EXT_NAME(glXFreeMemoryNV)) - return FALSE; -# endif -#endif - -#ifdef GL_NV_vertex_program - } else if (0 == strcmp(extension, "GL_NV_vertex_program")) { - GLH_EXT_NAME(glAreProgramsResidentNV) = (PFNGLAREPROGRAMSRESIDENTNVPROC)GLH_EXT_GET_PROC_ADDRESS("glAreProgramsResidentNV"); - if (NULL == GLH_EXT_NAME(glAreProgramsResidentNV)) - return FALSE; - GLH_EXT_NAME(glBindProgramNV) = (PFNGLBINDPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glBindProgramNV"); - if (NULL == GLH_EXT_NAME(glBindProgramNV)) - return FALSE; - GLH_EXT_NAME(glDeleteProgramsNV) = (PFNGLDELETEPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glDeleteProgramsNV"); - if (NULL == GLH_EXT_NAME(glDeleteProgramsNV)) - return FALSE; - GLH_EXT_NAME(glExecuteProgramNV) = (PFNGLEXECUTEPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glExecuteProgramNV"); - if (NULL == GLH_EXT_NAME(glExecuteProgramNV)) - return FALSE; - GLH_EXT_NAME(glGenProgramsNV) = (PFNGLGENPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGenProgramsNV"); - if (NULL == GLH_EXT_NAME(glGenProgramsNV)) - return FALSE; - GLH_EXT_NAME(glGetProgramParameterdvNV) = (PFNGLGETPROGRAMPARAMETERDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterdvNV"); - if (NULL == GLH_EXT_NAME(glGetProgramParameterdvNV)) - return FALSE; - GLH_EXT_NAME(glGetProgramParameterfvNV) = (PFNGLGETPROGRAMPARAMETERFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramParameterfvNV"); - if (NULL == GLH_EXT_NAME(glGetProgramParameterfvNV)) - return FALSE; - GLH_EXT_NAME(glGetProgramivNV) = (PFNGLGETPROGRAMIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramivNV"); - if (NULL == GLH_EXT_NAME(glGetProgramivNV)) - return FALSE; - GLH_EXT_NAME(glGetProgramStringNV) = (PFNGLGETPROGRAMSTRINGNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetProgramStringNV"); - if (NULL == GLH_EXT_NAME(glGetProgramStringNV)) - return FALSE; - GLH_EXT_NAME(glGetTrackMatrixivNV) = (PFNGLGETTRACKMATRIXIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetTrackMatrixivNV"); - if (NULL == GLH_EXT_NAME(glGetTrackMatrixivNV)) - return FALSE; - GLH_EXT_NAME(glGetVertexAttribdvNV) = (PFNGLGETVERTEXATTRIBDVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribdvNV"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribdvNV)) - return FALSE; - GLH_EXT_NAME(glGetVertexAttribfvNV) = (PFNGLGETVERTEXATTRIBFVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribfvNV"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribfvNV)) - return FALSE; - GLH_EXT_NAME(glGetVertexAttribivNV) = (PFNGLGETVERTEXATTRIBIVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribivNV"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribivNV)) - return FALSE; - GLH_EXT_NAME(glGetVertexAttribPointervNV) = (PFNGLGETVERTEXATTRIBPOINTERVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetVertexAttribPointervNV"); - if (NULL == GLH_EXT_NAME(glGetVertexAttribPointervNV)) - return FALSE; - GLH_EXT_NAME(glIsProgramNV) = (PFNGLISPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glIsProgramNV"); - if (NULL == GLH_EXT_NAME(glIsProgramNV)) - return FALSE; - GLH_EXT_NAME(glLoadProgramNV) = (PFNGLLOADPROGRAMNVPROC)GLH_EXT_GET_PROC_ADDRESS("glLoadProgramNV"); - if (NULL == GLH_EXT_NAME(glLoadProgramNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameter4dNV) = (PFNGLPROGRAMPARAMETER4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dNV"); - if (NULL == GLH_EXT_NAME(glProgramParameter4dNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameter4dvNV) = (PFNGLPROGRAMPARAMETER4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4dvNV"); - if (NULL == GLH_EXT_NAME(glProgramParameter4dvNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameter4fNV) = (PFNGLPROGRAMPARAMETER4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fNV"); - if (NULL == GLH_EXT_NAME(glProgramParameter4fNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameter4fvNV) = (PFNGLPROGRAMPARAMETER4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameter4fvNV"); - if (NULL == GLH_EXT_NAME(glProgramParameter4fvNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameters4dvNV) = (PFNGLPROGRAMPARAMETERS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4dvNV"); - if (NULL == GLH_EXT_NAME(glProgramParameters4dvNV)) - return FALSE; - GLH_EXT_NAME(glProgramParameters4fvNV) = (PFNGLPROGRAMPARAMETERS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glProgramParameters4fvNV"); - if (NULL == GLH_EXT_NAME(glProgramParameters4fvNV)) - return FALSE; - GLH_EXT_NAME(glRequestResidentProgramsNV) = (PFNGLREQUESTRESIDENTPROGRAMSNVPROC)GLH_EXT_GET_PROC_ADDRESS("glRequestResidentProgramsNV"); - if (NULL == GLH_EXT_NAME(glRequestResidentProgramsNV)) - return FALSE; - GLH_EXT_NAME(glTrackMatrixNV) = (PFNGLTRACKMATRIXNVPROC)GLH_EXT_GET_PROC_ADDRESS("glTrackMatrixNV"); - if (NULL == GLH_EXT_NAME(glTrackMatrixNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribPointerNV) = (PFNGLVERTEXATTRIBPOINTERNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribPointerNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribPointerNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1dNV) = (PFNGLVERTEXATTRIB1DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1dNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1dvNV) = (PFNGLVERTEXATTRIB1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1fNV) = (PFNGLVERTEXATTRIB1FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1fNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1fvNV) = (PFNGLVERTEXATTRIB1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1sNV) = (PFNGLVERTEXATTRIB1SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1sNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1sNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib1svNV) = (PFNGLVERTEXATTRIB1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib1svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib1svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2dNV) = (PFNGLVERTEXATTRIB2DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2dNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2dvNV) = (PFNGLVERTEXATTRIB2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2fNV) = (PFNGLVERTEXATTRIB2FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2fNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2fvNV) = (PFNGLVERTEXATTRIB2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2sNV) = (PFNGLVERTEXATTRIB2SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2sNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2sNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib2svNV) = (PFNGLVERTEXATTRIB2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib2svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib2svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3dNV) = (PFNGLVERTEXATTRIB3DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3dNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3dvNV) = (PFNGLVERTEXATTRIB3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3fNV) = (PFNGLVERTEXATTRIB3FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3fNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3fvNV) = (PFNGLVERTEXATTRIB3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3sNV) = (PFNGLVERTEXATTRIB3SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3sNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3sNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib3svNV) = (PFNGLVERTEXATTRIB3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib3svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib3svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4dNV) = (PFNGLVERTEXATTRIB4DNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4dNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4dvNV) = (PFNGLVERTEXATTRIB4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4fNV) = (PFNGLVERTEXATTRIB4FNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4fNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4fvNV) = (PFNGLVERTEXATTRIB4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4sNV) = (PFNGLVERTEXATTRIB4SNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4sNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4sNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4svNV) = (PFNGLVERTEXATTRIB4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttrib4ubvNV) = (PFNGLVERTEXATTRIB4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttrib4ubvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttrib4ubvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs1dvNV) = (PFNGLVERTEXATTRIBS1DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs1dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs1fvNV) = (PFNGLVERTEXATTRIBS1FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs1fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs1svNV) = (PFNGLVERTEXATTRIBS1SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs1svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs1svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs2dvNV) = (PFNGLVERTEXATTRIBS2DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs2dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs2fvNV) = (PFNGLVERTEXATTRIBS2FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs2fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs2svNV) = (PFNGLVERTEXATTRIBS2SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs2svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs2svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs3dvNV) = (PFNGLVERTEXATTRIBS3DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs3dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs3fvNV) = (PFNGLVERTEXATTRIBS3FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs3fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs3svNV) = (PFNGLVERTEXATTRIBS3SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs3svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs3svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs4dvNV) = (PFNGLVERTEXATTRIBS4DVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4dvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs4dvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs4fvNV) = (PFNGLVERTEXATTRIBS4FVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4fvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs4fvNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs4svNV) = (PFNGLVERTEXATTRIBS4SVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4svNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs4svNV)) - return FALSE; - GLH_EXT_NAME(glVertexAttribs4ubvNV) = (PFNGLVERTEXATTRIBS4UBVNVPROC)GLH_EXT_GET_PROC_ADDRESS("glVertexAttribs4ubvNV"); - if (NULL == GLH_EXT_NAME(glVertexAttribs4ubvNV)) - return FALSE; -#endif - -#ifdef GL_SGIS_generate_mipmap - } else if (0 == strcmp(extension, "GL_SGIS_generate_mipmap")) { -#endif - -#ifdef GL_SGIS_texture_lod - } else if (0 == strcmp(extension, "GL_SGIS_texture_lod")) { -#endif - -#ifdef GL_SGIX_depth_texture - } else if (0 == strcmp(extension, "GL_SGIX_depth_texture")) { -#endif - -#ifdef GL_SGIX_shadow - } else if (0 == strcmp(extension, "GL_SGIX_shadow")) { -#endif - -#ifdef GL_VERSION_1_2 - } else if (0 == strcmp(extension, "GL_VERSION_1_2")) { - GLH_CORE_1_2_NAME(glBlendColor) = (PFNGLBLENDCOLORPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendColor"); - if (NULL == GLH_CORE_1_2_NAME(glBlendColor)) - return FALSE; - GLH_CORE_1_2_NAME(glBlendEquation) = (PFNGLBLENDEQUATIONPROC)GLH_EXT_GET_PROC_ADDRESS("glBlendEquation"); - if (NULL == GLH_CORE_1_2_NAME(glBlendEquation)) - return FALSE; - GLH_CORE_1_2_NAME(glDrawRangeElements) = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements"); - if (NULL == GLH_CORE_1_2_NAME(glDrawRangeElements)) - return FALSE; - GLH_CORE_1_2_NAME(glColorTable) = (PFNGLCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTable"); - if (NULL == GLH_CORE_1_2_NAME(glColorTable)) - return FALSE; - GLH_CORE_1_2_NAME(glColorTableParameterfv) = (PFNGLCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameterfv"); - if (NULL == GLH_CORE_1_2_NAME(glColorTableParameterfv)) - return FALSE; - GLH_CORE_1_2_NAME(glColorTableParameteriv) = (PFNGLCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glColorTableParameteriv"); - if (NULL == GLH_CORE_1_2_NAME(glColorTableParameteriv)) - return FALSE; - GLH_CORE_1_2_NAME(glCopyColorTable) = (PFNGLCOPYCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyColorTable"); - if (NULL == GLH_CORE_1_2_NAME(glCopyColorTable)) - return FALSE; - GLH_CORE_1_2_NAME(glGetColorTable) = (PFNGLGETCOLORTABLEPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTable"); - if (NULL == GLH_CORE_1_2_NAME(glGetColorTable)) - return FALSE; - GLH_CORE_1_2_NAME(glGetColorTableParameterfv) = (PFNGLGETCOLORTABLEPARAMETERFVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameterfv"); - if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameterfv)) - return FALSE; - GLH_CORE_1_2_NAME(glGetColorTableParameteriv) = (PFNGLGETCOLORTABLEPARAMETERIVPROC)GLH_EXT_GET_PROC_ADDRESS("glGetColorTableParameteriv"); - if (NULL == GLH_CORE_1_2_NAME(glGetColorTableParameteriv)) - return FALSE; - GLH_CORE_1_2_NAME(glTexImage3D) = (PFNGLTEXIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexImage3D"); - if (NULL == GLH_CORE_1_2_NAME(glTexImage3D)) - return FALSE; - GLH_CORE_1_2_NAME(glTexSubImage3D) = (PFNGLTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glTexSubImage3D"); - if (NULL == GLH_CORE_1_2_NAME(glTexSubImage3D)) - return FALSE; - GLH_CORE_1_2_NAME(glCopyTexSubImage3D) = (PFNGLCOPYTEXSUBIMAGE3DPROC)GLH_EXT_GET_PROC_ADDRESS("glCopyTexSubImage3D"); - if (NULL == GLH_CORE_1_2_NAME(glCopyTexSubImage3D)) - return FALSE; -#endif - -#ifdef GL_WIN_swap_hint - } else if (0 == strcmp(extension, "GL_WIN_swap_hint")) { - GLH_EXT_NAME(glAddSwapHintRectWIN) = (PFNGLADDSWAPHINTRECTWINPROC)GLH_EXT_GET_PROC_ADDRESS("glAddSwapHintRectWIN"); - if (NULL == GLH_EXT_NAME(glAddSwapHintRectWIN)) - return FALSE; -#endif - -#ifdef WGL_ARB_pbuffer - } else if (0 == strcmp(extension, "WGL_ARB_pbuffer")) { -# ifdef _WIN32 - GLH_EXT_NAME(wglCreatePbufferARB) = (PFNWGLCREATEPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglCreatePbufferARB"); - if (NULL == GLH_EXT_NAME(wglCreatePbufferARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglGetPbufferDCARB) = (PFNWGLGETPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPbufferDCARB"); - if (NULL == GLH_EXT_NAME(wglGetPbufferDCARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglReleasePbufferDCARB) = (PFNWGLRELEASEPBUFFERDCARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleasePbufferDCARB"); - if (NULL == GLH_EXT_NAME(wglReleasePbufferDCARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglDestroyPbufferARB) = (PFNWGLDESTROYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglDestroyPbufferARB"); - if (NULL == GLH_EXT_NAME(wglDestroyPbufferARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglQueryPbufferARB) = (PFNWGLQUERYPBUFFERARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglQueryPbufferARB"); - if (NULL == GLH_EXT_NAME(wglQueryPbufferARB)) - return FALSE; -# endif -#endif - -#ifdef WGL_ARB_render_texture -# ifdef _WIN32 - GLH_EXT_NAME(wglBindTexImageARB) = (PFNWGLBINDTEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglBindTexImageARB"); - if (NULL == GLH_EXT_NAME(wglBindTexImageARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglReleaseTexImageARB) = (PFNWGLRELEASETEXIMAGEARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglReleaseTexImageARB"); - if (NULL == GLH_EXT_NAME(wglReleaseTexImageARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglSetPbufferAttribARB) = (PFNWGLSETPBUFFERATTRIBARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglSetPbufferAttribARB"); - if (NULL == GLH_EXT_NAME(wglSetPbufferAttribARB)) - return FALSE; -# endif -#endif - -#ifdef WGL_ARB_pixel_format - } else if (0 == strcmp(extension, "WGL_ARB_pixel_format")) { -# ifdef _WIN32 - GLH_EXT_NAME(wglGetPixelFormatAttribivARB) = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribivARB"); - if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribivARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglGetPixelFormatAttribfvARB) = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglGetPixelFormatAttribfvARB"); - if (NULL == GLH_EXT_NAME(wglGetPixelFormatAttribfvARB)) - return FALSE; -# endif -# ifdef _WIN32 - GLH_EXT_NAME(wglChoosePixelFormatARB) = (PFNWGLCHOOSEPIXELFORMATARBPROC)GLH_EXT_GET_PROC_ADDRESS("wglChoosePixelFormatARB"); - if (NULL == GLH_EXT_NAME(wglChoosePixelFormatARB)) - return FALSE; -# endif -#endif - - } else { - return FALSE; - } - return TRUE; -} -#endif - -#else // defined(__APPLE__) - -#ifdef GLH_EXT_SINGLE_FILE - -int glh_init_extension(const char* extension) -{ - // MBW -- XXX -- Should this check for extension availability? - return TRUE; -} -#endif // GLH_EXT_SINGLE_FILE - -#endif // defined(__APPLE__) - -#undef GLH_EXT_SINGLE_FILE - -#endif /* GLH_GENEXT_H */ diff --git a/indra/llwindow/llopenglview-objc.mm b/indra/llwindow/llopenglview-objc.mm index f9b387b00b..fd20f2ad15 100644 --- a/indra/llwindow/llopenglview-objc.mm +++ b/indra/llwindow/llopenglview-objc.mm @@ -288,7 +288,8 @@ attributedStringInfo getSegments(NSAttributedString *str) if (vsync) { - [glContext setValues:(const GLint*)1 forParameter:NSOpenGLCPSwapInterval]; + GLint value = 1; + [glContext setValues:&value forParameter:NSOpenGLCPSwapInterval]; } else { // supress this error after move to Xcode 7: // error: null passed to a callee that requires a non-null argument [-Werror,-Wnonnull] diff --git a/indra/llwindow/llwindow.cpp b/indra/llwindow/llwindow.cpp index 30bc743e72..f4678a70c5 100644 --- a/indra/llwindow/llwindow.cpp +++ b/indra/llwindow/llwindow.cpp @@ -137,6 +137,12 @@ BOOL LLWindow::canDelete() return TRUE; } +//virtual +void LLWindow::setTitle(const std::string title) +{ + // the action happens in the platform specific impl +} + // virtual void LLWindow::incBusyCount() { @@ -397,7 +403,7 @@ LLWindow* LLWindowManager::createWindow( const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, + BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth, U32 fsaa_samples) @@ -409,26 +415,26 @@ LLWindow* LLWindowManager::createWindow( #if LL_MESA_HEADLESS new_window = new LLWindowMesaHeadless(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); #elif LL_SDL new_window = new LLWindowSDL(callbacks, title, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); #elif LL_WINDOWS new_window = new LLWindowWin32(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); #elif LL_DARWIN new_window = new LLWindowMacOSX(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth, fsaa_samples); #endif } else { new_window = new LLWindowHeadless(callbacks, title, name, x, y, width, height, flags, - fullscreen, clearBg, disable_vsync, use_gl, ignore_pixel_depth); + fullscreen, clearBg, enable_vsync, use_gl, ignore_pixel_depth); } if (FALSE == new_window->isValid()) diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index d4d5b76937..0edf39f6ef 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -77,15 +77,37 @@ public: BOOL setSize(LLCoordScreen size); BOOL setSize(LLCoordWindow size); virtual void setMinSize(U32 min_width, U32 min_height, bool enforce_immediately = true); - virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) = 0; - virtual BOOL setCursorPosition(LLCoordWindow position) = 0; + virtual BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) = 0; + + //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread + // returns a pointer to be handed back to destroySharedConext/makeContextCurrent + virtual void* createSharedContext() = 0; + //make the given context current on the current thread + virtual void makeContextCurrent(void* context) = 0; + //destroy the given context that was retrieved by createSharedContext() + //Must be called on the same thread that called createSharedContext() + virtual void destroySharedContext(void* context) = 0; + + virtual void toggleVSync(bool enable_vsync) = 0; + + virtual BOOL setCursorPosition(LLCoordWindow position) = 0; virtual BOOL getCursorPosition(LLCoordWindow *position) = 0; +#if LL_WINDOWS + virtual BOOL getCursorDelta(LLCoordCommon* delta) = 0; +#endif virtual void showCursor() = 0; virtual void hideCursor() = 0; virtual BOOL isCursorHidden() = 0; virtual void showCursorFromMouseMove() = 0; virtual void hideCursorUntilMouseMove() = 0; + // Provide a way to set the Viewer window title after the + // windows has been created. The initial use case for this + // is described in SL-16102 (update window title with agent + // name, location etc. for non-interactive viewer) but it + // may also be useful in other cases. + virtual void setTitle(const std::string title); + // These two functions create a way to make a busy cursor instead // of an arrow when someone's busy doing something. Draw an // arrow/hour if busycount > 0. @@ -274,7 +296,7 @@ public: U32 flags = 0, BOOL fullscreen = FALSE, BOOL clearBg = FALSE, - BOOL disable_vsync = TRUE, + BOOL enable_vsync = FALSE, BOOL use_gl = TRUE, BOOL ignore_pixel_depth = FALSE, U32 fsaa_samples = 0); diff --git a/indra/llwindow/llwindowheadless.cpp b/indra/llwindow/llwindowheadless.cpp index 70f473281b..c3738af6ca 100644 --- a/indra/llwindow/llwindowheadless.cpp +++ b/indra/llwindow/llwindowheadless.cpp @@ -35,7 +35,7 @@ // LLWindowHeadless::LLWindowHeadless(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clear_background, - BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth) + BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth) : LLWindow(callbacks, fullscreen, flags) { // Initialize a headless keyboard. diff --git a/indra/llwindow/llwindowheadless.h b/indra/llwindow/llwindowheadless.h index c692666df1..410da79623 100644 --- a/indra/llwindow/llwindowheadless.h +++ b/indra/llwindow/llwindowheadless.h @@ -48,9 +48,16 @@ public: /*virtual*/ BOOL setPosition(LLCoordScreen position) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordScreen size) {return FALSE;}; /*virtual*/ BOOL setSizeImpl(LLCoordWindow size) {return FALSE;}; - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;}; - /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; - /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) {return FALSE;}; + void* createSharedContext() { return nullptr; } + void makeContextCurrent(void*) {} + void destroySharedContext(void*) {} + /*virtual*/ void toggleVSync(bool enable_vsync) { } + /*virtual*/ BOOL setCursorPosition(LLCoordWindow position) {return FALSE;}; + /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position) {return FALSE;}; +#if LL_WINDOWS + /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta) { return FALSE; } +#endif /*virtual*/ void showCursor() {}; /*virtual*/ void hideCursor() {}; /*virtual*/ void showCursorFromMouseMove() {}; @@ -97,7 +104,7 @@ public: S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clear_background, - BOOL disable_vsync, BOOL use_gl, BOOL ignore_pixel_depth); + BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth); virtual ~LLWindowHeadless(); private: diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp index 24ce5131d5..bc4f07941b 100644 --- a/indra/llwindow/llwindowmacosx.cpp +++ b/indra/llwindow/llwindowmacosx.cpp @@ -111,7 +111,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, BOOL use_gl, + BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth, U32 fsaa_samples) : LLWindow(NULL, fullscreen, flags) @@ -165,7 +165,7 @@ LLWindowMacOSX::LLWindowMacOSX(LLWindowCallbacks* callbacks, // Stash an object pointer for OSMessageBox() gWindowImplementation = this; // Create the GL context and set it up for windowed or fullscreen, as appropriate. - if(createContext(x, y, width, height, 32, fullscreen, disable_vsync)) + if(createContext(x, y, width, height, 32, fullscreen, enable_vsync)) { if(mWindow != NULL) { @@ -619,7 +619,7 @@ void LLWindowMacOSX::getMouseDeltas(float* delta) delta[1] = mCursorLastEventDeltaY; } -BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync) +BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync) { BOOL glNeedsInit = FALSE; @@ -634,7 +634,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits { // Our OpenGL view is already defined within SecondLife.xib. // Get the view instead. - mGLView = createOpenGLView(mWindow, mFSAASamples, !disable_vsync); + mGLView = createOpenGLView(mWindow, mFSAASamples, enable_vsync); mContext = getCGLContextObj(mGLView); // Since we just created the context, it needs to be set up. @@ -661,17 +661,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits } // Disable vertical sync for swap - GLint frames_per_swap = 0; - if (disable_vsync) - { - frames_per_swap = 0; - } - else - { - frames_per_swap = 1; - } - - CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); + toggleVSync(enable_vsync); //enable multi-threaded OpenGL if (sUseMultGL) @@ -698,7 +688,7 @@ BOOL LLWindowMacOSX::createContext(int x, int y, int width, int height, int bits // We only support OS X 10.7's fullscreen app mode which is literally a full screen window that fills a virtual desktop. // This makes this method obsolete. -BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +BOOL LLWindowMacOSX::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp) { return FALSE; } @@ -1920,6 +1910,49 @@ void LLWindowMacOSX::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) allowDirectMarkedTextInput(b, mGLView); // mLanguageTextInputAllowed and mMarkedTextAllowed should be updated at once (by Pell Smit } +class sharedContext +{ +public: + CGLContextObj mContext; +}; + +void* LLWindowMacOSX::createSharedContext() +{ + sharedContext* sc = new sharedContext(); + CGLCreateContext(mPixelFormat, mContext, &(sc->mContext)); + + return (void *)sc; +} + +void LLWindowMacOSX::makeContextCurrent(void* context) +{ + CGLSetCurrentContext(((sharedContext*)context)->mContext); +} + +void LLWindowMacOSX::destroySharedContext(void* context) +{ + sharedContext* sc = (sharedContext*)context; + + CGLDestroyContext(sc->mContext); + + delete sc; +} + +void LLWindowMacOSX::toggleVSync(bool enable_vsync) +{ + GLint frames_per_swap = 0; + if (!enable_vsync) + { + frames_per_swap = 0; + } + else + { + frames_per_swap = 1; + } + + CGLSetParameter(mContext, kCGLCPSwapInterval, &frames_per_swap); +} + void LLWindowMacOSX::interruptLanguageTextInput() { commitCurrentPreedit(mGLView); diff --git a/indra/llwindow/llwindowmacosx.h b/indra/llwindow/llwindowmacosx.h index bf45238c8d..b0f339e1db 100644 --- a/indra/llwindow/llwindowmacosx.h +++ b/indra/llwindow/llwindowmacosx.h @@ -41,85 +41,84 @@ #undef verify #undef require - class LLWindowMacOSX : public LLWindow { public: - /*virtual*/ void show(); - /*virtual*/ void hide(); - /*virtual*/ void close(); - /*virtual*/ BOOL getVisible(); - /*virtual*/ BOOL getMinimized(); - /*virtual*/ BOOL getMaximized(); - /*virtual*/ BOOL maximize(); - /*virtual*/ void minimize(); - /*virtual*/ void restore(); - /*virtual*/ BOOL getFullscreen(); - /*virtual*/ BOOL getPosition(LLCoordScreen *position); - /*virtual*/ BOOL getSize(LLCoordScreen *size); - /*virtual*/ BOOL getSize(LLCoordWindow *size); - /*virtual*/ BOOL setPosition(LLCoordScreen position); - /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); - /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); - /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); - /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); - /*virtual*/ void showCursor(); - /*virtual*/ void hideCursor(); - /*virtual*/ void showCursorFromMouseMove(); - /*virtual*/ void hideCursorUntilMouseMove(); - /*virtual*/ BOOL isCursorHidden(); - /*virtual*/ void updateCursor(); - /*virtual*/ ECursorType getCursor() const; - /*virtual*/ void captureMouse(); - /*virtual*/ void releaseMouse(); - /*virtual*/ void setMouseClipping( BOOL b ); - /*virtual*/ BOOL isClipboardTextAvailable(); - /*virtual*/ BOOL pasteTextFromClipboard(LLWString &dst); - /*virtual*/ BOOL copyTextToClipboard(const LLWString & src); - /*virtual*/ void flashIcon(F32 seconds); - /*virtual*/ F32 getGamma(); - /*virtual*/ BOOL setGamma(const F32 gamma); // Set the gamma - /*virtual*/ U32 getFSAASamples(); - /*virtual*/ void setFSAASamples(const U32 fsaa_samples); - /*virtual*/ BOOL restoreGamma(); // Restore original gamma table (before updating gamma) - /*virtual*/ ESwapMethod getSwapMethod() { return mSwapMethod; } - /*virtual*/ void gatherInput(); - /*virtual*/ void delayInputProcessing() {}; - /*virtual*/ void swapBuffers(); + void show() override; + void hide() override; + void close() override; + BOOL getVisible() override; + BOOL getMinimized() override; + BOOL getMaximized() override; + BOOL maximize() override; + void minimize() override; + void restore() override; + BOOL getFullscreen(); + BOOL getPosition(LLCoordScreen *position) override; + BOOL getSize(LLCoordScreen *size) override; + BOOL getSize(LLCoordWindow *size) override; + BOOL setPosition(LLCoordScreen position) override; + BOOL setSizeImpl(LLCoordScreen size) override; + BOOL setSizeImpl(LLCoordWindow size) override; + BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL) override; + BOOL setCursorPosition(LLCoordWindow position) override; + BOOL getCursorPosition(LLCoordWindow *position) override; + void showCursor() override; + void hideCursor() override; + void showCursorFromMouseMove() override; + void hideCursorUntilMouseMove() override; + BOOL isCursorHidden() override; + void updateCursor() override; + ECursorType getCursor() const override; + void captureMouse() override; + void releaseMouse() override; + void setMouseClipping( BOOL b ) override; + BOOL isClipboardTextAvailable() override; + BOOL pasteTextFromClipboard(LLWString &dst) override; + BOOL copyTextToClipboard(const LLWString & src) override; + void flashIcon(F32 seconds) override; + F32 getGamma() override; + BOOL setGamma(const F32 gamma) override; // Set the gamma + U32 getFSAASamples() override; + void setFSAASamples(const U32 fsaa_samples) override; + BOOL restoreGamma() override; // Restore original gamma table (before updating gamma) + ESwapMethod getSwapMethod() override { return mSwapMethod; } + void gatherInput() override; + void delayInputProcessing() override {}; + void swapBuffers() override; // handy coordinate space conversion routines - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to); - /*virtual*/ BOOL convertCoords(LLCoordWindow from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordWindow *to); - /*virtual*/ BOOL convertCoords(LLCoordScreen from, LLCoordGL *to); - /*virtual*/ BOOL convertCoords(LLCoordGL from, LLCoordScreen *to); + BOOL convertCoords(LLCoordScreen from, LLCoordWindow *to) override; + BOOL convertCoords(LLCoordWindow from, LLCoordScreen *to) override; + BOOL convertCoords(LLCoordWindow from, LLCoordGL *to) override; + BOOL convertCoords(LLCoordGL from, LLCoordWindow *to) override; + BOOL convertCoords(LLCoordScreen from, LLCoordGL *to) override; + BOOL convertCoords(LLCoordGL from, LLCoordScreen *to) override; - /*virtual*/ LLWindowResolution* getSupportedResolutions(S32 &num_resolutions); - /*virtual*/ F32 getNativeAspectRatio(); - /*virtual*/ F32 getPixelAspectRatio(); - /*virtual*/ void setNativeAspectRatio(F32 ratio) { mOverrideAspectRatio = ratio; } + LLWindowResolution* getSupportedResolutions(S32 &num_resolutions) override; + F32 getNativeAspectRatio() override; + F32 getPixelAspectRatio() override; + void setNativeAspectRatio(F32 ratio) override { mOverrideAspectRatio = ratio; } - /*virtual*/ void beforeDialog(); - /*virtual*/ void afterDialog(); + void beforeDialog() override; + void afterDialog() override; - /*virtual*/ BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b); + BOOL dialogColorPicker(F32 *r, F32 *g, F32 *b) override; - /*virtual*/ void *getPlatformWindow(); - /*virtual*/ void bringToFront() {}; + void *getPlatformWindow() override; + void bringToFront() override {}; - /*virtual*/ void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b); - /*virtual*/ void interruptLanguageTextInput(); - /*virtual*/ void spawnWebBrowser(const std::string& escaped_url, bool async); - /*virtual*/ F32 getSystemUISize(); + void allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) override; + void interruptLanguageTextInput() override; + void spawnWebBrowser(const std::string& escaped_url, bool async) override; + F32 getSystemUISize() override; static std::vector<std::string> getDisplaysResolutionList(); static std::vector<std::string> getDynamicFallbackFontList(); // Provide native key event data - /*virtual*/ LLSD getNativeKeyData(); + LLSD getNativeKeyData() override; void* getWindow() { return mWindow; } LLWindowCallbacks* getCallbacks() { return mCallbacks; } @@ -132,16 +131,27 @@ public: bool allowsLanguageInput() { return mLanguageTextInputAllowed; } + //create a new GL context that shares a namespace with this Window's main GL context and make it current on the current thread + // returns a pointer to be handed back to destroySharedConext/makeContextCurrent + void* createSharedContext() override; + //make the given context current on the current thread + void makeContextCurrent(void* context) override; + //destroy the given context that was retrieved by createSharedContext() + //Must be called on the same thread that called createSharedContext() + void destroySharedContext(void* context) override; + + void toggleVSync(bool enable_vsync) override; + protected: LLWindowMacOSX(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, + BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowMacOSX(); void initCursors(); - BOOL isValid(); + BOOL isValid() override; void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); @@ -157,7 +167,7 @@ protected: BOOL shouldPostQuit() { return mPostQuit; } //Satisfy MAINT-3135 and MAINT-3288 with a flag. - /*virtual */ void setOldResize(bool oldresize) {setResizeMode(oldresize, mGLView); } + /*virtual */ void setOldResize(bool oldresize) override {setResizeMode(oldresize, mGLView); } private: void restoreGLContext(); @@ -168,7 +178,7 @@ protected: // // create or re-create the GL context/window. Called from the constructor and switchContext(). - BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL disable_vsync); + BOOL createContext(int x, int y, int width, int height, int bits, BOOL fullscreen, BOOL enable_vsync); void destroyContext(); void setupFailure(const std::string& text, const std::string& caption, U32 type); void adjustCursorDecouple(bool warpingMouse = false); @@ -231,9 +241,9 @@ public: LLSplashScreenMacOSX(); virtual ~LLSplashScreenMacOSX(); - /*virtual*/ void showImpl(); - /*virtual*/ void updateImpl(const std::string& mesg); - /*virtual*/ void hideImpl(); + void showImpl(); + void updateImpl(const std::string& mesg); + void hideImpl(); private: WindowRef mWindow; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index a32346bfd3..33b4257706 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -45,6 +45,8 @@ #include "lldir.h" #include "llsdutil.h" #include "llglslshader.h" +#include "llthreadsafequeue.h" +#include "stringize.h" // System includes #include <commdlg.h> @@ -54,6 +56,10 @@ #include <shellapi.h> #include <fstream> #include <Imm.h> +#include <iomanip> +#include <future> +#include <sstream> +#include <utility> // std::pair // Require DirectInput version 8 #define DIRECTINPUT_VERSION 0x0800 @@ -77,8 +83,24 @@ const F32 ICON_FLASH_TIME = 0.5f; #define USER_DEFAULT_SCREEN_DPI 96 // Win7 #endif +// Claim a couple unused GetMessage() message IDs +const UINT WM_DUMMY_(WM_USER + 0x0017); +const UINT WM_POST_FUNCTION_(WM_USER + 0x0018); + extern BOOL gDebugWindowProc; +static std::thread::id sWindowThreadId; +static std::thread::id sMainThreadId; + +#if 1 // flip to zero to enable assertions for functions being called from wrong thread +#define ASSERT_MAIN_THREAD() +#define ASSERT_WINDOW_THREAD() +#else +#define ASSERT_MAIN_THREAD() llassert(LLThread::currentID() == sMainThreadId) +#define ASSERT_WINDOW_THREAD() llassert(LLThread::currentID() == sWindowThreadId) +#endif + + LPWSTR gIconResource = IDI_APPLICATION; LPDIRECTINPUT8 gDirectInput8; @@ -161,23 +183,19 @@ DWORD LLWindowWin32::sWinIMESentenceMode = IME_SMODE_AUTOMATIC; LLCoordWindow LLWindowWin32::sWinIMEWindowPosition(-1,-1); // The following class LLWinImm delegates Windows IMM APIs. -// We need this because some language versions of Windows, -// e.g., US version of Windows XP, doesn't install IMM32.DLL -// as a default, and we can't link against imm32.lib statically. -// I believe DLL loading of this type is best suited to do -// in a static initialization of a class. What I'm not sure is -// whether it follows the Linden Conding Standard... -// See http://wiki.secondlife.com/wiki/Coding_standards#Static_Members +// It was originally introduced to support US Windows XP, on which we needed +// to dynamically load IMM32.DLL and use GetProcAddress to resolve its entry +// points. Now that that's moot, we retain this wrapper only for hooks for +// metrics. class LLWinImm { public: - static bool isAvailable() { return sTheInstance.mHImmDll != NULL; } + static bool isAvailable() { return true; } public: // Wrappers for IMM API. static BOOL isIME(HKL hkl); - static HWND getDefaultIMEWnd(HWND hwnd); static HIMC getContext(HWND hwnd); static BOOL releaseContext(HWND hwnd, HIMC himc); static BOOL getOpenStatus(HIMC himc); @@ -191,236 +209,96 @@ public: static BOOL setCompositionFont(HIMC himc, LPLOGFONTW logfont); static BOOL setCandidateWindow(HIMC himc, LPCANDIDATEFORM candidate_form); static BOOL notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value); - -private: - LLWinImm(); - ~LLWinImm(); - -private: - // Pointers to IMM API. - BOOL (WINAPI *mImmIsIME)(HKL); - HWND (WINAPI *mImmGetDefaultIMEWnd)(HWND); - HIMC (WINAPI *mImmGetContext)(HWND); - BOOL (WINAPI *mImmReleaseContext)(HWND, HIMC); - BOOL (WINAPI *mImmGetOpenStatus)(HIMC); - BOOL (WINAPI *mImmSetOpenStatus)(HIMC, BOOL); - BOOL (WINAPI *mImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD); - BOOL (WINAPI *mImmSetConversionStatus)(HIMC, DWORD, DWORD); - BOOL (WINAPI *mImmGetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); - BOOL (WINAPI *mImmSetCompostitionWindow)(HIMC, LPCOMPOSITIONFORM); - LONG (WINAPI *mImmGetCompositionString)(HIMC, DWORD, LPVOID, DWORD); - BOOL (WINAPI *mImmSetCompositionString)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD); - BOOL (WINAPI *mImmSetCompositionFont)(HIMC, LPLOGFONTW); - BOOL (WINAPI *mImmSetCandidateWindow)(HIMC, LPCANDIDATEFORM); - BOOL (WINAPI *mImmNotifyIME)(HIMC, DWORD, DWORD, DWORD); - -private: - HMODULE mHImmDll; - static LLWinImm sTheInstance; }; -LLWinImm LLWinImm::sTheInstance; - -LLWinImm::LLWinImm() : mHImmDll(NULL) -{ - // Check system metrics - if ( !GetSystemMetrics( SM_IMMENABLED ) ) - return; - - mHImmDll = LoadLibraryA("Imm32"); - if (mHImmDll != NULL) - { - mImmIsIME = (BOOL (WINAPI *)(HKL)) GetProcAddress(mHImmDll, "ImmIsIME"); - mImmGetDefaultIMEWnd = (HWND (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetDefaultIMEWnd"); - mImmGetContext = (HIMC (WINAPI *)(HWND)) GetProcAddress(mHImmDll, "ImmGetContext"); - mImmReleaseContext = (BOOL (WINAPI *)(HWND, HIMC)) GetProcAddress(mHImmDll, "ImmReleaseContext"); - mImmGetOpenStatus = (BOOL (WINAPI *)(HIMC)) GetProcAddress(mHImmDll, "ImmGetOpenStatus"); - mImmSetOpenStatus = (BOOL (WINAPI *)(HIMC, BOOL)) GetProcAddress(mHImmDll, "ImmSetOpenStatus"); - mImmGetConversionStatus = (BOOL (WINAPI *)(HIMC, LPDWORD, LPDWORD)) GetProcAddress(mHImmDll, "ImmGetConversionStatus"); - mImmSetConversionStatus = (BOOL (WINAPI *)(HIMC, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmSetConversionStatus"); - mImmGetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmGetCompositionWindow"); - mImmSetCompostitionWindow = (BOOL (WINAPI *)(HIMC, LPCOMPOSITIONFORM)) GetProcAddress(mHImmDll, "ImmSetCompositionWindow"); - mImmGetCompositionString= (LONG (WINAPI *)(HIMC, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmGetCompositionStringW"); - mImmSetCompositionString= (BOOL (WINAPI *)(HIMC, DWORD, LPVOID, DWORD, LPVOID, DWORD)) GetProcAddress(mHImmDll, "ImmSetCompositionStringW"); - mImmSetCompositionFont = (BOOL (WINAPI *)(HIMC, LPLOGFONTW)) GetProcAddress(mHImmDll, "ImmSetCompositionFontW"); - mImmSetCandidateWindow = (BOOL (WINAPI *)(HIMC, LPCANDIDATEFORM)) GetProcAddress(mHImmDll, "ImmSetCandidateWindow"); - mImmNotifyIME = (BOOL (WINAPI *)(HIMC, DWORD, DWORD, DWORD)) GetProcAddress(mHImmDll, "ImmNotifyIME"); - - if (mImmIsIME == NULL || - mImmGetDefaultIMEWnd == NULL || - mImmGetContext == NULL || - mImmReleaseContext == NULL || - mImmGetOpenStatus == NULL || - mImmSetOpenStatus == NULL || - mImmGetConversionStatus == NULL || - mImmSetConversionStatus == NULL || - mImmGetCompostitionWindow == NULL || - mImmSetCompostitionWindow == NULL || - mImmGetCompositionString == NULL || - mImmSetCompositionString == NULL || - mImmSetCompositionFont == NULL || - mImmSetCandidateWindow == NULL || - mImmNotifyIME == NULL) - { - // If any of the above API entires are not found, we can't use IMM API. - // So, turn off the IMM support. We should log some warning message in - // the case, since it is very unusual; these APIs are available from - // the beginning, and all versions of IMM32.DLL should have them all. - // Unfortunately, this code may be executed before initialization of - // the logging channel (LL_WARNS()), and we can't do it here... Yes, this - // is one of disadvantages to use static constraction to DLL loading. - FreeLibrary(mHImmDll); - mHImmDll = NULL; - - // If we unload the library, make sure all the function pointers are cleared - mImmIsIME = NULL; - mImmGetDefaultIMEWnd = NULL; - mImmGetContext = NULL; - mImmReleaseContext = NULL; - mImmGetOpenStatus = NULL; - mImmSetOpenStatus = NULL; - mImmGetConversionStatus = NULL; - mImmSetConversionStatus = NULL; - mImmGetCompostitionWindow = NULL; - mImmSetCompostitionWindow = NULL; - mImmGetCompositionString = NULL; - mImmSetCompositionString = NULL; - mImmSetCompositionFont = NULL; - mImmSetCandidateWindow = NULL; - mImmNotifyIME = NULL; - } - } -} - - // static -BOOL LLWinImm::isIME(HKL hkl) +BOOL LLWinImm::isIME(HKL hkl) { - if ( sTheInstance.mImmIsIME ) - return sTheInstance.mImmIsIME(hkl); - return FALSE; + return ImmIsIME(hkl); } // static HIMC LLWinImm::getContext(HWND hwnd) { - if ( sTheInstance.mImmGetContext ) - return sTheInstance.mImmGetContext(hwnd); - return 0; + return ImmGetContext(hwnd); } //static BOOL LLWinImm::releaseContext(HWND hwnd, HIMC himc) { - if ( sTheInstance.mImmIsIME ) - return sTheInstance.mImmReleaseContext(hwnd, himc); - return FALSE; + return ImmReleaseContext(hwnd, himc); } // static BOOL LLWinImm::getOpenStatus(HIMC himc) { - if ( sTheInstance.mImmGetOpenStatus ) - return sTheInstance.mImmGetOpenStatus(himc); - return FALSE; + return ImmGetOpenStatus(himc); } // static -BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) +BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) { - if ( sTheInstance.mImmSetOpenStatus ) - return sTheInstance.mImmSetOpenStatus(himc, status); - return FALSE; + return ImmSetOpenStatus(himc, status); } // static BOOL LLWinImm::getConversionStatus(HIMC himc, LPDWORD conversion, LPDWORD sentence) { - if ( sTheInstance.mImmGetConversionStatus ) - return sTheInstance.mImmGetConversionStatus(himc, conversion, sentence); - return FALSE; + return ImmGetConversionStatus(himc, conversion, sentence); } // static BOOL LLWinImm::setConversionStatus(HIMC himc, DWORD conversion, DWORD sentence) { - if ( sTheInstance.mImmSetConversionStatus ) - return sTheInstance.mImmSetConversionStatus(himc, conversion, sentence); - return FALSE; + return ImmSetConversionStatus(himc, conversion, sentence); } // static BOOL LLWinImm::getCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) { - if ( sTheInstance.mImmGetCompostitionWindow ) - return sTheInstance.mImmGetCompostitionWindow(himc, form); - return FALSE; + return ImmGetCompositionWindow(himc, form); } // static BOOL LLWinImm::setCompositionWindow(HIMC himc, LPCOMPOSITIONFORM form) { - if ( sTheInstance.mImmSetCompostitionWindow ) - return sTheInstance.mImmSetCompostitionWindow(himc, form); - return FALSE; + return ImmSetCompositionWindow(himc, form); } // static LONG LLWinImm::getCompositionString(HIMC himc, DWORD index, LPVOID data, DWORD length) { - if ( sTheInstance.mImmGetCompositionString ) - return sTheInstance.mImmGetCompositionString(himc, index, data, length); - return FALSE; + return ImmGetCompositionString(himc, index, data, length); } // static BOOL LLWinImm::setCompositionString(HIMC himc, DWORD index, LPVOID pComp, DWORD compLength, LPVOID pRead, DWORD readLength) { - if ( sTheInstance.mImmSetCompositionString ) - return sTheInstance.mImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); - return FALSE; + return ImmSetCompositionString(himc, index, pComp, compLength, pRead, readLength); } // static BOOL LLWinImm::setCompositionFont(HIMC himc, LPLOGFONTW pFont) { - if ( sTheInstance.mImmSetCompositionFont ) - return sTheInstance.mImmSetCompositionFont(himc, pFont); - return FALSE; + return ImmSetCompositionFont(himc, pFont); } // static BOOL LLWinImm::setCandidateWindow(HIMC himc, LPCANDIDATEFORM form) { - if ( sTheInstance.mImmSetCandidateWindow ) - return sTheInstance.mImmSetCandidateWindow(himc, form); - return FALSE; + return ImmSetCandidateWindow(himc, form); } // static BOOL LLWinImm::notifyIME(HIMC himc, DWORD action, DWORD index, DWORD value) { - if ( sTheInstance.mImmNotifyIME ) - return sTheInstance.mImmNotifyIME(himc, action, index, value); - return FALSE; + return ImmNotifyIME(himc, action, index, value); } - -// ---------------------------------------------------------------------------------------- -LLWinImm::~LLWinImm() -{ - if (mHImmDll != NULL) - { - FreeLibrary(mHImmDll); - mHImmDll = NULL; - } -} - - class LLMonitorInfo { public: @@ -454,16 +332,83 @@ private: static LLMonitorInfo sMonitorInfo; + +// Thread that owns the Window Handle +// This whole struct is private to LLWindowWin32, which needs to mess with its +// members, which is why it's a struct rather than a class. In effect, we make +// the containing class a friend. +struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool +{ + static const int MAX_QUEUE_SIZE = 2048; + + LLThreadSafeQueue<MSG> mMessageQueue; + + LLWindowWin32Thread(); + + void run() override; + + /// called by main thread to post work to this window thread + template <typename CALLABLE> + void post(CALLABLE&& func) + { + try + { + getQueue().post(std::forward<CALLABLE>(func)); + } + catch (const LLThreadSafeQueueInterrupt&) + { + // Shutdown timing is tricky. The main thread can end up trying + // to post a cursor position after having closed the WorkQueue. + } + } + + /** + * Like post(), Post() is a way of conveying a single work item to this + * thread. Its virtue is that it will definitely be executed "soon" rather + * than potentially waiting for the next frame: it uses PostMessage() to + * break us out of the window thread's blocked GetMessage() call. It's + * more expensive, though, not only from the Windows API latency of + * PostMessage() and GetMessage(), but also because it involves heap + * allocation and release. + * + * Require HWND from caller, even though we store an HWND locally. + * Otherwise, if our mWindowHandle was accessed from both threads, we'd + * have to protect it with a mutex. + */ + template <typename CALLABLE> + void Post(HWND windowHandle, CALLABLE&& func) + { + // Move func to the heap. If we knew FuncType could fit into LPARAM, + // we could simply instantiate FuncType and pass it by value. But + // since we don't, we must put that on the heap as well as the + // internal heap allocation it likely requires to store func. + auto ptr = new FuncType(std::move(func)); + WPARAM wparam{ 0xF1C }; + LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle + << ", " << WM_POST_FUNCTION_ + << ", " << wparam << std::dec << LL_ENDL; + PostMessage(windowHandle, WM_POST_FUNCTION_, wparam, LPARAM(ptr)); + } + + using FuncType = std::function<void()>; + // call GetMessage() and pull enqueue messages for later processing + void gatherInput(); + HWND mWindowHandle = NULL; + HDC mhDC = 0; +}; + + LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, BOOL fullscreen, BOOL clearBg, - BOOL disable_vsync, BOOL use_gl, + BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags) { - + sMainThreadId = LLThread::currentID(); + mWindowThread = new LLWindowWin32Thread(); //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways LoadLibrary(L"opengl32.dll"); @@ -471,7 +416,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mIconResource = gIconResource; mOverrideAspectRatio = 0.f; mNativeAspectRatio = 0.f; - mMousePositionModified = FALSE; mInputProcessingPaused = FALSE; mPreeditor = NULL; mKeyCharCode = 0; @@ -483,6 +427,9 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, memset(mPrevGammaRamp, 0, sizeof(mPrevGammaRamp)); mCustomGammaSet = FALSE; mWindowHandle = NULL; + + mRect = {0, 0, 0, 0}; + mClientRect = {0, 0, 0, 0}; if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &mMouseVanish, 0)) { @@ -535,7 +482,6 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Make an instance of our window then define the window class mhInstance = GetModuleHandle(NULL); - mWndProc = NULL; // Init Direct Input - needed for joystick / Spacemouse @@ -784,7 +730,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, LLCoordScreen windowPos(x,y); LLCoordScreen windowSize(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top); - if (!switchContext(mFullscreen, windowSize, TRUE, &windowPos)) + if (!switchContext(mFullscreen, windowSize, enable_vsync, &windowPos)) { return; } @@ -793,6 +739,13 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, initCursors(); setCursor( UI_CURSOR_ARROW ); + mRawMouse.usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + mRawMouse.usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE + mRawMouse.dwFlags = 0; // adds mouse and also ignores legacy mouse messages + mRawMouse.hwndTarget = 0; + + RegisterRawInputDevices(&mRawMouse, 1, sizeof(mRawMouse)); + // Initialize (boot strap) the Language text input management, // based on the system's (or user's) default settings. allowLanguageTextInput(NULL, FALSE); @@ -811,6 +764,8 @@ LLWindowWin32::~LLWindowWin32() delete [] mWindowClassName; mWindowClassName = NULL; + + delete mWindowThread; } void LLWindowWin32::show() @@ -850,7 +805,7 @@ void LLWindowWin32::restore() // I'm turning off optimizations for this part to be sure code executes as intended // (it is a straw, but I have no idea why else __try can get overruled) #pragma optimize("", off) -bool destroy_window_handler(HWND &hWnd) +bool destroy_window_handler(HWND hWnd) { bool res; __try @@ -930,26 +885,33 @@ void LLWindowWin32::close() LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; - if (IsWindow(mWindowHandle)) - { - // Make sure we don't leave a blank toolbar button. - ShowWindow(mWindowHandle, SW_HIDE); - - // This causes WM_DESTROY to be sent *immediately* - if (!destroy_window_handler(mWindowHandle)) + mWindowThread->post([=]() { - OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), - mCallbacks->translateString("MBShutdownErr"), - OSMB_OK); - } - } - else - { - // Something killed the window while we were busy destroying gl or handle somehow got broken - LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; - } + if (IsWindow(mWindowHandle)) + { + // Make sure we don't leave a blank toolbar button. + ShowWindow(mWindowHandle, SW_HIDE); + + // This causes WM_DESTROY to be sent *immediately* + if (!destroy_window_handler(mWindowHandle)) + { + OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"), + mCallbacks->translateString("MBShutdownErr"), + OSMB_OK); + } + } + else + { + // Something killed the window while we were busy destroying gl or handle somehow got broken + LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL; + } - mWindowHandle = NULL; + }); + // Even though the above lambda might not yet have run, we've already + // bound mWindowHandle into it by value, which should suffice for the + // operations we're asking. That's the last time WE should touch it. + mWindowHandle = NULL; + mWindowThread->close(); } BOOL LLWindowWin32::isValid() @@ -996,49 +958,22 @@ BOOL LLWindowWin32::getFullscreen() BOOL LLWindowWin32::getPosition(LLCoordScreen *position) { - RECT window_rect; - - if (!mWindowHandle || - !GetWindowRect(mWindowHandle, &window_rect) || - NULL == position) - { - return FALSE; - } - - position->mX = window_rect.left; - position->mY = window_rect.top; + position->mX = mRect.left; + position->mY = mRect.top; return TRUE; } BOOL LLWindowWin32::getSize(LLCoordScreen *size) { - RECT window_rect; - - if (!mWindowHandle || - !GetWindowRect(mWindowHandle, &window_rect) || - NULL == size) - { - return FALSE; - } - - size->mX = window_rect.right - window_rect.left; - size->mY = window_rect.bottom - window_rect.top; + size->mX = mRect.right - mRect.left; + size->mY = mRect.bottom - mRect.top; return TRUE; } BOOL LLWindowWin32::getSize(LLCoordWindow *size) { - RECT client_rect; - - if (!mWindowHandle || - !GetClientRect(mWindowHandle, &client_rect) || - NULL == size) - { - return FALSE; - } - - size->mX = client_rect.right - client_rect.left; - size->mY = client_rect.bottom - client_rect.top; + size->mX = mClientRect.right - mClientRect.left; + size->mY = mClientRect.bottom - mClientRect.top; return TRUE; } @@ -1065,14 +1000,17 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordScreen size) return FALSE; } - WINDOWPLACEMENT placement; - placement.length = sizeof(WINDOWPLACEMENT); - - if (!GetWindowPlacement(mWindowHandle, &placement)) return FALSE; - - placement.showCmd = SW_RESTORE; + mWindowThread->post([=]() + { + WINDOWPLACEMENT placement; + placement.length = sizeof(WINDOWPLACEMENT); - if (!SetWindowPlacement(mWindowHandle, &placement)) return FALSE; + if (GetWindowPlacement(mWindowHandle, &placement)) + { + placement.showCmd = SW_RESTORE; + SetWindowPlacement(mWindowHandle, &placement); + } + }); moveWindow(position, size); return TRUE; @@ -1084,177 +1022,165 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size) DWORD dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; DWORD dw_style = WS_OVERLAPPEDWINDOW; - AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); + AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); return setSizeImpl(LLCoordScreen(window_rect.right - window_rect.left, window_rect.bottom - window_rect.top)); } // changing fullscreen resolution -BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp) +BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen& size, BOOL enable_vsync, const LLCoordScreen* const posp) { - GLuint pixel_format; - DEVMODE dev_mode; - ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); - dev_mode.dmSize = sizeof(DEVMODE); - DWORD current_refresh; - DWORD dw_ex_style; - DWORD dw_style; - RECT window_rect = {0, 0, 0, 0}; - S32 width = size.mX; - S32 height = size.mY; - BOOL auto_show = FALSE; - - if (mhRC) - { - auto_show = TRUE; - resetDisplayResolution(); - } - - if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) - { - current_refresh = dev_mode.dmDisplayFrequency; - } - else - { - current_refresh = 60; - } - - gGLManager.shutdownGL(); - //destroy gl context - if (mhRC) - { - if (!wglMakeCurrent(NULL, NULL)) - { - LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; - } + //called from main thread + GLuint pixel_format; + DEVMODE dev_mode; + ::ZeroMemory(&dev_mode, sizeof(DEVMODE)); + dev_mode.dmSize = sizeof(DEVMODE); + DWORD current_refresh; + DWORD dw_ex_style; + DWORD dw_style; + RECT window_rect = { 0, 0, 0, 0 }; + S32 width = size.mX; + S32 height = size.mY; + BOOL auto_show = FALSE; + + if (mhRC) + { + auto_show = TRUE; + resetDisplayResolution(); + } - if (!wglDeleteContext(mhRC)) - { - LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; - } + if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode)) + { + current_refresh = dev_mode.dmDisplayFrequency; + } + else + { + current_refresh = 60; + } - mhRC = NULL; - } + gGLManager.shutdownGL(); + //destroy gl context + if (mhRC) + { + if (!wglMakeCurrent(NULL, NULL)) + { + LL_WARNS("Window") << "Release of DC and RC failed" << LL_ENDL; + } - if (fullscreen) - { - mFullscreen = TRUE; - BOOL success = FALSE; - DWORD closest_refresh = 0; + if (!wglDeleteContext(mhRC)) + { + LL_WARNS("Window") << "Release of rendering context failed" << LL_ENDL; + } - for (S32 mode_num = 0;; mode_num++) - { - if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) - { - break; - } + mhRC = NULL; + } - if (dev_mode.dmPelsWidth == width && - dev_mode.dmPelsHeight == height && - dev_mode.dmBitsPerPel == BITS_PER_PIXEL) - { - success = TRUE; - if ((dev_mode.dmDisplayFrequency - current_refresh) - < (closest_refresh - current_refresh)) - { - closest_refresh = dev_mode.dmDisplayFrequency; - } - } - } + if (fullscreen) + { + mFullscreen = TRUE; + BOOL success = FALSE; + DWORD closest_refresh = 0; - if (closest_refresh == 0) - { - LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; - return FALSE; - } + for (S32 mode_num = 0;; mode_num++) + { + if (!EnumDisplaySettings(NULL, mode_num, &dev_mode)) + { + break; + } - // If we found a good resolution, use it. - if (success) - { - success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); - } + if (dev_mode.dmPelsWidth == width && + dev_mode.dmPelsHeight == height && + dev_mode.dmBitsPerPel == BITS_PER_PIXEL) + { + success = TRUE; + if ((dev_mode.dmDisplayFrequency - current_refresh) + < (closest_refresh - current_refresh)) + { + closest_refresh = dev_mode.dmDisplayFrequency; + } + } + } - // Keep a copy of the actual current device mode in case we minimize - // and change the screen resolution. JC - EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); + if (closest_refresh == 0) + { + LL_WARNS("Window") << "Couldn't find display mode " << width << " by " << height << " at " << BITS_PER_PIXEL << " bits per pixel" << LL_ENDL; + return FALSE; + } - if (success) - { - mFullscreen = TRUE; - mFullscreenWidth = dev_mode.dmPelsWidth; - mFullscreenHeight = dev_mode.dmPelsHeight; - mFullscreenBits = dev_mode.dmBitsPerPel; - mFullscreenRefresh = dev_mode.dmDisplayFrequency; + // If we found a good resolution, use it. + if (success) + { + success = setDisplayResolution(width, height, BITS_PER_PIXEL, closest_refresh); + } - LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth - << "x" << dev_mode.dmPelsHeight - << "x" << dev_mode.dmBitsPerPel - << " @ " << dev_mode.dmDisplayFrequency - << LL_ENDL; + // Keep a copy of the actual current device mode in case we minimize + // and change the screen resolution. JC + EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dev_mode); - window_rect.left = (long) 0; - window_rect.right = (long) width; // Windows GDI rects don't include rightmost pixel - window_rect.top = (long) 0; - window_rect.bottom = (long) height; - dw_ex_style = WS_EX_APPWINDOW; - dw_style = WS_POPUP; + if (success) + { + mFullscreen = TRUE; + mFullscreenWidth = dev_mode.dmPelsWidth; + mFullscreenHeight = dev_mode.dmPelsHeight; + mFullscreenBits = dev_mode.dmBitsPerPel; + mFullscreenRefresh = dev_mode.dmDisplayFrequency; + + LL_INFOS("Window") << "Running at " << dev_mode.dmPelsWidth + << "x" << dev_mode.dmPelsHeight + << "x" << dev_mode.dmBitsPerPel + << " @ " << dev_mode.dmDisplayFrequency + << LL_ENDL; + + window_rect.left = (long)0; + window_rect.right = (long)width; // Windows GDI rects don't include rightmost pixel + window_rect.top = (long)0; + window_rect.bottom = (long)height; + dw_ex_style = WS_EX_APPWINDOW; + dw_style = WS_POPUP; + + // Move window borders out not to cover window contents. + // This converts client rect to window rect, i.e. expands it by the window border size. + AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); + } + // If it failed, we don't want to run fullscreen + else + { + mFullscreen = FALSE; + mFullscreenWidth = -1; + mFullscreenHeight = -1; + mFullscreenBits = -1; + mFullscreenRefresh = -1; - // Move window borders out not to cover window contents. - // This converts client rect to window rect, i.e. expands it by the window border size. - AdjustWindowRectEx(&window_rect, dw_style, FALSE, dw_ex_style); - } - // If it failed, we don't want to run fullscreen - else - { - mFullscreen = FALSE; - mFullscreenWidth = -1; - mFullscreenHeight = -1; - mFullscreenBits = -1; - mFullscreenRefresh = -1; + LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; + return FALSE; + } + } + else + { + mFullscreen = FALSE; + window_rect.left = (long)(posp ? posp->mX : 0); + window_rect.right = (long)width + window_rect.left; // Windows GDI rects don't include rightmost pixel + window_rect.top = (long)(posp ? posp->mY : 0); + window_rect.bottom = (long)height + window_rect.top; + // Window with an edge + dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; + dw_style = WS_OVERLAPPEDWINDOW; + } - LL_INFOS("Window") << "Unable to run fullscreen at " << width << "x" << height << LL_ENDL; - return FALSE; - } - } - else - { - mFullscreen = FALSE; - window_rect.left = (long) (posp ? posp->mX : 0); - window_rect.right = (long) width + window_rect.left; // Windows GDI rects don't include rightmost pixel - window_rect.top = (long) (posp ? posp->mY : 0); - window_rect.bottom = (long) height + window_rect.top; - // Window with an edge - dw_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; - dw_style = WS_OVERLAPPEDWINDOW; - } + // don't post quit messages when destroying old windows + mPostQuit = FALSE; - // don't post quit messages when destroying old windows - mPostQuit = FALSE; - // create window + // create window LL_DEBUGS("Window") << "Creating window with X: " << window_rect.left << " Y: " << window_rect.top << " Width: " << (window_rect.right - window_rect.left) << " Height: " << (window_rect.bottom - window_rect.top) << " Fullscreen: " << mFullscreen << LL_ENDL; - if (mWindowHandle && !destroy_window_handler(mWindowHandle)) - { - LL_WARNS("Window") << "Failed to properly close window before recreating it!" << LL_ENDL; - } - mWindowHandle = CreateWindowEx(dw_ex_style, - mWindowClassName, - mWindowTitle, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - window_rect.left, // x pos - window_rect.top, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height - NULL, - NULL, - mhInstance, - NULL); + + recreateWindow(window_rect, dw_ex_style, dw_style); if (mWindowHandle) { @@ -1288,7 +1214,7 @@ BOOL LLWindowWin32::switchContext(BOOL fullscreen, const LLCoordScreen &size, BO 0, 0, 0 }; - if (!(mhDC = GetDC(mWindowHandle))) + if (!mhDC) { close(); OSMessageBox(mCallbacks->translateString("MBDevContextErr"), @@ -1582,25 +1508,17 @@ const S32 max_format = (S32)num_formats - 1; mhDC = 0; // Zero The Device Context } - // Destroy The Window - if (mWindowHandle && !destroy_window_handler(mWindowHandle)) + recreateWindow(window_rect, dw_ex_style, dw_style); + + RECT rect; + RECT client_rect; + //initialize immediately on main thread + if (GetWindowRect(mWindowHandle, &rect) && + GetClientRect(mWindowHandle, &client_rect)) { - LL_WARNS("Window") << "Failed to properly close window!" << LL_ENDL; - } - - mWindowHandle = CreateWindowEx(dw_ex_style, - mWindowClassName, - mWindowTitle, - WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, - window_rect.left, // x pos - window_rect.top, // y pos - window_rect.right - window_rect.left, // width - window_rect.bottom - window_rect.top, // height - NULL, - NULL, - mhInstance, - NULL); - + mRect = rect; + mClientRect = client_rect; + }; if (mWindowHandle) { @@ -1612,7 +1530,7 @@ const S32 max_format = (S32)num_formats - 1; LL_WARNS("Window") << "Window recreation failed, code: " << GetLastError() << LL_ENDL; } - if (!(mhDC = GetDC(mWindowHandle))) + if (!mhDC) { close(); OSMessageBox(mCallbacks->translateString("MBDevContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); @@ -1687,58 +1605,11 @@ const S32 max_format = (S32)num_formats - 1; mhRC = 0; if (wglCreateContextAttribsARB) { //attempt to create a specific versioned context - S32 attribs[] = - { //start at 4.2 - WGL_CONTEXT_MAJOR_VERSION_ARB, 4, - WGL_CONTEXT_MINOR_VERSION_ARB, 2, - WGL_CONTEXT_PROFILE_MASK_ARB, LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0, - 0 - }; - - bool done = false; - while (!done) - { - mhRC = wglCreateContextAttribsARB(mhDC, mhRC, attribs); - - if (!mhRC) - { - if (attribs[3] > 0) - { //decrement minor version - attribs[3]--; - } - else if (attribs[1] > 3) - { //decrement major version and start minor version over at 3 - attribs[1]--; - attribs[3] = 3; - } - else - { //we reached 3.0 and still failed, bail out - done = true; - } - } - else - { - LL_INFOS() << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << - (LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << LL_ENDL; - done = true; - - // force sNoFixedFunction iff we're trying to use nsight debugging which does not support many legacy API uses - - // nSight doesn't support use of legacy API funcs in the fixed function pipe - if (LLRender::sGLCoreProfile || LLRender::sNsightDebugSupport) - { - LLGLSLShader::sNoFixedFunction = true; - } - } - } - } - - if (!mhRC && !(mhRC = wglCreateContext(mhDC))) - { - close(); - OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); - return FALSE; + mhRC = (HGLRC) createSharedContext(); + if (!mhRC) + { + return FALSE; + } } if (!wglMakeCurrent(mhDC, mhRC)) @@ -1748,6 +1619,8 @@ const S32 max_format = (S32)num_formats - 1; return FALSE; } + LL_PROFILER_GPU_CONTEXT + if (!gGLManager.initGL()) { close(); @@ -1756,15 +1629,7 @@ const S32 max_format = (S32)num_formats - 1; } // Disable vertical sync for swap - if (disable_vsync && wglSwapIntervalEXT) - { - LL_DEBUGS("Window") << "Disabling vertical sync" << LL_ENDL; - wglSwapIntervalEXT(0); - } - else - { - LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL; - } + toggleVSync(enable_vsync); SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); @@ -1790,6 +1655,177 @@ const S32 max_format = (S32)num_formats - 1; return TRUE; } +void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style) +{ + auto oldHandle = mWindowHandle; + + // zero out mWindowHandle and mhDC before destroying window so window + // thread falls back to peekmessage + mWindowHandle = 0; + mhDC = 0; + + std::promise<std::pair<HWND, HDC>> promise; + // What follows must be done on the window thread. + auto window_work = + [this, + self=mWindowThread, + oldHandle, + // bind CreateWindowEx() parameters by value instead of + // back-referencing LLWindowWin32 members + windowClassName=mWindowClassName, + windowTitle=mWindowTitle, + hInstance=mhInstance, + window_rect, + dw_ex_style, + dw_style, + &promise] + () + { + LL_DEBUGS("Window") << "recreateWindow(): window_work entry" << LL_ENDL; + self->mWindowHandle = 0; + self->mhDC = 0; + + // important to call DestroyWindow() from the window thread + if (oldHandle && !destroy_window_handler(oldHandle)) + { + LL_WARNS("Window") << "Failed to properly close window before recreating it!" + << LL_ENDL; + } + + auto handle = CreateWindowEx(dw_ex_style, + windowClassName, + windowTitle, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | dw_style, + window_rect.left, // x pos + window_rect.top, // y pos + window_rect.right - window_rect.left, // width + window_rect.bottom - window_rect.top, // height + NULL, + NULL, + hInstance, + NULL); + + if (! handle) + { + // Failed to create window: clear the variables. This + // assignment is valid because we're running on mWindowThread. + self->mWindowHandle = NULL; + self->mhDC = 0; + } + else + { + // Update mWindowThread's own mWindowHandle and mhDC. + self->mWindowHandle = handle; + self->mhDC = GetDC(handle); + } + + updateWindowRect(); + + // It's important to wake up the future either way. + promise.set_value(std::make_pair(self->mWindowHandle, self->mhDC)); + LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL; + }; + // But how we pass window_work to the window thread depends on whether we + // already have a window handle. + if (! oldHandle) + { + // Pass window_work using the WorkQueue: without an existing window + // handle, the window thread can't call GetMessage(). + LL_DEBUGS("Window") << "posting window_work to WorkQueue" << LL_ENDL; + mWindowThread->post(window_work); + } + else + { + // Pass window_work using PostMessage(). We can still + // PostMessage(oldHandle) because oldHandle won't be destroyed until + // the window thread has retrieved and executed window_work. + LL_DEBUGS("Window") << "posting window_work to message queue" << LL_ENDL; + mWindowThread->Post(oldHandle, window_work); + } + + auto future = promise.get_future(); + // This blocks until mWindowThread processes CreateWindowEx() and calls + // promise.set_value(). + auto pair = future.get(); + mWindowHandle = pair.first; + mhDC = pair.second; +} + +void* LLWindowWin32::createSharedContext() +{ + S32 attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 4, + WGL_CONTEXT_MINOR_VERSION_ARB, 6, + WGL_CONTEXT_PROFILE_MASK_ARB, LLRender::sGLCoreProfile ? WGL_CONTEXT_CORE_PROFILE_BIT_ARB : WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + WGL_CONTEXT_FLAGS_ARB, gDebugGL ? WGL_CONTEXT_DEBUG_BIT_ARB : 0, + 0 + }; + + HGLRC rc = 0; + + bool done = false; + while (!done) + { + rc = wglCreateContextAttribsARB(mhDC, mhRC, attribs); + + if (!rc) + { + if (attribs[3] > 0) + { //decrement minor version + attribs[3]--; + } + else if (attribs[1] > 3) + { //decrement major version and start minor version over at 3 + attribs[1]--; + attribs[3] = 3; + } + else + { //we reached 3.0 and still failed, bail out + done = true; + } + } + else + { + LL_INFOS() << "Created OpenGL " << llformat("%d.%d", attribs[1], attribs[3]) << + (LLRender::sGLCoreProfile ? " core" : " compatibility") << " context." << LL_ENDL; + done = true; + } + } + + if (!rc && !(rc = wglCreateContext(mhDC))) + { + close(); + OSMessageBox(mCallbacks->translateString("MBGLContextErr"), mCallbacks->translateString("MBError"), OSMB_OK); + } + + return rc; +} + +void LLWindowWin32::makeContextCurrent(void* contextPtr) +{ + wglMakeCurrent(mhDC, (HGLRC) contextPtr); +} + +void LLWindowWin32::destroySharedContext(void* contextPtr) +{ + wglDeleteContext((HGLRC)contextPtr); +} + +void LLWindowWin32::toggleVSync(bool enable_vsync) +{ + if (!enable_vsync && wglSwapIntervalEXT) + { + LL_INFOS("Window") << "Disabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(0); + } + else + { + LL_INFOS("Window") << "Enabling vertical sync" << LL_ENDL; + wglSwapIntervalEXT(1); + } +} + void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScreen& size ) { if( mIsMouseClipping ) @@ -1808,66 +1844,106 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre // THIS CAUSES DEV-15484 and DEV-15949 //ShowWindow(mWindowHandle, SW_RESTORE); // NOW we can call MoveWindow - MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); + mWindowThread->post([=]() + { + MoveWindow(mWindowHandle, position.mX, position.mY, size.mX, size.mY, TRUE); + }); +} + +void LLWindowWin32::setTitle(const std::string title) +{ + // TODO: Do we need to use the wide string version of this call + // to support non-ascii usernames (and region names?) + mWindowThread->post([=]() + { + SetWindowTextA(mWindowHandle, title.c_str()); + }); } BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) { - mMousePositionModified = TRUE; - if (!mWindowHandle) - { - return FALSE; - } + ASSERT_MAIN_THREAD(); + if (!mWindowHandle) + { + return FALSE; + } - // Inform the application of the new mouse position (needed for per-frame - // hover/picking to function). - mCallbacks->handleMouseMove(this, position.convert(), (MASK)0); - - // DEV-18951 VWR-8524 Camera moves wildly when alt-clicking. - // Because we have preemptively notified the application of the new - // mouse position via handleMouseMove() above, we need to clear out - // any stale mouse move events. RN/JC - MSG msg; - while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) - { } - - LLCoordScreen screen_pos(position.convert()); - return ::SetCursorPos(screen_pos.mX, screen_pos.mY); + LLCoordScreen screen_pos(position.convert()); + + // instantly set the cursor position from the app's point of view + mCursorPosition = position; + mLastCursorPosition = position; + + // Inform the application of the new mouse position (needed for per-frame + // hover/picking to function). + mCallbacks->handleMouseMove(this, position.convert(), (MASK)0); + + // actually set the cursor position on the window thread + mWindowThread->post([=]() + { + // actually set the OS cursor position + SetCursorPos(screen_pos.mX, screen_pos.mY); + }); + + return TRUE; } BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) { - POINT cursor_point; - - if (!mWindowHandle - || !GetCursorPos(&cursor_point) - || !position) - { - return FALSE; - } + ASSERT_MAIN_THREAD(); + if (!position) + { + return FALSE; + } - *position = LLCoordScreen(cursor_point.x, cursor_point.y).convert(); + *position = mCursorPosition; return TRUE; } +BOOL LLWindowWin32::getCursorDelta(LLCoordCommon* delta) +{ + if (delta == nullptr) + { + return FALSE; + } + + *delta = mMouseFrameDelta; + + return TRUE; +} + void LLWindowWin32::hideCursor() { - while (ShowCursor(FALSE) >= 0) - { - // nothing, wait for cursor to push down - } + ASSERT_MAIN_THREAD(); + + mWindowThread->post([=]() + { + while (ShowCursor(FALSE) >= 0) + { + // nothing, wait for cursor to push down + } + }); + mCursorHidden = TRUE; mHideCursorPermanent = TRUE; } void LLWindowWin32::showCursor() { - // makes sure the cursor shows up - while (ShowCursor(TRUE) < 0) - { - // do nothing, wait for cursor to pop out - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + + ASSERT_MAIN_THREAD(); + + mWindowThread->post([=]() + { + // makes sure the cursor shows up + while (ShowCursor(TRUE) < 0) + { + // do nothing, wait for cursor to pop out + } + }); + mCursorHidden = FALSE; mHideCursorPermanent = FALSE; } @@ -1971,6 +2047,8 @@ void LLWindowWin32::initCursors() void LLWindowWin32::updateCursor() { + ASSERT_MAIN_THREAD(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 if (mNextCursor == UI_CURSOR_ARROW && mBusyCount > 0) { @@ -1980,7 +2058,11 @@ void LLWindowWin32::updateCursor() if( mCurrentCursor != mNextCursor ) { mCurrentCursor = mNextCursor; - SetCursor( mCursor[mNextCursor] ); + auto nextCursor = mCursor[mNextCursor]; + mWindowThread->post([=]() + { + SetCursor(nextCursor); + }); } } @@ -1996,13 +2078,8 @@ void LLWindowWin32::captureMouse() void LLWindowWin32::releaseMouse() { - // *NOTE:Mani ReleaseCapture will spawn new windows messages... - // which will in turn call our MainWindowProc. It therefore requires - // pausing *and more importantly resumption* of the mainlooptimeout... - // just like DispatchMessage below. - mCallbacks->handlePauseWatchdog(this); + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; ReleaseCapture(); - mCallbacks->handleResumeWatchdog(this); } @@ -2011,1003 +2088,1010 @@ void LLWindowWin32::delayInputProcessing() mInputProcessingPaused = TRUE; } + void LLWindowWin32::gatherInput() { - MSG msg; - int msg_count = 0; + ASSERT_MAIN_THREAD(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32 + MSG msg; - while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput"); - TranslateMessage(&msg); + { + LLMutexLock lock(&mRawMouseMutex); + mMouseFrameDelta = mRawMouseDelta; - // turn watchdog off in here to not fail if windows is doing something wacky - mCallbacks->handlePauseWatchdog(this); - DispatchMessage(&msg); - mCallbacks->handleResumeWatchdog(this); - msg_count++; + mRawMouseDelta.mX = 0; + mRawMouseDelta.mY = 0; + } - if ( mInputProcessingPaused ) - { - break; - } - /* Attempted workaround for problem where typing fast and hitting - return would result in only part of the text being sent. JC - BOOL key_posted = TranslateMessage(&msg); - DispatchMessage(&msg); - msg_count++; + if (mWindowThread->getQueue().size()) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PostMessage"); + kickWindowThread(); + } + + while (mWindowThread->mMessageQueue.tryPopBack(msg)) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - message queue"); + if (mInputProcessingPaused) + { + continue; + } - // If a key was translated, a WM_CHAR might have been posted to the end - // of the event queue. We need it immediately. - if (key_posted && msg.message == WM_KEYDOWN) - { - if (PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - msg_count++; - } - } - */ - mCallbacks->handlePingWatchdog(this, "Main:AsyncCallbackGatherInput"); - // For async host by name support. Really hacky. - if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) - { - gAsyncMsgCallback(msg); - } - } + // For async host by name support. Really hacky. + if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - callback"); + gAsyncMsgCallback(msg); + } + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - PeekMessage"); + S32 msg_count = 0; + while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + msg_count++; + } + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - function queue"); + //process any pending functions + std::function<void()> curFunc; + while (mFunctionQueue.tryPopBack(curFunc)) + { + curFunc(); + } + } + + // send one and only one mouse move event per frame BEFORE handling mouse button presses + if (mLastCursorPosition != mCursorPosition) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse move"); + mCallbacks->handleMouseMove(this, mCursorPosition.convert(), mMouseMask); + } + + mLastCursorPosition = mCursorPosition; + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("gi - mouse queue"); + // handle mouse button presses AFTER updating mouse cursor position + std::function<void()> curFunc; + while (mMouseQueue.tryPopBack(curFunc)) + { + curFunc(); + } + } mInputProcessingPaused = FALSE; updateCursor(); - - // clear this once we've processed all mouse messages that might have occurred after - // we slammed the mouse position - mMousePositionModified = FALSE; } static LLTrace::BlockTimerStatHandle FTM_KEYHANDLER("Handle Keyboard"); static LLTrace::BlockTimerStatHandle FTM_MOUSEHANDLER("Handle Mouse"); +#define WINDOW_IMP_POST(x) window_imp->post([=]() { x; }) + LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_param, LPARAM l_param) { - // Ignore clicks not originated in the client area, i.e. mouse-up events not preceded with a WM_LBUTTONDOWN. - // This helps prevent avatar walking after maximizing the window by double-clicking the title bar. - static bool sHandleLeftMouseUp = true; - - // Ignore the double click received right after activating app. - // This is to avoid triggering double click teleport after returning focus (see MAINT-3786). - static bool sHandleDoubleClick = true; - - LLWindowWin32 *window_imp = (LLWindowWin32 *)GetWindowLongPtr( h_wnd, GWLP_USERDATA ); - - bool debug_window_proc = gDebugWindowProc || debugLoggingEnabled("Window"); - - - if (NULL != window_imp) - { - window_imp->mCallbacks->handleResumeWatchdog(window_imp); - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:StartWndProc"); - // Has user provided their own window callback? - if (NULL != window_imp->mWndProc) - { - if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param)) - { - // user has handled window message - return 0; - } - } - - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:PreSwitchWndProc"); - - // Juggle to make sure we can get negative positions for when - // mouse is outside window. - LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)); - - // This doesn't work, as LOWORD returns unsigned short. - //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param)); - LLCoordGL gl_coord; - - // pass along extended flag in mask - MASK mask = (l_param>>16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; - BOOL eat_keystroke = TRUE; - - switch(u_msg) - { - RECT update_rect; - S32 update_width; - S32 update_height; - - case WM_TIMER: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_TIMER"); - window_imp->mCallbacks->handleTimerEvent(window_imp); - break; - - case WM_DEVICECHANGE: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DEVICECHANGE"); - if (debug_window_proc) - { - LL_INFOS("Window") << " WM_DEVICECHANGE: wParam=" << w_param - << "; lParam=" << l_param << LL_ENDL; - } - if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) - { - if (window_imp->mCallbacks->handleDeviceChange(window_imp)) - { - return 0; - } - } - break; + ASSERT_WINDOW_THREAD(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; - case WM_PAINT: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PAINT"); - GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE); - update_width = update_rect.right - update_rect.left + 1; - update_height = update_rect.bottom - update_rect.top + 1; - window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top, - update_width, update_height); - break; - case WM_PARENTNOTIFY: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_PARENTNOTIFY"); - u_msg = u_msg; - break; - - case WM_SETCURSOR: - // This message is sent whenever the cursor is moved in a window. - // You need to set the appropriate cursor appearance. - - // Only take control of cursor over client region of window - // This allows Windows(tm) to handle resize cursors, etc. - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETCURSOR"); - if (LOWORD(l_param) == HTCLIENT) - { - SetCursor(window_imp->mCursor[ window_imp->mCurrentCursor] ); - return 0; - } - break; - - case WM_ENTERMENULOOP: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ENTERMENULOOP"); - window_imp->mCallbacks->handleWindowBlock(window_imp); - break; - - case WM_EXITMENULOOP: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_EXITMENULOOP"); - window_imp->mCallbacks->handleWindowUnblock(window_imp); - break; - - case WM_ACTIVATEAPP: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATEAPP"); - { - // This message should be sent whenever the app gains or loses focus. - BOOL activating = (BOOL) w_param; - BOOL minimized = window_imp->getMinimized(); - - if (debug_window_proc) - { - LL_INFOS("Window") << "WINDOWPROC ActivateApp " - << " activating " << S32(activating) - << " minimized " << S32(minimized) - << " fullscreen " << S32(window_imp->mFullscreen) - << LL_ENDL; - } - - if (window_imp->mFullscreen) - { - // When we run fullscreen, restoring or minimizing the app needs - // to switch the screen resolution - if (activating) - { - window_imp->setFullscreenResolution(); - window_imp->restore(); - } - else - { - window_imp->minimize(); - window_imp->resetDisplayResolution(); - } - } - - if (!activating) - { - sHandleDoubleClick = false; - } - - window_imp->mCallbacks->handleActivateApp(window_imp, activating); - - break; - } - - case WM_ACTIVATE: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_ACTIVATE"); - { - // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE - BOOL activating = (LOWORD(w_param) != WA_INACTIVE); - - BOOL minimized = BOOL(HIWORD(w_param)); - - if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } - - // JC - I'm not sure why, but if we don't report that we handled the - // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work - // properly when we run fullscreen. - if (debug_window_proc) - { - LL_INFOS("Window") << "WINDOWPROC Activate " - << " activating " << S32(activating) - << " minimized " << S32(minimized) - << LL_ENDL; - } - - // Don't handle this. - break; - } - - case WM_QUERYOPEN: - // TODO: use this to return a nice icon - break; + LL_DEBUGS("Window") << "mainWindowProc(" << std::hex << h_wnd + << ", " << u_msg + << ", " << w_param << ")" << std::dec << LL_ENDL; - case WM_SYSCOMMAND: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSCOMMAND"); - switch(w_param) - { - case SC_KEYMENU: - // Disallow the ALT key from triggering the default system menu. - return 0; - - case SC_SCREENSAVE: - case SC_MONITORPOWER: - // eat screen save messages and prevent them! - return 0; - } - break; - - case WM_CLOSE: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CLOSE"); - // Will the app allow the window to close? - if (window_imp->mCallbacks->handleCloseRequest(window_imp)) - { - // Get the app to initiate cleanup. - window_imp->mCallbacks->handleQuit(window_imp); - // The app is responsible for calling destroyWindow when done with GL - } - return 0; - - case WM_DESTROY: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DESTROY"); - if (window_imp->shouldPostQuit()) - { - PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0 - } - return 0; + if (u_msg == WM_POST_FUNCTION_) + { + LL_DEBUGS("Window") << "WM_POST_FUNCTION_" << LL_ENDL; + // from LLWindowWin32Thread::Post() + // Cast l_param back to the pointer to the heap FuncType + // allocated by Post(). Capture in unique_ptr so we'll delete + // once we're done with it. + std::unique_ptr<LLWindowWin32Thread::FuncType> + ptr(reinterpret_cast<LLWindowWin32Thread::FuncType*>(l_param)); + (*ptr)(); + return 0; + } - case WM_COMMAND: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COMMAND"); - if (!HIWORD(w_param)) // this message is from a menu - { - window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param)); - } - break; + // Ignore clicks not originated in the client area, i.e. mouse-up events not preceded with a WM_LBUTTONDOWN. + // This helps prevent avatar walking after maximizing the window by double-clicking the title bar. + static bool sHandleLeftMouseUp = true; - case WM_SYSKEYDOWN: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SYSKEYDOWN"); - // allow system keys, such as ALT-F4 to be processed by Windows - eat_keystroke = FALSE; - case WM_KEYDOWN: - window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next - window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff; - window_imp->mKeyVirtualKey = w_param; - window_imp->mRawMsg = u_msg; - window_imp->mRawWParam = w_param; - window_imp->mRawLParam = l_param; - - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYDOWN"); - { - if (debug_window_proc) - { - LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " - << " key " << S32(w_param) - << LL_ENDL; - } - if(gKeyboard->handleKeyDown(w_param, mask) && eat_keystroke) - { - return 0; - } - // pass on to windows if we didn't handle it - break; - } - case WM_SYSKEYUP: - eat_keystroke = FALSE; - case WM_KEYUP: - { - window_imp->mKeyScanCode = ( l_param >> 16 ) & 0xff; - window_imp->mKeyVirtualKey = w_param; - window_imp->mRawMsg = u_msg; - window_imp->mRawWParam = w_param; - window_imp->mRawLParam = l_param; + // Ignore the double click received right after activating app. + // This is to avoid triggering double click teleport after returning focus (see MAINT-3786). + static bool sHandleDoubleClick = true; - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); - LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER); + LLWindowWin32* window_imp = (LLWindowWin32*)GetWindowLongPtr(h_wnd, GWLP_USERDATA); - if (debug_window_proc) - { - LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " - << " key " << S32(w_param) - << LL_ENDL; - } - if (gKeyboard->handleKeyUp(w_param, mask) && eat_keystroke) - { - return 0; - } + bool debug_window_proc = false; // gDebugWindowProc || debugLoggingEnabled("Window"); - // pass on to windows - break; - } - case WM_IME_SETCONTEXT: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_SETCONTEXT"); - if (debug_window_proc) - { - LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL; - } - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW; - // Invoke DefWinProc with the modified LPARAM. - } - break; + if (NULL != window_imp) + { + // Juggle to make sure we can get negative positions for when + // mouse is outside window. + LLCoordWindow window_coord((S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)); - case WM_IME_STARTCOMPOSITION: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_STARTCOMPOSITION"); - if (debug_window_proc) - { - LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL; - } - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->handleStartCompositionMessage(); - return 0; - } - break; + // pass along extended flag in mask + MASK mask = (l_param >> 16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; + BOOL eat_keystroke = TRUE; - case WM_IME_ENDCOMPOSITION: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_ENDCOMPOSITION"); - if (debug_window_proc) - { - LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL; - } - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - return 0; - } - break; + switch (u_msg) + { + RECT update_rect; + S32 update_width; + S32 update_height; - case WM_IME_COMPOSITION: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_COMPOSITION"); - if (debug_window_proc) - { - LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL; - } - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->handleCompositionMessage(l_param); - return 0; - } - break; + case WM_TIMER: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_TIMER"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleTimerEvent(window_imp)); + break; + } - case WM_IME_REQUEST: - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_IME_REQUEST"); - if (debug_window_proc) - { - LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL; - } - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - LRESULT result = 0; - if (window_imp->handleImeRequests(w_param, l_param, &result)) - { - return result; - } - } - break; + case WM_DEVICECHANGE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DEVICECHANGE"); + if (debug_window_proc) + { + LL_INFOS("Window") << " WM_DEVICECHANGE: wParam=" << w_param + << "; lParam=" << l_param << LL_ENDL; + } + if (w_param == DBT_DEVNODES_CHANGED || w_param == DBT_DEVICEARRIVAL) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleDeviceChange(window_imp)); + + return TRUE; + } + break; + } - case WM_CHAR: - window_imp->mKeyCharCode = w_param; - window_imp->mRawMsg = u_msg; - window_imp->mRawWParam = w_param; - window_imp->mRawLParam = l_param; - - // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need - // to figure out how that works. - Doug - // - // ... Well, I don't think so. - // How it works is explained in Win32 API document, but WM_UNICHAR didn't work - // as specified at least on Windows XP SP1 Japanese version. I have never used - // it since then, and I'm not sure whether it has been fixed now, but I don't think - // it is worth trying. The good old WM_CHAR works just fine even for supplementary - // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's - // by ourselves. It is not that tough. -- Alissa Sabre @ SL - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_CHAR"); - if (debug_window_proc) - { - LL_INFOS("Window") << "Debug WindowProc WM_CHAR " - << " key " << S32(w_param) - << LL_ENDL; - } - // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE, - // we *did* processed the event, so I believe we should not pass it to DefWindowProc... - window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); - return 0; + case WM_PAINT: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_PAINT"); + GetUpdateRect(window_imp->mWindowHandle, &update_rect, FALSE); + update_width = update_rect.right - update_rect.left + 1; + update_height = update_rect.bottom - update_rect.top + 1; + + WINDOW_IMP_POST(window_imp->mCallbacks->handlePaint(window_imp, update_rect.left, update_rect.top, + update_width, update_height)); + break; + } + case WM_PARENTNOTIFY: + { + break; + } - case WM_NCLBUTTONDOWN: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_NCLBUTTONDOWN"); - // A click in a non-client area, e.g. title bar or window border. - sHandleLeftMouseUp = false; - sHandleDoubleClick = true; - } - break; + case WM_SETCURSOR: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETCURSOR"); + // This message is sent whenever the cursor is moved in a window. + // You need to set the appropriate cursor appearance. - case WM_LBUTTONDOWN: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - sHandleLeftMouseUp = true; + // Only take control of cursor over client region of window + // This allows Windows(tm) to handle resize cursors, etc. + if (LOWORD(l_param) == HTCLIENT) + { + SetCursor(window_imp->mCursor[window_imp->mCurrentCursor]); + return 0; + } + break; + } + case WM_ENTERMENULOOP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ENTERMENULOOP"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowBlock(window_imp)); + break; + } - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } + case WM_EXITMENULOOP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_EXITMENULOOP"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp)); + break; + } - // Because we move the cursor position in the app, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - if (window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask)) - { - return 0; - } - } - break; + case WM_ACTIVATEAPP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATEAPP"); + window_imp->post([=]() + { + // This message should be sent whenever the app gains or loses focus. + BOOL activating = (BOOL)w_param; + BOOL minimized = window_imp->getMinimized(); + + if (debug_window_proc) + { + LL_INFOS("Window") << "WINDOWPROC ActivateApp " + << " activating " << S32(activating) + << " minimized " << S32(minimized) + << " fullscreen " << S32(window_imp->mFullscreen) + << LL_ENDL; + } + + if (window_imp->mFullscreen) + { + // When we run fullscreen, restoring or minimizing the app needs + // to switch the screen resolution + if (activating) + { + window_imp->setFullscreenResolution(); + window_imp->restore(); + } + else + { + window_imp->minimize(); + window_imp->resetDisplayResolution(); + } + } + + if (!activating) + { + sHandleDoubleClick = false; + } + + window_imp->mCallbacks->handleActivateApp(window_imp, activating); + }); + break; + } + case WM_ACTIVATE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_ACTIVATE"); + window_imp->post([=]() + { + // Can be one of WA_ACTIVE, WA_CLICKACTIVE, or WA_INACTIVE + BOOL activating = (LOWORD(w_param) != WA_INACTIVE); + + BOOL minimized = BOOL(HIWORD(w_param)); + + if (!activating && LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + // JC - I'm not sure why, but if we don't report that we handled the + // WM_ACTIVATE message, the WM_ACTIVATEAPP messages don't work + // properly when we run fullscreen. + if (debug_window_proc) + { + LL_INFOS("Window") << "WINDOWPROC Activate " + << " activating " << S32(activating) + << " minimized " << S32(minimized) + << LL_ENDL; + } + }); + + break; + } - case WM_LBUTTONDBLCLK: - //RN: ignore right button double clicks for now - //case WM_RBUTTONDBLCLK: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDBLCLK"); + case WM_QUERYOPEN: + // TODO: use this to return a nice icon + break; - if (!sHandleDoubleClick) - { - sHandleDoubleClick = true; - break; - } + case WM_SYSCOMMAND: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSCOMMAND"); + switch (w_param) + { + case SC_KEYMENU: + // Disallow the ALT key from triggering the default system menu. + return 0; + + case SC_SCREENSAVE: + case SC_MONITORPOWER: + // eat screen save messages and prevent them! + return 0; + } + break; + } + case WM_CLOSE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CLOSE"); + window_imp->post([=]() + { + // Will the app allow the window to close? + if (window_imp->mCallbacks->handleCloseRequest(window_imp)) + { + // Get the app to initiate cleanup. + window_imp->mCallbacks->handleQuit(window_imp); + // The app is responsible for calling destroyWindow when done with GL + } + }); + return 0; + } + case WM_DESTROY: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DESTROY"); + if (window_imp->shouldPostQuit()) + { + PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0 + } + return 0; + } + case WM_COMMAND: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COMMAND"); + if (!HIWORD(w_param)) // this message is from a menu + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleMenuSelect(window_imp, LOWORD(w_param))); + } + break; + } + case WM_SYSKEYDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SYSKEYDOWN"); + // allow system keys, such as ALT-F4 to be processed by Windows + eat_keystroke = FALSE; + // intentional fall-through here + } + case WM_KEYDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYDOWN"); + window_imp->post([=]() + { + window_imp->mKeyCharCode = 0; // don't know until wm_char comes in next + window_imp->mKeyScanCode = (l_param >> 16) & 0xff; + window_imp->mKeyVirtualKey = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; + + { + if (debug_window_proc) + { + LL_INFOS("Window") << "Debug WindowProc WM_KEYDOWN " + << " key " << S32(w_param) + << LL_ENDL; + } + + gKeyboard->handleKeyDown(w_param, mask); + } + }); + if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress + break; + } + case WM_SYSKEYUP: + eat_keystroke = FALSE; + // intentional fall-through here + case WM_KEYUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KEYUP"); + window_imp->post([=]() + { + window_imp->mKeyScanCode = (l_param >> 16) & 0xff; + window_imp->mKeyVirtualKey = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; + + { + LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER); + + if (debug_window_proc) + { + LL_INFOS("Window") << "Debug WindowProc WM_KEYUP " + << " key " << S32(w_param) + << LL_ENDL; + } + gKeyboard->handleKeyUp(w_param, mask); + } + }); + if (eat_keystroke) return 0; // skip DefWindowProc() handling if we're consuming the keypress + break; + } + case WM_IME_SETCONTEXT: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_SETCONTEXT"); + if (debug_window_proc) + { + LL_INFOS("Window") << "WM_IME_SETCONTEXT" << LL_ENDL; + } + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + l_param &= ~ISC_SHOWUICOMPOSITIONWINDOW; + // Invoke DefWinProc with the modified LPARAM. + } + break; + } + case WM_IME_STARTCOMPOSITION: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_STARTCOMPOSITION"); + if (debug_window_proc) + { + LL_INFOS() << "WM_IME_STARTCOMPOSITION" << LL_ENDL; + } + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + WINDOW_IMP_POST(window_imp->handleStartCompositionMessage()); + return 0; + } + break; + } + case WM_IME_ENDCOMPOSITION: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_ENDCOMPOSITION"); + if (debug_window_proc) + { + LL_INFOS() << "WM_IME_ENDCOMPOSITION" << LL_ENDL; + } + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + return 0; + } + break; + } + case WM_IME_COMPOSITION: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_COMPOSITION"); + if (debug_window_proc) + { + LL_INFOS() << "WM_IME_COMPOSITION" << LL_ENDL; + } + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + WINDOW_IMP_POST(window_imp->handleCompositionMessage(l_param)); + return 0; + } + break; + } + case WM_IME_REQUEST: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_IME_REQUEST"); + if (debug_window_proc) + { + LL_INFOS() << "WM_IME_REQUEST" << LL_ENDL; + } + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + LRESULT result; + window_imp->handleImeRequests(w_param, l_param, &result); + return result; + } + break; + } + case WM_CHAR: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_CHAR"); + window_imp->post([=]() + { + window_imp->mKeyCharCode = w_param; + window_imp->mRawMsg = u_msg; + window_imp->mRawWParam = w_param; + window_imp->mRawLParam = l_param; + + // Should really use WM_UNICHAR eventually, but it requires a specific Windows version and I need + // to figure out how that works. - Doug + // + // ... Well, I don't think so. + // How it works is explained in Win32 API document, but WM_UNICHAR didn't work + // as specified at least on Windows XP SP1 Japanese version. I have never used + // it since then, and I'm not sure whether it has been fixed now, but I don't think + // it is worth trying. The good old WM_CHAR works just fine even for supplementary + // characters. We just need to take care of surrogate pairs sent as two WM_CHAR's + // by ourselves. It is not that tough. -- Alissa Sabre @ SL + if (debug_window_proc) + { + LL_INFOS("Window") << "Debug WindowProc WM_CHAR " + << " key " << S32(w_param) + << LL_ENDL; + } + // Even if LLWindowCallbacks::handleUnicodeChar(llwchar, BOOL) returned FALSE, + // we *did* processed the event, so I believe we should not pass it to DefWindowProc... + window_imp->handleUnicodeUTF16((U16)w_param, gKeyboard->currentMask(FALSE)); + }); + return 0; + } + case WM_NCLBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_NCLBUTTONDOWN"); + { + // A click in a non-client area, e.g. title bar or window border. + window_imp->post([=]() + { + sHandleLeftMouseUp = false; + sHandleDoubleClick = true; + }); + } + break; + } + case WM_LBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->postMouseButtonEvent([=]() + { + sHandleLeftMouseUp = true; + + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + MASK mask = gKeyboard->currentMask(TRUE); + auto gl_coord = window_imp->mCursorPosition.convert(); + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + window_imp->mCallbacks->handleMouseDown(window_imp, gl_coord, mask); + }); + + return 0; + } + break; + } - // Because we move the cursor position in the app, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - if (window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask) ) - { - return 0; - } - } - break; + case WM_LBUTTONDBLCLK: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONDBLCLK"); + window_imp->postMouseButtonEvent([=]() + { + //RN: ignore right button double clicks for now + //case WM_RBUTTONDBLCLK: + if (!sHandleDoubleClick) + { + sHandleDoubleClick = true; + return; + } + MASK mask = gKeyboard->currentMask(TRUE); + + // generate move event to update mouse coordinates + window_imp->mCursorPosition = window_coord; + window_imp->mCallbacks->handleDoubleClick(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + + return 0; + } + case WM_LBUTTONUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_LBUTTONUP"); + { + window_imp->postMouseButtonEvent([=]() + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + if (!sHandleLeftMouseUp) + { + sHandleLeftMouseUp = true; + return; + } + sHandleDoubleClick = true; + + + MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCursorPosition = window_coord; + window_imp->mCallbacks->handleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + } + return 0; + } + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->post([=]() + { + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + WINDOW_IMP_POST(window_imp->interruptLanguageTextInput()); + } + + MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + auto gl_coord = window_imp->mCursorPosition.convert(); + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask); + }); + } + return 0; + } + break; - case WM_LBUTTONUP: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + case WM_RBUTTONUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_RBUTTONUP"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->postMouseButtonEvent([=]() + { + MASK mask = gKeyboard->currentMask(TRUE); + window_imp->mCallbacks->handleRightMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + } + } + break; - if (!sHandleLeftMouseUp) - { - sHandleLeftMouseUp = true; - break; - } - sHandleDoubleClick = true; - - //if (gDebugClicks) - //{ - // LL_INFOS("Window") << "WndProc left button up" << LL_ENDL; - //} - // Because we move the cursor position in the app, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - if (window_imp->mCallbacks->handleMouseUp(window_imp, gl_coord, mask)) - { - return 0; - } - } - break; + case WM_MBUTTONDOWN: + // case WM_MBUTTONDBLCLK: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->postMouseButtonEvent([=]() + { + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + MASK mask = gKeyboard->currentMask(TRUE); + window_imp->mCallbacks->handleMiddleMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + } + } + break; - case WM_RBUTTONDBLCLK: - case WM_RBUTTONDOWN: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONDOWN"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } + case WM_MBUTTONUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MBUTTONUP"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->postMouseButtonEvent([=]() + { + MASK mask = gKeyboard->currentMask(TRUE); + window_imp->mCallbacks->handleMiddleMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask); + }); + } + } + break; + case WM_XBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONDOWN"); + window_imp->postMouseButtonEvent([=]() + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + S32 button = GET_XBUTTON_WPARAM(w_param); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + MASK mask = gKeyboard->currentMask(TRUE); + // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 + window_imp->mCallbacks->handleOtherMouseDown(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); + }); + + } + break; - // Because we move the cursor position in the llviewerapp, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - if (window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask)) - { - return 0; - } - } - break; + case WM_XBUTTONUP: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_XBUTTONUP"); + window_imp->postMouseButtonEvent([=]() + { - case WM_RBUTTONUP: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_RBUTTONUP"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - // Because we move the cursor position in the app, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - if (window_imp->mCallbacks->handleRightMouseUp(window_imp, gl_coord, mask)) - { - return 0; - } - } - break; + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - case WM_MBUTTONDOWN: -// case WM_MBUTTONDBLCLK: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } + S32 button = GET_XBUTTON_WPARAM(w_param); + MASK mask = gKeyboard->currentMask(TRUE); + // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 + window_imp->mCallbacks->handleOtherMouseUp(window_imp, window_imp->mCursorPosition.convert(), mask, button + 3); + }); + } + break; - // Because we move the cursor position in tllviewerhe app, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - if (window_imp->mCallbacks->handleMiddleMouseDown(window_imp, gl_coord, mask)) - { - return 0; - } - } - break; + case WM_MOUSEWHEEL: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEWHEEL"); + static short z_delta = 0; - case WM_MBUTTONUP: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - // Because we move the cursor position in the llviewer app, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - if (window_imp->mCallbacks->handleMiddleMouseUp(window_imp, gl_coord, mask)) - { - return 0; - } - } - break; - case WM_XBUTTONDOWN: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONDOWN"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - S32 button = GET_XBUTTON_WPARAM(w_param); - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } + RECT client_rect; - // Because we move the cursor position in tllviewerhe app, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 - if (window_imp->mCallbacks->handleOtherMouseDown(window_imp, gl_coord, mask, button + 3)) - { - return 0; - } - } - break; + // eat scroll events that occur outside our window, since we use mouse position to direct scroll + // instead of keyboard focus + // NOTE: mouse_coord is in *window* coordinates for scroll events + POINT mouse_coord = { (S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param) }; - case WM_XBUTTONUP: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MBUTTONUP"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - S32 button = GET_XBUTTON_WPARAM(w_param); - // Because we move the cursor position in the llviewer app, we need to query - // to find out where the cursor at the time the event is handled. - // If we don't do this, many clicks could get buffered up, and if the - // first click changes the cursor position, all subsequent clicks - // will occur at the wrong location. JC - if (window_imp->mMousePositionModified) - { - LLCoordWindow cursor_coord_window; - window_imp->getCursorPosition(&cursor_coord_window); - gl_coord = cursor_coord_window.convert(); - } - else - { - gl_coord = window_coord.convert(); - } - MASK mask = gKeyboard->currentMask(TRUE); - // generate move event to update mouse coordinates - window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); - // Windows uses numbers 1 and 2 for buttons, remap to 4, 5 - if (window_imp->mCallbacks->handleOtherMouseUp(window_imp, gl_coord, mask, button + 3)) - { - return 0; - } - } - break; + if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) + && GetClientRect(window_imp->mWindowHandle, &client_rect)) + { + // we have a valid mouse point and client rect + if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x + || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) + { + // mouse is outside of client rect, so don't do anything + return 0; + } + } - case WM_MOUSEWHEEL: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEWHEEL"); - static short z_delta = 0; + S16 incoming_z_delta = HIWORD(w_param); + z_delta += incoming_z_delta; + // cout << "z_delta " << z_delta << endl; + + // current mouse wheels report changes in increments of zDelta (+120, -120) + // Future, higher resolution mouse wheels may report smaller deltas. + // So we sum the deltas and only act when we've exceeded WHEEL_DELTA + // + // If the user rapidly spins the wheel, we can get messages with + // large deltas, like 480 or so. Thus we need to scroll more quickly. + if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) + { + short clicks = -z_delta / WHEEL_DELTA; + WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollWheel(window_imp, clicks)); + z_delta = 0; + } + return 0; + } + /* + // TODO: add this after resolving _WIN32_WINNT issue + case WM_MOUSELEAVE: + { + window_imp->mCallbacks->handleMouseLeave(window_imp); + + // TRACKMOUSEEVENT track_mouse_event; + // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); + // track_mouse_event.dwFlags = TME_LEAVE; + // track_mouse_event.hwndTrack = h_wnd; + // track_mouse_event.dwHoverTime = HOVER_DEFAULT; + // TrackMouseEvent( &track_mouse_event ); + return 0; + } + */ + case WM_MOUSEHWHEEL: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEHWHEEL"); + static short h_delta = 0; - RECT client_rect; + RECT client_rect; - // eat scroll events that occur outside our window, since we use mouse position to direct scroll - // instead of keyboard focus - // NOTE: mouse_coord is in *window* coordinates for scroll events - POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)}; + // eat scroll events that occur outside our window, since we use mouse position to direct scroll + // instead of keyboard focus + // NOTE: mouse_coord is in *window* coordinates for scroll events + POINT mouse_coord = { (S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param) }; - if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) - && GetClientRect(window_imp->mWindowHandle, &client_rect)) - { - // we have a valid mouse point and client rect - if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x - || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) - { - // mouse is outside of client rect, so don't do anything - return 0; - } - } + if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) + && GetClientRect(window_imp->mWindowHandle, &client_rect)) + { + // we have a valid mouse point and client rect + if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x + || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) + { + // mouse is outside of client rect, so don't do anything + return 0; + } + } - S16 incoming_z_delta = HIWORD(w_param); - z_delta += incoming_z_delta; - // cout << "z_delta " << z_delta << endl; - - // current mouse wheels report changes in increments of zDelta (+120, -120) - // Future, higher resolution mouse wheels may report smaller deltas. - // So we sum the deltas and only act when we've exceeded WHEEL_DELTA - // - // If the user rapidly spins the wheel, we can get messages with - // large deltas, like 480 or so. Thus we need to scroll more quickly. - if (z_delta <= -WHEEL_DELTA || WHEEL_DELTA <= z_delta) - { - window_imp->mCallbacks->handleScrollWheel(window_imp, -z_delta / WHEEL_DELTA); - z_delta = 0; - } - return 0; - } - /* - // TODO: add this after resolving _WIN32_WINNT issue - case WM_MOUSELEAVE: - { - window_imp->mCallbacks->handleMouseLeave(window_imp); - - // TRACKMOUSEEVENT track_mouse_event; - // track_mouse_event.cbSize = sizeof( TRACKMOUSEEVENT ); - // track_mouse_event.dwFlags = TME_LEAVE; - // track_mouse_event.hwndTrack = h_wnd; - // track_mouse_event.dwHoverTime = HOVER_DEFAULT; - // TrackMouseEvent( &track_mouse_event ); - return 0; - } - */ - case WM_MOUSEHWHEEL: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEHWHEEL"); - static short h_delta = 0; + S16 incoming_h_delta = HIWORD(w_param); + h_delta += incoming_h_delta; - RECT client_rect; + // If the user rapidly spins the wheel, we can get messages with + // large deltas, like 480 or so. Thus we need to scroll more quickly. + if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA)); + h_delta = 0; + } + return 0; + } + // Handle mouse movement within the window + case WM_MOUSEMOVE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE"); + // DO NOT use mouse event queue for move events to ensure cursor position is updated + // when button events are handled + WINDOW_IMP_POST( + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_MOUSEMOVE lambda"); + + MASK mask = gKeyboard->currentMask(TRUE); + window_imp->mMouseMask = mask; + window_imp->mCursorPosition = window_coord; + }); + return 0; + } - // eat scroll events that occur outside our window, since we use mouse position to direct scroll - // instead of keyboard focus - // NOTE: mouse_coord is in *window* coordinates for scroll events - POINT mouse_coord = {(S32)(S16)LOWORD(l_param), (S32)(S16)HIWORD(l_param)}; + case WM_GETMINMAXINFO: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_GETMINMAXINFO"); + LPMINMAXINFO min_max = (LPMINMAXINFO)l_param; + min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth; + min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight; + return 0; + } - if (ScreenToClient(window_imp->mWindowHandle, &mouse_coord) - && GetClientRect(window_imp->mWindowHandle, &client_rect)) - { - // we have a valid mouse point and client rect - if (mouse_coord.x < client_rect.left || client_rect.right < mouse_coord.x - || mouse_coord.y < client_rect.top || client_rect.bottom < mouse_coord.y) - { - // mouse is outside of client rect, so don't do anything - return 0; - } - } + case WM_MOVE: + { + window_imp->updateWindowRect(); + return 0; + } + case WM_SIZE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SIZE"); + window_imp->updateWindowRect(); + S32 width = S32(LOWORD(l_param)); + S32 height = S32(HIWORD(l_param)); - S16 incoming_h_delta = HIWORD(w_param); - h_delta += incoming_h_delta; + + if (debug_window_proc) + { + BOOL maximized = (w_param == SIZE_MAXIMIZED); + BOOL restored = (w_param == SIZE_RESTORED); + BOOL minimized = (w_param == SIZE_MINIMIZED); + + LL_INFOS("Window") << "WINDOWPROC Size " + << width << "x" << height + << " max " << S32(maximized) + << " min " << S32(minimized) + << " rest " << S32(restored) + << LL_ENDL; + } - // If the user rapidly spins the wheel, we can get messages with - // large deltas, like 480 or so. Thus we need to scroll more quickly. - if (h_delta <= -WHEEL_DELTA || WHEEL_DELTA <= h_delta) - { - window_imp->mCallbacks->handleScrollHWheel(window_imp, h_delta / WHEEL_DELTA); - h_delta = 0; - } - return 0; - } - // Handle mouse movement within the window - case WM_MOUSEMOVE: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_MOUSEMOVE"); - MASK mask = gKeyboard->currentMask(TRUE); - window_imp->mCallbacks->handleMouseMove(window_imp, window_coord.convert(), mask); - return 0; - } + // There's an odd behavior with WM_SIZE that I would call a bug. If + // the window is maximized, and you call MoveWindow() with a size smaller + // than a maximized window, it ends up sending WM_SIZE with w_param set + // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. + // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see + // LLWindowWin32::moveWindow in this file). - case WM_GETMINMAXINFO: - { - LPMINMAXINFO min_max = (LPMINMAXINFO)l_param; - min_max->ptMinTrackSize.x = window_imp->mMinWindowWidth; - min_max->ptMinTrackSize.y = window_imp->mMinWindowHeight; - return 0; - } + // If we are now restored, but we weren't before, this + // means that the window was un-minimized. + if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, TRUE)); + } - case WM_SIZE: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SIZE"); - S32 width = S32( LOWORD(l_param) ); - S32 height = S32( HIWORD(l_param) ); + // handle case of window being maximized from fully minimized state + if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, TRUE)); + } - if (debug_window_proc) - { - BOOL maximized = ( w_param == SIZE_MAXIMIZED ); - BOOL restored = ( w_param == SIZE_RESTORED ); - BOOL minimized = ( w_param == SIZE_MINIMIZED ); - - LL_INFOS("Window") << "WINDOWPROC Size " - << width << "x" << height - << " max " << S32(maximized) - << " min " << S32(minimized) - << " rest " << S32(restored) - << LL_ENDL; - } + // Also handle the minimization case + if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleActivate(window_imp, FALSE)); + } - // There's an odd behavior with WM_SIZE that I would call a bug. If - // the window is maximized, and you call MoveWindow() with a size smaller - // than a maximized window, it ends up sending WM_SIZE with w_param set - // to SIZE_MAXIMIZED -- which isn't true. So the logic below doesn't work. - // (SL-44655). Fixed it by calling ShowWindow(SW_RESTORE) first (see - // LLWindowWin32::moveWindow in this file). + // Actually resize all of our views + if (w_param != SIZE_MINIMIZED) + { + // Ignore updates for minimizing and minimized "windows" + WINDOW_IMP_POST(window_imp->mCallbacks->handleResize(window_imp, + LOWORD(l_param), + HIWORD(l_param))); + } - // If we are now restored, but we weren't before, this - // means that the window was un-minimized. - if (w_param == SIZE_RESTORED && window_imp->mLastSizeWParam != SIZE_RESTORED) - { - window_imp->mCallbacks->handleActivate(window_imp, TRUE); - } + window_imp->mLastSizeWParam = w_param; - // handle case of window being maximized from fully minimized state - if (w_param == SIZE_MAXIMIZED && window_imp->mLastSizeWParam != SIZE_MAXIMIZED) - { - window_imp->mCallbacks->handleActivate(window_imp, TRUE); - } + return 0; + } - // Also handle the minimization case - if (w_param == SIZE_MINIMIZED && window_imp->mLastSizeWParam != SIZE_MINIMIZED) - { - window_imp->mCallbacks->handleActivate(window_imp, FALSE); - } + case WM_DPICHANGED: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_DPICHANGED"); + LPRECT lprc_new_scale; + F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI); + lprc_new_scale = (LPRECT)l_param; + S32 new_width = lprc_new_scale->right - lprc_new_scale->left; + S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top; + WINDOW_IMP_POST(window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height)); + + SetWindowPos(h_wnd, + HWND_TOP, + lprc_new_scale->left, + lprc_new_scale->top, + new_width, + new_height, + SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } - // Actually resize all of our views - if (w_param != SIZE_MINIMIZED) - { - // Ignore updates for minimizing and minimized "windows" - window_imp->mCallbacks->handleResize( window_imp, - LOWORD(l_param), - HIWORD(l_param) ); - } + case WM_SETFOCUS: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS"); + if (debug_window_proc) + { + LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL; + } + WINDOW_IMP_POST(window_imp->mCallbacks->handleFocus(window_imp)); + return 0; + } - window_imp->mLastSizeWParam = w_param; + case WM_KILLFOCUS: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_KILLFOCUS"); + if (debug_window_proc) + { + LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; + } + WINDOW_IMP_POST(window_imp->mCallbacks->handleFocusLost(window_imp)); + return 0; + } - return 0; - } + case WM_COPYDATA: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_COPYDATA"); + { + // received a URL + PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT)l_param; + void* data = new U8[myCDS->cbData]; + memcpy(data, myCDS->lpData, myCDS->cbData); + auto myType = myCDS->dwData; + + window_imp->post([=]() + { + window_imp->mCallbacks->handleDataCopy(window_imp, myType, data); + delete[] data; + }); + }; + return 0; + + break; + } + case WM_SETTINGCHANGE: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETTINGCHANGE"); + if (w_param == SPI_SETMOUSEVANISH) + { + if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0)) + { + WINDOW_IMP_POST(window_imp->mMouseVanish = TRUE); + } + } + } + break; - case WM_DPICHANGED: - { - LPRECT lprc_new_scale; - F32 new_scale = F32(LOWORD(w_param)) / F32(USER_DEFAULT_SCREEN_DPI); - lprc_new_scale = (LPRECT)l_param; - S32 new_width = lprc_new_scale->right - lprc_new_scale->left; - S32 new_height = lprc_new_scale->bottom - lprc_new_scale->top; - if (window_imp->mCallbacks->handleDPIChanged(window_imp, new_scale, new_width, new_height)) - { - SetWindowPos(h_wnd, - HWND_TOP, - lprc_new_scale->left, - lprc_new_scale->top, - new_width, - new_height, - SWP_NOZORDER | SWP_NOACTIVATE); - } - return 0; - } - - case WM_SETFOCUS: - if (debug_window_proc) - { - LL_INFOS("Window") << "WINDOWPROC SetFocus" << LL_ENDL; - } - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_SETFOCUS"); - window_imp->mCallbacks->handleFocus(window_imp); - return 0; - - case WM_KILLFOCUS: - if (debug_window_proc) - { - LL_INFOS("Window") << "WINDOWPROC KillFocus" << LL_ENDL; - } - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KILLFOCUS"); - window_imp->mCallbacks->handleFocusLost(window_imp); - return 0; - - case WM_COPYDATA: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_COPYDATA"); - // received a URL - PCOPYDATASTRUCT myCDS = (PCOPYDATASTRUCT) l_param; - window_imp->mCallbacks->handleDataCopy(window_imp, myCDS->dwData, myCDS->lpData); - }; - return 0; + case WM_INPUT: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("MWP - WM_INPUT"); + + UINT dwSize = 0; + GetRawInputData((HRAWINPUT)l_param, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER)); + llassert(dwSize < 1024); + + U8 lpb[1024]; + + if (GetRawInputData((HRAWINPUT)l_param, RID_INPUT, (void*)lpb, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize) + { + RAWINPUT* raw = (RAWINPUT*)lpb; + + if (raw->header.dwType == RIM_TYPEMOUSE) + { + LLMutexLock lock(&window_imp->mRawMouseMutex); + window_imp->mRawMouseDelta.mX += raw->data.mouse.lLastX; + window_imp->mRawMouseDelta.mY -= raw->data.mouse.lLastY; + } + } + } - break; + //list of messages we get often that we don't care to log about + case WM_NCHITTEST: + case WM_NCMOUSEMOVE: + case WM_NCMOUSELEAVE: + case WM_MOVING: + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + break; - case WM_SETTINGCHANGE: - { - if (w_param == SPI_SETMOUSEVANISH) - { - if (!SystemParametersInfo(SPI_GETMOUSEVANISH, 0, &window_imp->mMouseVanish, 0)) - { - window_imp->mMouseVanish = TRUE; - } - } - } - break; - default: - { - if (debug_window_proc) - { - LL_INFOS("Window") << "Unhandled windows message code: " << U32(u_msg) << LL_ENDL; - } - } - break; - } - - window_imp->mCallbacks->handlePauseWatchdog(window_imp); - } + default: + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - default"); + if (debug_window_proc) + { + LL_INFOS("Window") << "Unhandled windows message code: 0x" << std::hex << U32(u_msg) << LL_ENDL; + } + } + break; + } + } else { // (NULL == window_imp) LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; } - // pass unhandled messages down to Windows - return DefWindowProc(h_wnd, u_msg, w_param, l_param); + // pass unhandled messages down to Windows + LRESULT ret; + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - DefWindowProc"); + ret = DefWindowProc(h_wnd, u_msg, w_param, l_param); + } + return ret; } BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) @@ -3186,6 +3270,8 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) // Constrains the mouse to the window. void LLWindowWin32::setMouseClipping( BOOL b ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + ASSERT_MAIN_THREAD(); if( b != mIsMouseClipping ) { BOOL success = FALSE; @@ -3216,43 +3302,46 @@ void LLWindowWin32::setMouseClipping( BOOL b ) BOOL LLWindowWin32::getClientRectInScreenSpace( RECT* rectp ) { - BOOL success = FALSE; + BOOL success = FALSE; - RECT client_rect; - if( mWindowHandle && GetClientRect(mWindowHandle, &client_rect) ) - { - POINT top_left; - top_left.x = client_rect.left; - top_left.y = client_rect.top; - ClientToScreen(mWindowHandle, &top_left); - - POINT bottom_right; - bottom_right.x = client_rect.right; - bottom_right.y = client_rect.bottom; - ClientToScreen(mWindowHandle, &bottom_right); - - SetRect( rectp, - top_left.x, - top_left.y, - bottom_right.x, - bottom_right.y ); - - success = TRUE; - } + RECT client_rect; + if (mWindowHandle && GetClientRect(mWindowHandle, &client_rect)) + { + POINT top_left; + top_left.x = client_rect.left; + top_left.y = client_rect.top; + ClientToScreen(mWindowHandle, &top_left); + + POINT bottom_right; + bottom_right.x = client_rect.right; + bottom_right.y = client_rect.bottom; + ClientToScreen(mWindowHandle, &bottom_right); + + SetRect(rectp, + top_left.x, + top_left.y, + bottom_right.x, + bottom_right.y); + + success = TRUE; + } - return success; + return success; } void LLWindowWin32::flashIcon(F32 seconds) { - FLASHWINFO flash_info; - - flash_info.cbSize = sizeof(FLASHWINFO); - flash_info.hwnd = mWindowHandle; - flash_info.dwFlags = FLASHW_TRAY; - flash_info.uCount = UINT(seconds / ICON_FLASH_TIME); - flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds - FlashWindowEx(&flash_info); + mWindowThread->post([=]() + { + FLASHWINFO flash_info; + + flash_info.cbSize = sizeof(FLASHWINFO); + flash_info.hwnd = mWindowHandle; + flash_info.dwFlags = FLASHW_TRAY; + flash_info.uCount = UINT(seconds / ICON_FLASH_TIME); + flash_info.dwTimeout = DWORD(1000.f * ICON_FLASH_TIME); // milliseconds + FlashWindowEx(&flash_info); + }); } F32 LLWindowWin32::getGamma() @@ -3262,6 +3351,7 @@ F32 LLWindowWin32::getGamma() BOOL LLWindowWin32::restoreGamma() { + ASSERT_MAIN_THREAD(); if (mCustomGammaSet != FALSE) { LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL; @@ -3273,6 +3363,7 @@ BOOL LLWindowWin32::restoreGamma() BOOL LLWindowWin32::setGamma(const F32 gamma) { + ASSERT_MAIN_THREAD(); mCurrentGamma = gamma; //Get the previous gamma ramp to restore later. @@ -3311,6 +3402,7 @@ BOOL LLWindowWin32::setGamma(const F32 gamma) void LLWindowWin32::setFSAASamples(const U32 fsaa_samples) { + ASSERT_MAIN_THREAD(); mFSAASamples = fsaa_samples; } @@ -3321,6 +3413,7 @@ U32 LLWindowWin32::getFSAASamples() LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) { + ASSERT_MAIN_THREAD(); if (!mSupportedResolutions) { mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; @@ -3475,7 +3568,12 @@ BOOL LLWindowWin32::resetDisplayResolution() void LLWindowWin32::swapBuffers() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + ASSERT_MAIN_THREAD(); + glFlush(); //superstitious flush for maybe frame stall removal? SwapBuffers(mhDC); + + LL_PROFILER_GPU_COLLECT } @@ -3700,13 +3798,19 @@ void *LLWindowWin32::getPlatformWindow() void LLWindowWin32::bringToFront() { - BringWindowToTop(mWindowHandle); + mWindowThread->post([=]() + { + BringWindowToTop(mWindowHandle); + }); } // set (OS) window focus back to the client void LLWindowWin32::focusClient() { - SetFocus ( mWindowHandle ); + mWindowThread->post([=]() + { + SetFocus(mWindowHandle); + }); } void LLWindowWin32::allowLanguageTextInput(LLPreeditor *preeditor, BOOL b) @@ -3948,6 +4052,7 @@ void LLWindowWin32::updateLanguageTextInputArea() void LLWindowWin32::interruptLanguageTextInput() { + ASSERT_MAIN_THREAD(); if (mPreeditor && LLWinImm::isAvailable()) { HIMC himc = LLWinImm::getContext(mWindowHandle); @@ -4150,6 +4255,7 @@ static LLWString find_context(const LLWString & wtext, S32 focus, S32 focus_leng // for files and via IDropTarget interface requests. LLWindowCallbacks::DragNDropResult LLWindowWin32::completeDragNDropRequest( const LLCoordGL gl_coord, const MASK mask, LLWindowCallbacks::DragNDropAction action, const std::string url ) { + ASSERT_MAIN_THREAD(); return mCallbacks->handleDragNDrop( this, gl_coord, mask, action, url ); } @@ -4198,6 +4304,7 @@ BOOL LLWindowWin32::handleImeRequests(WPARAM request, LPARAM param, LRESULT *res LL_WARNS("Window") << "*** IMR_QUERYCHARPOSITON called but getPreeditLocation failed." << LL_ENDL; return FALSE; } + fillCharPosition(caret_coord, preedit_bounds, text_control, char_position); *result = 1; @@ -4406,3 +4513,153 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() #endif // LL_WINDOWS + +inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() + : ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE) +{ + ThreadPool::start(); +} + +/** + * LogChange is to log changes in status while trying to avoid spamming the + * log with repeated messages, especially in a tight loop. It refuses to log + * a continuous run of identical messages, but logs every time the message + * changes. (It will happily spam when messages quickly bounce back and + * forth.) + */ +class LogChange +{ +public: + LogChange(const std::string& tag): + mTag(tag) + {} + + template <typename... Items> + void always(Items&&... items) + { + // This odd construct ensures that the stringize() call is only + // executed if DEBUG logging is enabled for the passed tag. + LL_DEBUGS(mTag.c_str()); + log(LL_CONT, stringize(std::forward<Items>(items)...)); + LL_ENDL; + } + + template <typename... Items> + void onChange(Items&&... items) + { + LL_DEBUGS(mTag.c_str()); + auto str = stringize(std::forward<Items>(items)...); + if (str != mPrev) + { + log(LL_CONT, str); + } + LL_ENDL; + } + +private: + void log(std::ostream& out, const std::string& message) + { + mPrev = message; + out << message; + } + std::string mTag; + std::string mPrev; +}; + +void LLWindowWin32::LLWindowWin32Thread::run() +{ + sWindowThreadId = std::this_thread::get_id(); + LogChange logger("Window"); + + while (! getQueue().done()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + + if (mWindowHandle != 0) + { + MSG msg; + BOOL status; + if (mhDC == 0) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage"); + logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")"); + status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE); + } + else + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage"); + logger.always("GetMessage(", std::hex, mWindowHandle, ")"); + status = GetMessage(&msg, NULL, 0, 0); + } + if (status > 0) + { + logger.always("got MSG (", std::hex, msg.hwnd, ", ", msg.message, + ", ", msg.wParam, ")"); + TranslateMessage(&msg); + DispatchMessage(&msg); + + mMessageQueue.pushFront(msg); + } + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Function Queue"); + logger.onChange("runPending()"); + //process any pending functions + getQueue().runPending(); + } + +#if 0 + { + LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - Sleep"); + logger.always("sleep(1)"); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +#endif + } +} + +void LLWindowWin32::post(const std::function<void()>& func) +{ + mFunctionQueue.pushFront(func); +} + +void LLWindowWin32::postMouseButtonEvent(const std::function<void()>& func) +{ + mMouseQueue.pushFront(func); +} + +void LLWindowWin32::kickWindowThread(HWND windowHandle) +{ + if (! windowHandle) + windowHandle = mWindowHandle; + if (windowHandle) + { + // post a nonsense user message to wake up the Window Thread in + // case any functions are pending and no windows events came + // through this frame + WPARAM wparam{ 0xB0B0 }; + LL_DEBUGS("Window") << "PostMessage(" << std::hex << windowHandle + << ", " << WM_DUMMY_ + << ", " << wparam << ")" << std::dec << LL_ENDL; + PostMessage(windowHandle, WM_DUMMY_, wparam, 0x1337); + } +} + +void LLWindowWin32::updateWindowRect() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32; + //called from window thread + RECT rect; + RECT client_rect; + + if (GetWindowRect(mWindowHandle, &rect) && + GetClientRect(mWindowHandle, &client_rect)) + { + post([=] + { + mRect = rect; + mClientRect = client_rect; + }); + } +} diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index e33330c1bb..b391acc12d 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -33,6 +33,10 @@ #include "llwindow.h" #include "llwindowcallbacks.h" #include "lldragdropwin32.h" +#include "llthread.h" +#include "llthreadsafequeue.h" +#include "llmutex.h" +#include "workqueue.h" // Hack for async host by name #define LL_WM_HOST_RESOLVED (WM_APP + 1) @@ -57,9 +61,15 @@ public: /*virtual*/ BOOL setPosition(LLCoordScreen position); /*virtual*/ BOOL setSizeImpl(LLCoordScreen size); /*virtual*/ BOOL setSizeImpl(LLCoordWindow size); - /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL disable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ BOOL switchContext(BOOL fullscreen, const LLCoordScreen &size, BOOL enable_vsync, const LLCoordScreen * const posp = NULL); + /*virtual*/ void setTitle(const std::string title); + void* createSharedContext() override; + void makeContextCurrent(void* context) override; + void destroySharedContext(void* context) override; + /*virtual*/ void toggleVSync(bool enable_vsync); /*virtual*/ BOOL setCursorPosition(LLCoordWindow position); /*virtual*/ BOOL getCursorPosition(LLCoordWindow *position); + /*virtual*/ BOOL getCursorDelta(LLCoordCommon* delta); /*virtual*/ void showCursor(); /*virtual*/ void hideCursor(); /*virtual*/ void showCursorFromMouseMove(); @@ -126,7 +136,7 @@ public: protected: LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, int x, int y, int width, int height, U32 flags, - BOOL fullscreen, BOOL clearBg, BOOL disable_vsync, BOOL use_gl, + BOOL fullscreen, BOOL clearBg, BOOL enable_vsync, BOOL use_gl, BOOL ignore_pixel_depth, U32 fsaa_samples); ~LLWindowWin32(); @@ -175,17 +185,24 @@ protected: WCHAR *mWindowTitle; WCHAR *mWindowClassName; - HWND mWindowHandle; // window handle - HGLRC mhRC; // OpenGL rendering context - HDC mhDC; // Windows Device context handle + HWND mWindowHandle = 0; // window handle + HGLRC mhRC = 0; // OpenGL rendering context + HDC mhDC = 0; // Windows Device context handle HINSTANCE mhInstance; // handle to application instance - WNDPROC mWndProc; // user-installable window proc RECT mOldMouseClip; // Screen rect to which the mouse cursor was globally constrained before we changed it in clipMouse() WPARAM mLastSizeWParam; F32 mOverrideAspectRatio; F32 mNativeAspectRatio; HCURSOR mCursor[ UI_CURSOR_COUNT ]; // Array of all mouse cursors + LLCoordWindow mCursorPosition; // mouse cursor position, should only be mutated on main thread + LLMutex mRawMouseMutex; + RAWINPUTDEVICE mRawMouse; + LLCoordWindow mLastCursorPosition; // mouse cursor position from previous frame + LLCoordCommon mRawMouseDelta; // raw mouse delta according to window thread + LLCoordCommon mMouseFrameDelta; // how much the mouse moved between the last two calls to gatherInput + + MASK mMouseMask; static BOOL sIsClassRegistered; // has the window class been registered? @@ -196,7 +213,6 @@ protected: BOOL mCustomGammaSet; LPWSTR mIconResource; - BOOL mMousePositionModified; BOOL mInputProcessingPaused; // The following variables are for Language Text Input control. @@ -224,6 +240,20 @@ protected: BOOL mMouseVanish; + // Cached values of GetWindowRect and GetClientRect to be used by app thread + void updateWindowRect(); + RECT mRect; + RECT mClientRect; + + struct LLWindowWin32Thread; + LLWindowWin32Thread* mWindowThread = nullptr; + LLThreadSafeQueue<std::function<void()>> mFunctionQueue; + LLThreadSafeQueue<std::function<void()>> mMouseQueue; + void post(const std::function<void()>& func); + void postMouseButtonEvent(const std::function<void()>& func); + void recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw_style); + void kickWindowThread(HWND windowHandle=0); + friend class LLWindowManager; }; diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 19508becc3..0839c02c50 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -247,6 +247,7 @@ public: // generic getter template<typename T> T get(const std::string& name) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; LLControlVariable* control = getControl(name); LLSD value; eControlType type = TYPE_COUNT; @@ -405,8 +406,8 @@ public: const T& default_value, const std::string& comment = "Declared In Code") { - mCachedControlPtr = LLControlCache<T>::getInstance(name); - if (mCachedControlPtr.isNull()) + mCachedControlPtr = LLControlCache<T>::getInstance(name).get(); + if (! mCachedControlPtr) { mCachedControlPtr = new LLControlCache<T>(group, name, default_value, comment); } @@ -415,8 +416,8 @@ public: LLCachedControl(LLControlGroup& group, const std::string& name) { - mCachedControlPtr = LLControlCache<T>::getInstance(name); - if (mCachedControlPtr.isNull()) + mCachedControlPtr = LLControlCache<T>::getInstance(name).get(); + if (! mCachedControlPtr) { mCachedControlPtr = new LLControlCache<T>(group, name); } diff --git a/indra/media_plugins/cef/CMakeLists.txt b/indra/media_plugins/cef/CMakeLists.txt index 854ba55731..2acce03d08 100644 --- a/indra/media_plugins/cef/CMakeLists.txt +++ b/indra/media_plugins/cef/CMakeLists.txt @@ -108,9 +108,6 @@ if (DARWIN) LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" ) - ## turns on C++11 using Cmake - target_compile_features(media_plugin_cef PRIVATE cxx_range_for) - add_custom_command(TARGET media_plugin_cef POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -change "@executable_path/Chromium Embedded Framework" "@executable_path/../../../../Frameworks/Chromium Embedded Framework.framework/Chromium Embedded Framework" diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 6e648485fd..964615320d 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -17,7 +17,6 @@ include(DBusGlib) include(DragDrop) include(EXPAT) include(FMODSTUDIO) -include(GLOD) include(Hunspell) include(JPEGEncoderBasic) include(JsonCpp) @@ -33,6 +32,7 @@ include(LLInventory) include(LLKDU) include(LLLogin) include(LLMath) +include(LLMeshOptimizer) include(LLMessage) include(LLPhysicsExtensions) include(LLPlugin) @@ -50,6 +50,7 @@ include(OpenSSL) include(PNG) include(TemplateCheck) include(ThreeJS) +include(Tracy) include(UI) include(UnixInstall) include(ViewerMiscLibs) @@ -70,7 +71,6 @@ endif(FMODSTUDIO) include_directories( ${DBUSGLIB_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} - ${GLOD_INCLUDE_DIR} ${LLAUDIO_INCLUDE_DIRS} ${LLCHARACTER_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} @@ -80,6 +80,7 @@ include_directories( ${LLKDU_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} + ${LLMESHOPTIMIZER_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} ${LLPLUGIN_INCLUDE_DIRS} ${LLPRIMITIVE_INCLUDE_DIRS} @@ -95,6 +96,7 @@ include_directories( ${LIBS_PREBUILT_DIR}/include/collada/1.4 ${LLAPPEARANCE_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR} + ${TRACY_INCLUDE_DIR} ) include_directories(SYSTEM @@ -282,7 +284,7 @@ set(viewer_SOURCE_FILES llfloaternamedesc.cpp llfloaternotificationsconsole.cpp llfloaternotificationstabbed.cpp - llfloateroutfitphotopreview.cpp + llfloateroutfitphotopreview.cpp llfloateroutfitsnapshot.cpp llfloaterobjectweights.cpp llfloateropenobject.cpp @@ -395,7 +397,6 @@ set(viewer_SOURCE_FILES llloginhandler.cpp lllogininstance.cpp llmachineid.cpp - llmainlooprepeater.cpp llmanip.cpp llmaniprotate.cpp llmanipscale.cpp @@ -591,11 +592,8 @@ set(viewer_SOURCE_FILES llsyntaxid.cpp llsyswellitem.cpp llsyswellwindow.cpp - lltelemetry.cpp llteleporthistory.cpp llteleporthistorystorage.cpp - lltextureatlas.cpp - lltextureatlasmanager.cpp lltexturecache.cpp lltexturectrl.cpp lltexturefetch.cpp @@ -1036,7 +1034,6 @@ set(viewer_HEADER_FILES llloginhandler.h lllogininstance.h llmachineid.h - llmainlooprepeater.h llmanip.h llmaniprotate.h llmanipscale.h @@ -1225,8 +1222,6 @@ set(viewer_HEADER_FILES lltable.h llteleporthistory.h llteleporthistorystorage.h - lltextureatlas.h - lltextureatlasmanager.h lltexturecache.h lltexturectrl.h lltexturefetch.h @@ -1386,7 +1381,7 @@ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt" "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}\n") set_source_files_properties( - llversioninfo.cpp tests/llversioninfo_test.cpp + llversioninfo.cpp tests/llversioninfo_test.cpp PROPERTIES COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" # see BuildVersion.cmake ) @@ -1608,6 +1603,7 @@ if (WINDOWS) ${WINDOWS_LIBRARIES} comdlg32 dxguid + imm32 kernel32 odbc32 odbccp32 @@ -1697,6 +1693,8 @@ set(viewer_APPSETTINGS_FILES ${CMAKE_SOURCE_DIR}/../etc/message.xml ${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg packages-info.txt + featuretable.txt + featuretable_mac.txt ) source_group("App Settings" FILES ${viewer_APPSETTINGS_FILES}) @@ -1751,10 +1749,6 @@ endif (HAVOK OR HAVOK_TPV) # progress view disables/enables icons based on available packages set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") -if (GLODLIB) - set_source_files_properties(llfloatermodelpreview.cpp PROPERTIES COMPILE_FLAGS "-DLL_GLOD") -endif (GLODLIB) - list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) set_source_files_properties(${viewer_HEADER_FILES} @@ -1822,9 +1816,6 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapr-1.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libaprutil-1.dll ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/libapriconv-1.dll - ${SHARED_LIB_STAGING_DIR}/Release/glod.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/glod.dll - ${SHARED_LIB_STAGING_DIR}/Debug/glod.dll ${SHARED_LIB_STAGING_DIR}/Release/libcollada14dom22.dll ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/libcollada14dom22.dll ${SHARED_LIB_STAGING_DIR}/Debug/libcollada14dom22-d.dll @@ -2009,7 +2000,7 @@ endif (WINDOWS) # one of these being libz where you can find four or more versions in play # at once. On Linux, libz can be found at link and run time via a number # of paths: -# +# # => -lfreetype # => libz.so.1 (on install machine, not build) # => -lSDL @@ -2034,6 +2025,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLCHARACTER_LIBRARIES} ${LLIMAGE_LIBRARIES} ${LLINVENTORY_LIBRARIES} + ${LLMESHOPTIMIZER_LIBRARIES} ${LLMESSAGE_LIBRARIES} ${LLPLUGIN_LIBRARIES} ${LLPRIMITIVE_LIBRARIES} @@ -2057,7 +2049,6 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} ${FMODWRAPPER_LIBRARY} # must come after LLAudio - ${GLOD_LIBRARIES} ${OPENGL_LIBRARIES} ${JSONCPP_LIBRARIES} ${SDL_LIBRARY} @@ -2072,6 +2063,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLPHYSICS_LIBRARIES} ${LLPHYSICSEXTENSIONS_LIBRARIES} ${LLAPPEARANCE_LIBRARIES} + ${TRACY_LIBRARY} ) if (USE_BUGSPLAT) @@ -2180,7 +2172,7 @@ if (DARWIN) # https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/ set(CMAKE_MACOSX_RPATH 1) - + set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES @@ -2382,7 +2374,7 @@ if (LL_TESTS) llworldmap.cpp llworldmipmap.cpp PROPERTIES - LL_TEST_ADDITIONAL_SOURCE_FILES + LL_TEST_ADDITIONAL_SOURCE_FILES tests/llviewertexture_stub.cpp #llviewertexturelist.cpp ) @@ -2416,7 +2408,7 @@ if (LL_TESTS) llworldmap.cpp llworldmipmap.cpp PROPERTIES - LL_TEST_ADDITIONAL_SOURCE_FILES + LL_TEST_ADDITIONAL_SOURCE_FILES tests/llviewertexture_stub.cpp #llviewertexturelist.cpp LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}" diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index cc81d718c3..826f5ce030 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -6.5.5 +6.6.0 diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index 3100baf943..dd2b656ce3 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -209,6 +209,14 @@ <string>NoAudio</string> </map> + <key>noninteractive</key> + <map> + <key>desc</key> + <string>Run in semi-headless mode where only login and logout need to work.</string> + <key>map-to</key> + <string>NonInteractive</string> + </map> + <key>nonotifications</key> <map> <key>desc</key> diff --git a/indra/newview/app_settings/high_graphics.xml b/indra/newview/app_settings/high_graphics.xml index 662f7e39dd..f64937f443 100644 --- a/indra/newview/app_settings/high_graphics.xml +++ b/indra/newview/app_settings/high_graphics.xml @@ -6,8 +6,6 @@ <RenderAvatarLODFactor value="1.0"/> <!--Default for now--> <RenderAvatarPhysicsLODFactor value="0.9"/> - <!--NO SHADERS--> - <RenderAvatarVP value="TRUE"/> <!--Short Range--> <RenderFarClip value="128"/> <!--Default for now--> diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml index 0ee8e7a059..b31a040d67 100644 --- a/indra/newview/app_settings/low_graphics.xml +++ b/indra/newview/app_settings/low_graphics.xml @@ -6,8 +6,6 @@ <RenderAvatarLODFactor value="0.5"/> <!--Default for now--> <RenderAvatarPhysicsLODFactor value="0.0"/> - <!--NO SHADERS--> - <RenderAvatarVP value="FALSE"/> <!--Short Range--> <RenderFarClip value="64"/> <!--Default for now--> diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml index c89e060307..9c2c17fc60 100644 --- a/indra/newview/app_settings/mid_graphics.xml +++ b/indra/newview/app_settings/mid_graphics.xml @@ -6,8 +6,6 @@ <RenderAvatarLODFactor value="0.5"/> <!--Default for now--> <RenderAvatarPhysicsLODFactor value="0.75"/> - <!--NO SHADERS--> - <RenderAvatarVP value="TRUE"/> <!--Short Range--> <RenderFarClip value="96"/> <!--Default for now--> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b3be9d302e..a6dce3cceb 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -812,17 +812,6 @@ <key>Value</key> <integer>0</integer> </map> - <key>FramePerSecondLimit</key> - <map> - <key>Comment</key> - <string>Controls upper limit of frames per second</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>U32</string> - <key>Value</key> - <integer>120</integer> - </map> <key>BackgroundYieldTime</key> <map> <key>Comment</key> @@ -3409,10 +3398,10 @@ <key>Value</key> <integer>0</integer> </map> - <key>DisableVerticalSync</key> + <key>RenderVSyncEnable</key> <map> <key>Comment</key> - <string>Update frames as fast as possible (FALSE = update frames between display scans)</string> + <string>Update frames between display scans (FALSE = Update frames as fast as possible).</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -3585,7 +3574,7 @@ <key>Value</key> <integer>0</integer> </map> - <key>DoubleClickTeleport</key> + <key>DoubleClickTeleport</key> <map> <key>Comment</key> <string>Enable double-click to teleport where allowed (afects minimap and people panel)</string> @@ -3915,6 +3904,17 @@ <key>Value</key> <integer>1</integer> </map> + <key>MainWorkTime</key> + <map> + <key>Comment</key> + <string>Max time per frame devoted to mainloop work queue (in milliseconds)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>0.1</real> + </map> <key>QueueInventoryFetchTimeout</key> <map> <key>Comment</key> @@ -6470,7 +6470,7 @@ <key>MaxHeapSize</key> <map> <key>Comment</key> - <string>Maximum heap size (GB)</string> + <string>Maximum heap size on 32-bit builds (GB)</string> <key>Persist</key> <integer>1</integer> <key>Type</key> @@ -6478,6 +6478,17 @@ <key>Value</key> <real>1.6</real> </map> + <key>MaxHeapSize64</key> + <map> + <key>Comment</key> + <string>Maximum heap size on 64-bit builds (GB)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>16.0</real> + </map> <key>MaxPersistentNotifications</key> <map> <key>Comment</key> @@ -7074,6 +7085,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>NonInteractive</key> + <map> + <key>Comment</key> + <string>Run in a semi-headless mode where only logging in and logging out needs to work.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>NonvisibleObjectsInMemoryTime</key> <map> <key>Comment</key> @@ -8693,28 +8715,6 @@ </array> </map> - <key>RenderAlphaBatchFullbrights</key> - <map> - <key>Comment</key> - <string>Render fullbright alpha content more efficiently, but with possible visual differences from prev viewers.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>0</integer> - </map> - <key>RenderAlphaBatchEmissives</key> - <map> - <key>Comment</key> - <string>Render emissive alpha content more efficiently, but with possible visual differences from prev viewers.</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>RenderAnisotropic</key> <map> <key>Comment</key> @@ -8895,17 +8895,6 @@ <key>Value</key> <real>1.0</real> </map> - <key>RenderAvatarVP</key> - <map> - <key>Comment</key> - <string>Use vertex programs to perform hardware skinning of avatar</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>RenderCompressTextures</key> <map> <key>Comment</key> @@ -8917,7 +8906,7 @@ <key>Value</key> <integer>0</integer> </map> - <key>RenderHiDPI</key> + <key>RenderHiDPI</key> <map> <key>Comment</key> <string>Enable support for HiDPI displays, like Retina (MacOS X ONLY, requires restart)</string> @@ -9875,7 +9864,7 @@ <key>Value</key> <real>2.2</real> </map> - <key>RenderGLCoreProfile</key> + <key>RenderGLContextCoreProfile</key> <map> <key>Comment</key> <string>Don't use a compatibility profile OpenGL context. Requires restart. Basic shaders MUST be enabled.</string> @@ -9886,6 +9875,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>RenderGLMultiThreaded</key> + <map> + <key>Comment</key> + <string>Allow OpenGL to use multiple render contexts (reduces frame stutters from loading textures, doesn't play nice with Intel drivers).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>RenderGlow</key> <map> <key>Comment</key> @@ -10189,7 +10189,7 @@ <key>Type</key> <string>S32</string> <key>Value</key> - <integer>512</integer> + <integer>4096</integer> </map> <key>RenderNameFadeDuration</key> <map> @@ -11639,7 +11639,7 @@ <string>Boolean</string> <key>Value</key> <integer>0</integer> - </map> + </map> <key>NearbyListShowMap</key> <map> <key>Comment</key> @@ -12755,6 +12755,20 @@ <key>Value</key> <string /> </map> + <key>ThreadPoolSizes</key> + <map> + <key>Comment</key> + <string>Map of size overrides for specific thread pools.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>LLSD</string> + <key>Value</key> + <map> + <key>General</key> + <integer>4</integer> + </map> + </map> <key>ThrottleBandwidthKBPS</key> <map> <key>Comment</key> @@ -14197,17 +14211,6 @@ <key>Value</key> <integer>1</integer> </map> - <key>RenderSynchronousOcclusion</key> - <map> - <key>Comment</key> - <string>Don't let occlusion queries get more than one frame behind (block until they complete).</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> - </map> <key>RenderDelayVBUpdate</key> <map> <key>Comment</key> @@ -16725,8 +16728,8 @@ <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>1</integer> - </map> + <integer>1</integer> + </map> <key>360CaptureUseInterestListCap</key> <map> <key>Comment</key> @@ -16806,14 +16809,25 @@ </map> <key>ResetUIScaleOnFirstRun</key> <map> - <key>Comment</key> - <string>Resets the UI scale factor on first run due to changed display scaling behavior</string> - <key>Persist</key> - <integer>1</integer> - <key>Type</key> - <string>Boolean</string> - <key>Value</key> - <integer>1</integer> + <key>Comment</key> + <string>Resets the UI scale factor on first run due to changed display scaling behavior</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>UpdateAppWindowTitleBar</key> + <map> + <key>Comment</key> + <string>Updates the application window title bar with brief information about user/location</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> </map> </map> </llsd> diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl index dc484317e9..02b2daf0ac 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl @@ -56,6 +56,10 @@ VARYING vec3 vary_norm; VARYING vec4 vertex_color; //vertex color should be treated as sRGB #endif +#ifdef HAS_ALPHA_MASK +uniform float minimum_alpha; +#endif + uniform mat4 proj_mat; uniform mat4 inv_proj; uniform vec2 screen_res; @@ -86,6 +90,14 @@ float getAmbientClamp(); vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, float ambiance) { + // SL-14895 inverted attenuation work-around + // This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct + // that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights() + // to recover the `adjusted_radius` value previously being sent as la. + float falloff_factor = (12.0 * fa) - 9.0; + float inverted_la = falloff_factor / la; + // Yes, it makes me want to cry as well. DJH + vec3 col = vec3(0); //get light vector @@ -95,7 +107,7 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec float dist = length(lv); float da = 1.0; - /*if (dist > la) + /*if (dist > inverted_la) { return col; } @@ -113,9 +125,9 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec return col; }*/ - if (dist > 0.0 && la > 0.0) + if (dist > 0.0 && inverted_la > 0.0) { - dist /= la; + dist /= inverted_la; //normalize light vector lv = normalize(lv); @@ -183,7 +195,6 @@ void main() #endif vec4 diffuse_srgb = diffuse_tap; - vec4 diffuse_linear = vec4(srgb_to_linear(diffuse_srgb.rgb), diffuse_srgb.a); #ifdef FOR_IMPOSTOR vec4 color; @@ -192,25 +203,37 @@ void main() float final_alpha = diffuse_srgb.a * vertex_color.a; diffuse_srgb.rgb *= vertex_color.rgb; - diffuse_linear.rgb = srgb_to_linear(diffuse_srgb.rgb); // Insure we don't pollute depth with invis pixels in impostor rendering // - if (final_alpha < 0.01) + if (final_alpha < minimum_alpha) { discard; } -#else - + + color.rgb = diffuse_srgb.rgb; + color.a = final_alpha; + +#else // FOR_IMPOSTOR + + vec4 diffuse_linear = vec4(srgb_to_linear(diffuse_srgb.rgb), diffuse_srgb.a); + vec3 light_dir = (sun_up_factor == 1) ? sun_dir: moon_dir; float final_alpha = diffuse_linear.a; #ifdef USE_VERTEX_COLOR final_alpha *= vertex_color.a; + + if (final_alpha < minimum_alpha) + { // TODO: figure out how to get invisible faces out of + // render batches without breaking glow + discard; + } + diffuse_srgb.rgb *= vertex_color.rgb; diffuse_linear.rgb = srgb_to_linear(diffuse_srgb.rgb); -#endif +#endif // USE_VERTEX_COLOR vec3 sunlit; vec3 amblit; @@ -242,13 +265,13 @@ void main() #if !defined(AMBIENT_KILL) color.rgb = amblit; color.rgb *= ambient; -#endif +#endif // !defined(AMBIENT_KILL) vec3 post_ambient = color.rgb; #if !defined(SUNLIGHT_KILL) color.rgb += sun_contrib; -#endif +#endif // !defined(SUNLIGHT_KILL) vec3 post_sunlight = color.rgb; @@ -280,7 +303,7 @@ vec3 post_atmo = color.rgb; // sum local light contrib in linear colorspace #if !defined(LOCAL_LIGHT_KILL) color.rgb += light.rgb; -#endif +#endif // !defined(LOCAL_LIGHT_KILL) // back to sRGB as we're going directly to the final RT post-deferred gamma correction color.rgb = linear_to_srgb(color.rgb); @@ -299,8 +322,8 @@ vec3 post_atmo = color.rgb; color = applyWaterFogView(pos.xyz, color); #endif // WATER_FOG -#endif - +#endif // #else // FOR_IMPOSTOR + frag_color = color; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl index 506118d381..6a93bc2fd2 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl @@ -105,9 +105,9 @@ void main() vec4 vert = vec4(position.xyz, 1.0); pos = (modelview_matrix * vert); gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); -#endif +#endif //IS_AVATAR_SKIN -#endif +#endif // HAS_SKIN #ifdef USE_INDEXED_TEX passTextureIndex(); diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl index ef49b6f4e8..1b16e4eb09 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowF.glsl @@ -40,11 +40,11 @@ VARYING vec4 post_pos; VARYING float pos_w; VARYING float target_pos_x; VARYING vec2 vary_texcoord0; -VARYING vec4 vertex_color; +uniform vec4 color; void main() { - float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * vertex_color.a; + float alpha = texture2D(diffuseMap, vary_texcoord0.xy).a * color.a; if (alpha < 0.05) // treat as totally transparent { diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl index d1d7ece6fe..1c5b142ebd 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaShadowV.glsl @@ -30,7 +30,6 @@ uniform float shadow_target_width; mat4 getSkinnedTransform(); void passTextureIndex(); -ATTRIBUTE vec4 diffuse_color; ATTRIBUTE vec3 position; ATTRIBUTE vec3 normal; ATTRIBUTE vec2 texcoord0; @@ -41,7 +40,6 @@ VARYING vec4 post_pos; VARYING float pos_w; VARYING float target_pos_x; VARYING vec2 vary_texcoord0; -VARYING vec4 vertex_color; void main() { @@ -68,7 +66,6 @@ void main() vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vertex_color = diffuse_color; #if !DEPTH_CLAMP post_pos = pos; diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl deleted file mode 100644 index 10144f3e16..0000000000 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl +++ /dev/null @@ -1,64 +0,0 @@ -/** - * @file bumpV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 projection_matrix; -uniform mat4 texture_matrix0; -uniform mat4 modelview_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec2 texcoord0; -ATTRIBUTE vec4 tangent; - -VARYING vec3 vary_mat0; -VARYING vec3 vary_mat1; -VARYING vec3 vary_mat2; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - -mat4 getObjectSkinnedTransform(); - -void main() -{ - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - - mat4 mat = getObjectSkinnedTransform(); - - mat = modelview_matrix * mat; - - vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; - - - vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz); - vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz); - vec3 b = cross(n, t) * tangent.w; - - vary_mat0 = vec3(t.x, b.x, n.x); - vary_mat1 = vec3(t.y, b.y, n.y); - vary_mat2 = vec3(t.z, b.z, n.z); - - gl_Position = projection_matrix*vec4(pos, 1.0); - vertex_color = diffuse_color; -} diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl index 9f9749394e..d90891aa20 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl @@ -39,16 +39,32 @@ VARYING vec3 vary_mat2; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; +#endif + void main() { //transform vertex +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; + gl_Position = projection_matrix*vec4(pos, 1.0); + + vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz); + vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz); +#else gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vec3 n = normalize(normal_matrix * normal); vec3 t = normalize(normal_matrix * tangent.xyz); +#endif + vec3 b = cross(n, t) * tangent.w; - + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + vary_mat0 = vec3(t.x, b.x, n.x); vary_mat1 = vec3(t.y, b.y, n.y); vary_mat2 = vec3(t.z, b.z, n.z); diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl index 3c026796c8..d64bcefade 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl @@ -39,14 +39,28 @@ VARYING vec2 vary_texcoord0; void passTextureIndex(); +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; +#endif + void main() { - //transform vertex +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vec4(position.xyz, 1.0); + gl_Position = projection_matrix * pos; + vary_normal = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); +#else gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vary_normal = normalize(normal_matrix * normal); +#endif + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; passTextureIndex(); - vary_normal = normalize(normal_matrix * normal); - + vertex_color = diffuse_color; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl index 5e4f08b017..08b1147ab0 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveV.glsl @@ -40,15 +40,26 @@ vec3 atmosAffectDirectionalLight(float lightIntensity); VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +#endif void main() { //transform vertex - vec4 vert = vec4(position.xyz, 1.0); - vec4 pos = (modelview_matrix * vert); passTextureIndex(); - gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + + vec4 pos = mat * vec4(position.xyz, 1.0); + gl_Position = projection_matrix * pos; +#else + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0)); +#endif vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl index 8f6eb79668..2c139430e7 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl @@ -25,7 +25,6 @@ uniform mat3 normal_matrix; uniform mat4 texture_matrix0; -uniform mat4 texture_matrix1; uniform mat4 modelview_matrix; uniform mat4 modelview_projection_matrix; @@ -47,19 +46,32 @@ VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; VARYING vec4 vary_position; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +#endif + void main() { //transform vertex vec4 vert = vec4(position.xyz,1.0); passTextureIndex(); + +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vert; + vary_position = gl_Position = projection_matrix * pos; + vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); +#else vec4 pos = (modelview_matrix * vert); vary_position = gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); - vec3 norm = normalize(normal_matrix * normal); +#endif vec3 ref = reflect(pos.xyz, -norm); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz; + vary_texcoord1 = transpose(normal_matrix) * ref.xyz; calcAtmospherics(pos.xyz); diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl index bdf3546aa5..e71636f2c9 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl @@ -45,15 +45,26 @@ VARYING vec3 vary_position; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +#endif void main() { //transform vertex vec4 vert = vec4(position.xyz, 1.0); - vec4 pos = (modelview_matrix * vert); passTextureIndex(); +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vert; + gl_Position = projection_matrix * pos; +#else + vec4 pos = (modelview_matrix * vert); gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); +#endif #ifdef WATER_FOG vary_position = pos.xyz; diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl index eb6e56e718..a58cc3d12d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl @@ -54,8 +54,7 @@ void main() vec4 norm = texture2D(normalMap, vary_texcoord0.xy); vec4 spec = texture2D(specularMap, vary_texcoord0.xy); - col.rgb = linear_to_srgb(col.rgb); frag_data[0] = vec4(col.rgb, 0.0); frag_data[1] = spec; - frag_data[2] = vec4(norm.xy,0,0); + frag_data[2] = norm; } diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl index e1f7031af6..02d83925ea 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl @@ -91,6 +91,14 @@ float getAmbientClamp(); vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, inout float glare, float ambiance) { + // SL-14895 inverted attenuation work-around + // This routine is tweaked to match deferred lighting, but previously used an inverted la value. To reconstruct + // that previous value now that the inversion is corrected, we reverse the calculations in LLPipeline::setupHWLights() + // to recover the `adjusted_radius` value previously being sent as la. + float falloff_factor = (12.0 * fa) - 9.0; + float inverted_la = falloff_factor / la; + // Yes, it makes me want to cry as well. DJH + vec3 col = vec3(0); //get light vector @@ -100,9 +108,9 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spe float dist = length(lv); float da = 1.0; - dist /= la; + dist /= inverted_la; - if (dist > 0.0 && la > 0.0) + if (dist > 0.0 && inverted_la > 0.0) { //normalize light vector lv = normalize(lv); diff --git a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl index d0c06cd51f..7a941674b8 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/normgenF.glsl @@ -43,18 +43,18 @@ uniform float norm_scale; void main() { - float alpha = texture2D(alphaMap, vary_texcoord0).a; + float c = texture2D(alphaMap, vary_texcoord0).r; - vec3 right = vec3(norm_scale, 0, (texture2D(alphaMap, vary_texcoord0+vec2(stepX, 0)).a-alpha)*255); - vec3 left = vec3(-norm_scale, 0, (texture2D(alphaMap, vary_texcoord0-vec2(stepX, 0)).a-alpha)*255); - vec3 up = vec3(0, -norm_scale, (texture2D(alphaMap, vary_texcoord0-vec2(0, stepY)).a-alpha)*255); - vec3 down = vec3(0, norm_scale, (texture2D(alphaMap, vary_texcoord0+vec2(0, stepY)).a-alpha)*255); + vec3 right = vec3(norm_scale, 0, (texture2D(alphaMap, vary_texcoord0+vec2(stepX, 0)).r-c)*255); + vec3 left = vec3(-norm_scale, 0, (texture2D(alphaMap, vary_texcoord0-vec2(stepX, 0)).r-c)*255); + vec3 up = vec3(0, -norm_scale, (texture2D(alphaMap, vary_texcoord0-vec2(0, stepY)).r-c)*255); + vec3 down = vec3(0, norm_scale, (texture2D(alphaMap, vary_texcoord0+vec2(0, stepY)).r-c)*255); vec3 norm = cross(right, down) + cross(down, left) + cross(left,up) + cross(up, right); norm = normalize(norm); norm *= 0.5; norm += 0.5; - - frag_color = vec4(norm, alpha); + + frag_color = vec4(norm, c); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl index 2487110624..2b17aea75a 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/diffuseSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskSkinnedV.glsl @@ -1,8 +1,9 @@ /** - * @file diffuseSkinnedV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * @file shadowAlphaMaskSkinnedV.glsl + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2007, Linden Research, Inc. + * Copyright (C) 2011, 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 @@ -22,38 +23,48 @@ * $/LicenseInfo$ */ -uniform mat4 projection_matrix; uniform mat4 texture_matrix0; uniform mat4 modelview_matrix; +uniform mat4 projection_matrix; +uniform float shadow_target_width; ATTRIBUTE vec3 position; ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec3 normal; ATTRIBUTE vec2 texcoord0; -VARYING vec3 vary_normal; +VARYING vec4 post_pos; +VARYING float target_pos_x; VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +void passTextureIndex(); + mat4 getObjectSkinnedTransform(); void main() { - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - + //transform vertex + vec4 pre_pos = vec4(position.xyz, 1.0); + mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; - vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; - vec4 norm = vec4(position.xyz, 1.0); - norm.xyz += normal.xyz; - norm.xyz = (mat*norm).xyz; - norm.xyz = normalize(norm.xyz-pos.xyz); + vec4 pos = mat * pre_pos; + pos = projection_matrix * pos; - vary_normal = norm.xyz; - - vertex_color = diffuse_color; + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + + post_pos = pos; + +#if !defined(DEPTH_CLAMP) + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif - gl_Position = projection_matrix*vec4(pos, 1.0); + passTextureIndex(); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; + vertex_color = diffuse_color; } diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl index df31b5a79f..bdf8e0854d 100644 --- a/indra/newview/app_settings/shaders/class1/objects/simpleSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowSkinnedV.glsl @@ -1,6 +1,7 @@ /** - * @file simpleSkinnedV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * @file shadowSkinnedV.glsl + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. * @@ -22,44 +23,30 @@ * $/LicenseInfo$ */ -uniform mat4 texture_matrix0; uniform mat4 modelview_matrix; uniform mat4 projection_matrix; ATTRIBUTE vec3 position; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; +VARYING vec4 post_pos; - -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); -void calcAtmospherics(vec3 inPositionEye); mat4 getObjectSkinnedTransform(); void main() { //transform vertex - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; - vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; - - vec4 norm = vec4(position.xyz, 1.0); - norm.xyz += normal.xyz; - norm.xyz = (mat*norm).xyz; - norm.xyz = normalize(norm.xyz-pos.xyz); - - calcAtmospherics(pos.xyz); + vec4 pos = (mat*vec4(position.xyz, 1.0)); + pos = projection_matrix*pos; + + post_pos = pos; + +#if !defined(DEPTH_CLAMP) + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); +#else + gl_Position = pos; +#endif - vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color); - vertex_color = color; - - gl_Position = projection_matrix*vec4(pos, 1.0); - - } diff --git a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl index 9064904191..d9ca6d3a46 100644 --- a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/treeShadowSkinnedV.glsl @@ -1,7 +1,7 @@ /** - * @file emissiveSkinnedV.glsl + * @file treeShadowV.glsl * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. * @@ -23,34 +23,31 @@ * $/LicenseInfo$ */ -uniform mat4 projection_matrix; uniform mat4 texture_matrix0; uniform mat4 modelview_matrix; - +uniform mat4 projection_matrix; + ATTRIBUTE vec3 position; -ATTRIBUTE vec4 emissive; ATTRIBUTE vec2 texcoord0; -VARYING vec4 vertex_color; +VARYING vec4 post_pos; VARYING vec2 vary_texcoord0; - -void calcAtmospherics(vec3 inPositionEye); mat4 getObjectSkinnedTransform(); void main() { //transform vertex - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - - mat4 mat = getObjectSkinnedTransform(); + mat4 mat = getObjectSkinnedTransform(); mat = modelview_matrix * mat; - vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; - vertex_color = emissive; - - calcAtmospherics(pos.xyz); - - gl_Position = projection_matrix*vec4(pos, 1.0); + vec4 pos = mat * vec4(position.xyz, 1.0); + pos = projection_matrix * pos; + + post_pos = pos; + + gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w); + + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; } diff --git a/indra/newview/app_settings/shaders/class1/interface/debugV.glsl b/indra/newview/app_settings/shaders/class1/interface/debugV.glsl index f4d704577a..153998f1d5 100644 --- a/indra/newview/app_settings/shaders/class1/interface/debugV.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/debugV.glsl @@ -27,8 +27,21 @@ uniform mat4 modelview_projection_matrix; ATTRIBUTE vec3 position; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; +#endif + void main() { +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vec4(position.xyz,1.0); + gl_Position = projection_matrix * pos; +#else gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); +#endif } diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl index 9bf7b60eb7..0b362cf46c 100644 --- a/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/highlightV.glsl @@ -31,10 +31,23 @@ ATTRIBUTE vec2 texcoord0; VARYING vec2 vary_texcoord0; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; +#endif + void main() { //transform vertex +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vec4(position.xyz,1.0); + gl_Position = projection_matrix * pos; +#else gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); +#endif vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; } diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl index eff75435a9..7305065a05 100644 --- a/indra/newview/app_settings/shaders/class1/objects/fullbrightSkinnedV.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/occlusionSkinnedV.glsl @@ -1,6 +1,7 @@ /** - * @file fullbrightSkinnedV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * @file occlusionSkinnedV.glsl + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2007, Linden Research, Inc. * @@ -23,35 +24,17 @@ */ uniform mat4 projection_matrix; -uniform mat4 texture_matrix0; uniform mat4 modelview_matrix; ATTRIBUTE vec3 position; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; -void calcAtmospherics(vec3 inPositionEye); mat4 getObjectSkinnedTransform(); -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; - - void main() { - //transform vertex - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - mat4 mat = getObjectSkinnedTransform(); - mat = modelview_matrix * mat; vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; - - calcAtmospherics(pos.xyz); - - vertex_color = diffuse_color; - gl_Position = projection_matrix*vec4(pos, 1.0); - - } + diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl index 5fcdf3107c..89be8195f0 100644 --- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl +++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl @@ -56,5 +56,6 @@ void fullbright_lighting() color.rgb = pow(color.rgb, vec3(1.0/texture_gamma)); frag_color = color; + } diff --git a/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl b/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl index a7738087dc..ee9970bc70 100644 --- a/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/bumpV.glsl @@ -33,10 +33,23 @@ ATTRIBUTE vec2 texcoord1; VARYING vec2 vary_texcoord0; VARYING vec2 vary_texcoord1; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +uniform mat4 modelview_matrix; +#endif + void main() { //transform vertex +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vec4(position.xyz, 1.0); + gl_Position = projection_matrix * pos; +#else gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); +#endif vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; vary_texcoord1 = (texture_matrix0 * vec4(texcoord1,0,1)).xy; } diff --git a/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl b/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl index e984deb0c8..d762239e51 100644 --- a/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/emissiveV.glsl @@ -37,20 +37,30 @@ VARYING vec2 vary_texcoord0; void calcAtmospherics(vec3 inPositionEye); - - +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +#endif void main() { //transform vertex passTextureIndex(); + +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + + vec4 pos = mat * vec4(position.xyz, 1.0); + gl_Position = projection_matrix * pos; +#else gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0)); +#endif vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0)); + calcAtmospherics(pos.xyz); vertex_color = emissive; - - } diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl deleted file mode 100644 index 1e244d9dfd..0000000000 --- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinySkinnedV.glsl +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @file shinySimpleSkinnedV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 texture_matrix0; -uniform mat4 texture_matrix1; -uniform mat4 modelview_matrix; -uniform mat4 projection_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; - -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; -VARYING vec3 vary_texcoord1; -VARYING vec4 vary_position; - - -void calcAtmospherics(vec3 inPositionEye); -mat4 getObjectSkinnedTransform(); - -void main() -{ - mat4 mat = getObjectSkinnedTransform(); - - mat = modelview_matrix * mat; - vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; - - mat4 mvp = modelview_matrix * projection_matrix; - vary_position = mvp * vec4(position, 1.0); - - vec4 norm = vec4(position.xyz, 1.0); - norm.xyz += normal.xyz; - norm.xyz = (mat*norm).xyz; - norm.xyz = normalize(norm.xyz-pos.xyz); - - vec3 ref = reflect(pos.xyz, -norm.xyz); - - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz; - - calcAtmospherics(pos.xyz); - - vertex_color = diffuse_color; - - gl_Position = projection_matrix*vec4(pos, 1.0); - - -} diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl index 34bd8d445a..ace2574ac2 100644 --- a/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightShinyV.glsl @@ -25,7 +25,6 @@ uniform mat3 normal_matrix; uniform mat4 texture_matrix0; -uniform mat4 texture_matrix1; uniform mat4 modelview_matrix; uniform mat4 modelview_projection_matrix; @@ -46,20 +45,32 @@ VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; VARYING vec3 vary_texcoord1; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +#endif void main() { //transform vertex vec4 vert = vec4(position.xyz,1.0); passTextureIndex(); + +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vert; + gl_Position = projection_matrix * pos; + vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); +#else vec4 pos = (modelview_matrix * vert); gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); - vec3 norm = normalize(normal_matrix * normal); +#endif vec3 ref = reflect(pos.xyz, -norm); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz; + vary_texcoord1 = transpose(normal_matrix) * ref; calcAtmospherics(pos.xyz); diff --git a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl index fc20d3270e..5af42f1fcf 100644 --- a/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/fullbrightV.glsl @@ -33,26 +33,33 @@ ATTRIBUTE vec2 texcoord0; ATTRIBUTE vec3 normal; ATTRIBUTE vec4 diffuse_color; - void calcAtmospherics(vec3 inPositionEye); - VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +#endif void main() { //transform vertex vec4 vert = vec4(position.xyz,1.0); passTextureIndex(); - vec4 pos = (modelview_matrix * vert); +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vert; + gl_Position = projection_matrix * pos; +#else + vec4 pos = (modelview_matrix * vert); gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); +#endif vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; calcAtmospherics(pos.xyz); vertex_color = diffuse_color; - - } diff --git a/indra/llcommon/timing.cpp b/indra/newview/app_settings/shaders/class1/objects/previewPhysicsF.glsl index c2dc695ef3..3a5e6fdf7c 100644 --- a/indra/llcommon/timing.cpp +++ b/indra/newview/app_settings/shaders/class1/objects/previewPhysicsF.glsl @@ -1,10 +1,9 @@ /** - * @file timing.cpp - * @brief This file will be deprecated in the future. + * @file previewPhysicsF.glsl * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * Copyright (C) 2022, 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 @@ -23,3 +22,21 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; +uniform vec4 color; + +VARYING vec2 vary_texcoord0; + +//==================================================================================================== + +void main() +{ + frag_color = texture2D(diffuseMap,vary_texcoord0.xy) * color; +} diff --git a/indra/newview/app_settings/shaders/class1/objects/previewPhysicsV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewPhysicsV.glsl new file mode 100644 index 0000000000..913dec83bd --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/objects/previewPhysicsV.glsl @@ -0,0 +1,42 @@ +/** + * @file previewPhysicsV.glsl + * + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2022, 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$ + */ + +uniform mat4 texture_matrix0; +uniform mat4 modelview_matrix; +uniform mat4 modelview_projection_matrix; + +ATTRIBUTE vec3 position; +ATTRIBUTE vec2 texcoord0; + +VARYING vec2 vary_texcoord0; + +//==================================================================================================== + +void main() +{ + //transform vertex + gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; +} diff --git a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl deleted file mode 100644 index 727bae19c0..0000000000 --- a/indra/newview/app_settings/shaders/class1/objects/shinySimpleSkinnedV.glsl +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file shinySimpleSkinnedV.glsl - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2007, 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$ - */ - -uniform mat4 projection_matrix; -uniform mat4 texture_matrix0; -uniform mat4 texture_matrix1; -uniform mat4 modelview_matrix; - -ATTRIBUTE vec3 position; -ATTRIBUTE vec3 normal; -ATTRIBUTE vec4 diffuse_color; -ATTRIBUTE vec2 texcoord0; - -VARYING vec4 vertex_color; -VARYING vec2 vary_texcoord0; -VARYING vec3 vary_texcoord1; - -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color); -void calcAtmospherics(vec3 inPositionEye); -mat4 getObjectSkinnedTransform(); - -void main() -{ - mat4 mat = getObjectSkinnedTransform(); - - mat = modelview_matrix * mat; - vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz; - - vec4 norm = vec4(position.xyz, 1.0); - norm.xyz += normal.xyz; - norm.xyz = (mat*norm).xyz; - norm.xyz = normalize(norm.xyz-pos.xyz); - - vec3 ref = reflect(pos.xyz, -norm.xyz); - - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz; - - calcAtmospherics(pos.xyz); - - vec4 color = calcLighting(pos.xyz, norm.xyz, diffuse_color); - vertex_color = color; - - gl_Position = projection_matrix*vec4(pos, 1.0); -} diff --git a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl index 4ba8194d03..097e42d233 100644 --- a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl @@ -25,7 +25,6 @@ uniform mat3 normal_matrix; uniform mat4 texture_matrix0; -uniform mat4 texture_matrix1; uniform mat4 modelview_matrix; uniform mat4 modelview_projection_matrix; @@ -45,19 +44,32 @@ void calcAtmospherics(vec3 inPositionEye); uniform vec4 origin; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +#endif + void main() { //transform vertex vec4 vert = vec4(position.xyz,1.0); passTextureIndex(); + +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * vert; + gl_Position = projection_matrix * pos; + vec3 norm = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz); +#else vec4 pos = (modelview_matrix * vert); gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); - vec3 norm = normalize(normal_matrix * normal); +#endif vec3 ref = reflect(pos.xyz, -norm); - vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz; + vary_texcoord0 = (texture_matrix0*vec4(texcoord0,0,1)).xy; + vary_texcoord1 = transpose(normal_matrix) * ref; calcAtmospherics(pos.xyz); diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl index 9ef7704b70..2025174f7d 100644 --- a/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/simpleV.glsl @@ -44,12 +44,16 @@ void calcAtmospherics(vec3 inPositionEye); VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +#ifdef HAS_SKIN +mat4 getObjectSkinnedTransform(); +uniform mat4 projection_matrix; +#endif + void main() { //transform vertex vec4 vert = vec4(position.xyz,1.0); - gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); passTextureIndex(); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0, 0, 1)).xy; @@ -58,11 +62,23 @@ void main() if (no_atmo == 1) { vertex_color = diffuse_color; + gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); } else { +#ifdef HAS_SKIN + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + + vec4 pos = mat * vert; + vec3 norm = normalize((mat*vec4(normal.xyz+vert.xyz,1.0)).xyz-pos.xyz); + + gl_Position = projection_matrix * pos; +#else vec4 pos = (modelview_matrix * vert); vec3 norm = normalize(normal_matrix * normal); + gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0); +#endif calcAtmospherics(pos.xyz); diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml index eb2cd356d9..8462df207b 100644 --- a/indra/newview/app_settings/ultra_graphics.xml +++ b/indra/newview/app_settings/ultra_graphics.xml @@ -6,8 +6,6 @@ <RenderAvatarLODFactor value="1.0"/> <!--Default for now--> <RenderAvatarPhysicsLODFactor value="1.0"/> - <!--NO SHADERS--> - <RenderAvatarVP value="TRUE"/> <!--Short Range--> <RenderFarClip value="256"/> <!--Default for now--> diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index f1bf8d76c2..1ccde98283 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -1,4 +1,4 @@ -version 33 +version 34 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -70,37 +70,9 @@ RenderShadowDetail 1 2 RenderUseStreamVBO 1 1 RenderFSAASamples 1 16 RenderMaxTextureIndex 1 16 +RenderGLContextCoreProfile 1 1 +RenderGLMultiThreaded 1 1 -// -// Low Graphics Settings (fixed function) -// -list LowFixedFunction -RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 -RenderAvatarLODFactor 1 0 -RenderAvatarPhysicsLODFactor 1 0 -RenderAvatarMaxNonImpostors 1 3 -RenderAvatarMaxComplexity 1 25000 -RenderAvatarVP 1 0 -RenderFarClip 1 64 -RenderFlexTimeFactor 1 0 -RenderGlowResolutionPow 1 8 -RenderLocalLights 1 0 -RenderMaxPartCount 1 0 -RenderObjectBump 1 0 -RenderReflectionDetail 1 0 -RenderTerrainDetail 1 0 -RenderTerrainLODFactor 1 1 -RenderTransparentWater 1 0 -RenderTreeLODFactor 1 0 -RenderVolumeLODFactor 1 1.125 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderUseAdvancedAtmospherics 1 0 -RenderShadowDetail 1 0 -WLSkyDetail 1 48 -RenderFSAASamples 1 0 // // Low Graphics Settings @@ -112,7 +84,6 @@ RenderAvatarLODFactor 1 0 RenderAvatarPhysicsLODFactor 1 0 RenderAvatarMaxNonImpostors 1 3 RenderAvatarMaxComplexity 1 35000 -RenderAvatarVP 1 0 RenderFarClip 1 64 RenderFlexTimeFactor 1 0 RenderGlowResolutionPow 1 8 @@ -142,7 +113,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0.5 RenderAvatarMaxComplexity 1 100000 RenderAvatarPhysicsLODFactor 1 0.75 -RenderAvatarVP 1 1 RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 @@ -172,7 +142,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 200000 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -202,7 +171,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 250000 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -232,7 +200,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 300000 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -262,7 +229,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 350000 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -291,7 +257,6 @@ RenderAnisotropic 1 1 RenderAvatarCloth 1 1 RenderAvatarLODFactor 1 1.0 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 256 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -316,414 +281,45 @@ RenderFSAASamples 1 2 // Class Unknown Hardware (unknown) // list Unknown -RenderVBOEnable 1 0 RenderShadowDetail 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 // -// Class 0 Hardware (just old) -// -list Class0 -RenderVBOEnable 1 1 - -// -// Class 1 Hardware -// -list Class1 -RenderVBOEnable 1 1 - -// -// Class 2 Hardware -// -list Class2 -RenderVBOEnable 1 1 - -// -// Class 3 Hardware -// -list Class3 -RenderVBOEnable 1 1 - -// -// Class 4 Hardware -// -list Class4 -RenderVBOEnable 1 1 - -// -// Class 5 Hardware -// -list Class5 -RenderVBOEnable 1 1 - -// // VRAM > 512MB // list VRAMGT512 RenderCompressTextures 1 0 // -// No Pixel Shaders available -// -list NoPixelShaders -RenderAvatarVP 0 0 -RenderAvatarCloth 0 0 -RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderShadowDetail 0 0 -RenderUseAdvancedAtmospherics 0 0 - -// -// No Vertex Shaders available -// -list NoVertexShaders -RenderAvatarVP 0 0 -RenderAvatarCloth 0 0 -RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderShadowDetail 0 0 -RenderUseAdvancedAtmospherics 0 0 - -// -// GL_ARB_map_buffer_range exists -// -list MapBufferRange -RenderVBOMappingDisable 1 1 - - -// // "Default" setups for safe, low, medium, high // list safe RenderAnisotropic 1 0 RenderAvatarCloth 0 0 -RenderAvatarVP 0 0 RenderAvatarMaxNonImpostors 1 16 RenderAvatarMaxComplexity 1 80000 RenderObjectBump 0 0 RenderLocalLights 1 0 RenderMaxPartCount 1 1024 RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 RenderReflectionDetail 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 RenderDeferredSSAO 0 0 RenderShadowDetail 0 0 -// -// CPU based feature masks -// - -// 1Ghz or less (equiv) -list CPUSlow -RenderMaxPartCount 1 1024 - -// -// RAM based feature masks -// -list RAM256MB -RenderObjectBump 0 0 - -// -// Graphics card based feature masks -// -list OpenGLPre15 -RenderVBOEnable 1 0 - -list OpenGLPre30 -RenderDeferred 0 0 -RenderMaxTextureIndex 1 1 - list Intel RenderAnisotropic 1 0 -RenderVBOEnable 1 0 RenderFSAASamples 1 0 +RenderGLMultiThreaded 1 0 +RenderGLContextCoreProfile 1 0 -list GeForce2 -RenderAnisotropic 1 0 -RenderMaxPartCount 1 2048 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 1 - -list SiS -UseOcclusion 0 0 - - -list Intel_830M -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_845G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_855GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_865G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_900 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_915GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_915G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_945GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_945G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_950 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_965 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -UseOcclusion 0 0 - -list Intel_G33 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_G45 -WindLightUseAtmosShaders 0 0 - -list Intel_Bear_Lake -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Broadwater -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Brookdale -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Eaglelake -WindLightUseAtmosShaders 0 0 - -list Intel_Montara -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Springdale -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - - -list ATI_FireGL_5200 -RenderVBOEnable 1 0 -WindLightUseAtmosShaders 0 0 - - -list ATI_Mobility_Radeon_7xxx -RenderVBOEnable 0 0 - -list ATI_Radeon_7xxx -RenderVBOEnable 0 0 - -list ATI_All-in-Wonder_Radeon -RenderVBOEnable 0 0 - -list ATI_All-in-Wonder_7500 -RenderVBOEnable 0 0 - -list ATI_Mobility_Radeon_9600 -Disregard96DefaultDrawDistance 1 0 - - -/// tweaked ATI to 96 Draw distance - -list ATI_Radeon_9000 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9200 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9500 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9600 -Disregard96DefaultDrawDistance 1 0 - -/// tweaked ATI to 128 draw distance - -list ATI_Radeon_X300 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X400 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X500 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X600 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X700 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X1300 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -UseStartScreen 0 0 -list ATI_Radeon_X1400 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X1500 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -UseStartScreen 0 0 -list ATI_Radeon_X1600 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Radeon_X1700 -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 -list ATI_Mobility_Radeon_X1xxx -Disregard128DefaultDrawDistance 1 0 -RenderVBOEnable 1 0 - -list ATI_Radeon_HD_2300 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_HD_2400 -Disregard128DefaultDrawDistance 1 0 -list ATI_ASUS_AH24xx -Disregard128DefaultDrawDistance 1 0 - - -// Avatar hardware skinning causes invisible avatars -// on various ATI chipsets on drivers before 8.2 - -list ATIOldDriver -RenderAvatarVP 0 0 -RenderAvatarCloth 0 0 -RenderVBOEnable 1 0 - -// ATI cards generally perform better when not using VBOs for streaming data - -list ATI +// AMD cards generally perform better when not using VBOs for streaming data +// AMD cards also prefer an OpenGL Compatibility Profile Context +list AMD RenderUseStreamVBO 1 0 +RenderGLContextCoreProfile 1 0 -// Disable vertex buffer objects by default for ATI cards with little video memory -list ATIVramLT256 -RenderVBOEnable 1 0 - -/// Tweaked NVIDIA - -list NVIDIA_GeForce_FX_5100 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5200 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5500 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5600 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_FX_Go5100 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5200 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5300 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5500 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5600 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_6100 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6200 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6500 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6600 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_G73 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_Go_6100 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6200 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6500 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6600 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6700 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6800 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_7000 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7100 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7200 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7300 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7400 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7500 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7600 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7700 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7800 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_7900 -RenderShaderLightingMaxLevel 1 2 - -list NVIDIA_GeForce_Go_7200 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7300 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7300_LE -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7400 -Disregard128DefaultDrawDistance 1 0 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7600 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7700 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7800 -RenderShaderLightingMaxLevel 1 2 -list NVIDIA_GeForce_Go_7900 -RenderShaderLightingMaxLevel 1 2 diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index bac6fd5708..c9efd89cc8 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -1,4 +1,4 @@ -version 37 +version 38 // The version number above should be incremented IF AND ONLY IF some // change has been made that is sufficiently important to justify // resetting the graphics preferences of all users to the recommended @@ -70,37 +70,8 @@ RenderShadowDetail 1 2 RenderUseStreamVBO 1 1 RenderFSAASamples 1 16 RenderMaxTextureIndex 1 16 - -// -// Low Graphics Settings (fixed function) -// -list LowFixedFunction -RenderAnisotropic 1 0 -RenderAvatarCloth 1 0 -RenderAvatarLODFactor 1 0 -RenderAvatarPhysicsLODFactor 1 0 -RenderAvatarMaxNonImpostors 1 3 -RenderAvatarMaxComplexity 1 25000 -RenderAvatarVP 1 0 -RenderFarClip 1 64 -RenderFlexTimeFactor 1 0 -RenderGlowResolutionPow 1 8 -RenderLocalLights 1 0 -RenderMaxPartCount 1 0 -RenderObjectBump 1 0 -RenderReflectionDetail 1 0 -RenderTerrainDetail 1 0 -RenderTerrainLODFactor 1 1 -RenderTransparentWater 1 0 -RenderTreeLODFactor 1 0 -RenderVolumeLODFactor 1 0.5 -WindLightUseAtmosShaders 1 0 -RenderDeferred 1 0 -RenderDeferredSSAO 1 0 -RenderUseAdvancedAtmospherics 1 0 -RenderShadowDetail 1 0 -WLSkyDetail 1 48 -RenderFSAASamples 1 0 +RenderGLContextCoreProfile 1 0 +RenderGLMultiThreaded 1 0 // // Low Graphics Settings @@ -112,7 +83,6 @@ RenderAvatarLODFactor 1 0 RenderAvatarPhysicsLODFactor 1 0 RenderAvatarMaxNonImpostors 1 3 RenderAvatarMaxComplexity 1 35000 -RenderAvatarVP 1 0 RenderFarClip 1 64 RenderFlexTimeFactor 1 0 RenderGlowResolutionPow 1 8 @@ -142,7 +112,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 0.5 RenderAvatarMaxComplexity 1 100000 RenderAvatarPhysicsLODFactor 1 0.75 -RenderAvatarVP 1 1 RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 @@ -172,7 +141,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 200000 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -202,7 +170,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 250000 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -232,7 +199,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 300000 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -262,7 +228,6 @@ RenderAvatarCloth 1 0 RenderAvatarLODFactor 1 1.0 RenderAvatarMaxComplexity 1 350000 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -291,7 +256,6 @@ RenderAnisotropic 1 1 RenderAvatarCloth 1 1 RenderAvatarLODFactor 1 1.0 RenderAvatarPhysicsLODFactor 1 1.0 -RenderAvatarVP 1 1 RenderFarClip 1 256 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -316,73 +280,11 @@ RenderFSAASamples 1 2 // Class Unknown Hardware (unknown) // list Unknown -RenderVBOEnable 1 0 RenderShadowDetail 1 0 RenderDeferred 1 0 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 -// -// Class 0 Hardware (just old) -// -list Class0 -RenderVBOEnable 1 1 - -// -// Class 1 Hardware -// -list Class1 -RenderVBOEnable 1 1 - -// -// Class 2 Hardware -// -list Class2 -RenderVBOEnable 1 1 - -// -// Class 3 Hardware -// -list Class3 -RenderVBOEnable 1 1 - -// -// Class 4 Hardware -// -list Class4 -RenderVBOEnable 1 1 - -// -// Class 5 Hardware -// -list Class5 -RenderVBOEnable 1 1 - -// -// No Pixel Shaders available -// -list NoPixelShaders -RenderAvatarVP 0 0 -RenderAvatarCloth 0 0 -RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderUseAdvancedAtmospherics 0 0 -RenderShadowDetail 0 0 - -// -// No Vertex Shaders available -// -list NoVertexShaders -RenderAvatarVP 0 0 -RenderAvatarCloth 0 0 -RenderReflectionDetail 0 0 -WindLightUseAtmosShaders 0 0 -RenderDeferred 0 0 -RenderDeferredSSAO 0 0 -RenderUseAdvancedAtmospherics 0 0 -RenderShadowDetail 0 0 // // VRAM > 512MB @@ -396,14 +298,12 @@ RenderCompressTextures 1 0 list safe RenderAnisotropic 1 0 RenderAvatarCloth 0 0 -RenderAvatarVP 0 0 RenderAvatarMaxNonImpostors 1 16 RenderAvatarMaxComplexity 1 80000 RenderObjectBump 0 0 RenderLocalLights 1 0 RenderMaxPartCount 1 1024 RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 RenderReflectionDetail 0 0 WindLightUseAtmosShaders 0 0 RenderDeferred 0 0 @@ -411,31 +311,10 @@ RenderDeferredSSAO 0 0 RenderUseAdvancedAtmospherics 0 0 RenderShadowDetail 0 0 -// -// CPU based feature masks -// - -// 1Ghz or less (equiv) -list CPUSlow -RenderMaxPartCount 1 1024 - -// -// RAM based feature masks -// -list RAM256MB -RenderObjectBump 0 0 - -// -// Graphics card based feature masks -// -list OpenGLPre15 -RenderVBOEnable 1 0 - - list TexUnit8orLess RenderDeferredSSAO 0 0 -list ATI +list AMD RenderDeferredSSAO 1 0 list Intel @@ -443,195 +322,6 @@ RenderAnisotropic 1 0 RenderLocalLights 1 0 RenderFSAASamples 1 0 -list GeForce2 -RenderAnisotropic 1 0 -RenderLocalLights 1 0 -RenderMaxPartCount 1 2048 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 1 - -list Intel_830M -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_845G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_855GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_865G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_900 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_915GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_915G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_945GM -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_945G -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_950 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -RenderGround 1 0 - -list Intel_965 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 -UseOcclusion 0 0 - -list Intel_G33 -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Bear_Lake -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Broadwater -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Brookdale -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_X3100 -WindLightUseAtmosShaders 0 0 - -list Intel_Montara -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list Intel_Springdale -RenderTerrainDetail 1 0 -RenderVBOEnable 1 0 - -list ATI_Mobility_Radeon_9600 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_8600 -RenderTextureMemoryMultiple 1 1 -UseOcclusion 0 0 - -/// tweaked ATI to 96 Draw distance - -list ATI_Radeon_9000 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9200 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9500 -Disregard96DefaultDrawDistance 1 0 -list ATI_Radeon_9600 -Disregard96DefaultDrawDistance 1 0 - -/// tweaked ATI to 128 draw distance - -list ATI_Radeon_X300 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X400 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X500 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X600 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X700 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X1300 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X1400 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X1500 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X1600 -Disregard128DefaultDrawDistance 1 0 -list ATI_Radeon_X1700 -Disregard128DefaultDrawDistance 1 0 -list ATI_Mobility_Radeon_X1xxx -Disregard128DefaultDrawDistance 1 0 - -/// Tweaked NVIDIA - -list NVIDIA_GeForce_FX_5100 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5200 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_5500 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_FX_Go5100 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5200 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5300 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5500 -Disregard96DefaultDrawDistance 1 0 -list NVIDIA_GeForce_FX_Go5600 -Disregard96DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_6100 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6200 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6500 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_6600 -Disregard128DefaultDrawDistance 1 0 - - -list NVIDIA_GeForce_Go_6100 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6200 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6500 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6600 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6700 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6800 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_6 -RenderVBOEnable 1 0 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_7200 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_7300 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_7400 -Disregard128DefaultDrawDistance 1 0 - -list NVIDIA_GeForce_Go_7200 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_7300 -Disregard128DefaultDrawDistance 1 0 -list NVIDIA_GeForce_Go_7400 -Disregard128DefaultDrawDistance 1 0 - list OSX_10_6_8 RenderDeferred 0 0 diff --git a/indra/newview/licenses-mac.txt b/indra/newview/licenses-mac.txt index d0747ccd03..fba6a55da3 100644 --- a/indra/newview/licenses-mac.txt +++ b/indra/newview/licenses-mac.txt @@ -693,3 +693,29 @@ From Vivox: Attn: customer support 40 Speen Street Suite 402 Framingham, MA 01701 + + +============= +meshoptimizer +============= +MIT License + +Copyright (c) 2016-2021 Arseny Kapoulkine + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt index 98edd35bea..837d92139d 100644 --- a/indra/newview/licenses-win32.txt +++ b/indra/newview/licenses-win32.txt @@ -770,71 +770,29 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ============= -GLOD license +meshoptimizer ============= -The GLOD Open-Source License Version 1.0 June 16, 2004 +MIT License -Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns -Hopkins University and David Luebke, Brenden Schubert, University of -Virginia. All rights reserved. +Copyright (c) 2016-2021 Arseny Kapoulkine -Redistribution and use in source and binary forms, with or without -modification, is permitted provided that the following conditions are -met: +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer and - request. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer and - request in the documentation and/or other materials provided with - the distribution. - -3. The name "GLOD" must not be used to endorse or promote products - derived from this software without prior written permission. - -4. Redistributions of any modified version of this source, whether in - source or binary form , must include a form of the following - acknowledgment: "This product is derived from the GLOD library, - which is available from http://www.cs.jhu.edu/~graphics/GLOD." - -5. Redistributions of any modified version of this source in binary - form must provide, free of charge, access to the modified version - of the code. - -6. This license shall be governed by and construed and enforced in - accordance with the laws of the State of Maryland, without - reference to its conflicts of law provisions. The exclusive - jurisdiction and venue for all legal actions relating to this - license shall be in courts of competent subject matter jurisdiction - located in the State of Maryland. - -TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED -UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND, -EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES -THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR -PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE -ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH -YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE -COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY -NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY -CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS -AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - -TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL -THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY -SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF -PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS. - -YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE -COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS, -DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM -YOUR ACCEPTANCE AND USE OF GLOD. - -Although NOT REQUIRED, we would appreciate it if active users of GLOD -put a link on their web site to the GLOD web site when possible. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index d5d0d044c0..b79af04c36 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -1481,7 +1481,7 @@ void LLAgent::resetControlFlags() //----------------------------------------------------------------------------- void LLAgent::setAFK() { - if (!gAgent.getRegion()) + if (gNonInteractive || !gAgent.getRegion()) { // Don't set AFK if we're not talking to a region yet. return; diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index ed6c3c307f..84a41113be 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -210,9 +210,6 @@ void LLAgentCamera::init() mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType"); - mCameraOffsetInitial = gSavedSettings.getControl("CameraOffsetRearView"); - mFocusOffsetInitial = gSavedSettings.getControl("FocusOffsetRearView"); - mCameraCollidePlane.clearVec(); mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale"); mTargetCameraDistance = mCurrentCameraDistance; @@ -1672,8 +1669,8 @@ LLVector3d LLAgentCamera::calcThirdPersonFocusOffset() agent_rot *= ((LLViewerObject*)(gAgentAvatarp->getParent()))->getRenderRotation(); } - focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, ""); - return focus_offset * agent_rot; + static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d()); + return focus_offset_initial * agent_rot; } void LLAgentCamera::setupSitCamera() @@ -1810,8 +1807,9 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit) } else { - local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale"); - + static LLCachedControl<F32> camera_offset_scale(gSavedSettings, "CameraOffsetScale"); + local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * camera_offset_scale; + // are we sitting down? if (isAgentAvatarValid() && gAgentAvatarp->getParent()) { @@ -2028,12 +2026,15 @@ bool LLAgentCamera::isJoystickCameraUsed() LLVector3 LLAgentCamera::getCameraOffsetInitial() { - return convert_from_llsd<LLVector3>(mCameraOffsetInitial->get(), TYPE_VEC3, ""); + // getCameraOffsetInitial and getFocusOffsetInitial can be called on update from idle before init() + static LLCachedControl<LLVector3> camera_offset_initial (gSavedSettings, "CameraOffsetRearView", LLVector3()); + return camera_offset_initial; } LLVector3d LLAgentCamera::getFocusOffsetInitial() { - return convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, ""); + static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d()); + return focus_offset_initial; } F32 LLAgentCamera::getCameraMaxZoomDistance() diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index ec1ed433d7..89680f95dc 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -131,12 +131,6 @@ private: /** Camera preset in Third Person Mode */ ECameraPreset mCameraPreset; - /** Initial camera offset */ - LLPointer<LLControlVariable> mCameraOffsetInitial; - - /** Initial focus offset */ - LLPointer<LLControlVariable> mFocusOffsetInitial; - LLQuaternion mInitSitRot; //-------------------------------------------------------------------- diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 0c4874ef11..a63203f3cb 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -91,7 +91,6 @@ #include "llsdutil_math.h" #include "lllocationhistory.h" #include "llfasttimerview.h" -#include "lltelemetry.h" #include "llvector4a.h" #include "llviewermenufile.h" #include "llvoicechannel.h" @@ -233,11 +232,12 @@ #include "llavatariconctrl.h" #include "llgroupiconctrl.h" #include "llviewerassetstats.h" +#include "workqueue.h" +using namespace LL; // Include for security api initialization #include "llsecapi.h" #include "llmachineid.h" -#include "llmainlooprepeater.h" #include "llcleanup.h" #include "llcoproceduremanager.h" @@ -363,6 +363,10 @@ BOOL gLogoutInProgress = FALSE; BOOL gSimulateMemLeak = FALSE; +// We don't want anyone, especially threads working on the graphics pipeline, +// to have to block due to this WorkQueue being full. +WorkQueue gMainloopWork("mainloop", 1024*1024); + //////////////////////////////////////////////////////////// // Internal globals... that should be removed. static std::string gArgs; @@ -378,42 +382,6 @@ static std::string gLaunchFileOnQuit; // Used on Win32 for other apps to identify our window (eg, win_setup) const char* const VIEWER_WINDOW_CLASSNAME = "Second Life"; -//-- LLDeferredTaskList ------------------------------------------------------ - -/** - * A list of deferred tasks. - * - * We sometimes need to defer execution of some code until the viewer gets idle, - * e.g. removing an inventory item from within notifyObservers() may not work out. - * - * Tasks added to this list will be executed in the next LLAppViewer::idle() iteration. - * All tasks are executed only once. - */ -class LLDeferredTaskList: public LLSingleton<LLDeferredTaskList> -{ - LLSINGLETON_EMPTY_CTOR(LLDeferredTaskList); - LOG_CLASS(LLDeferredTaskList); - - friend class LLAppViewer; - typedef boost::signals2::signal<void()> signal_t; - - void addTask(const signal_t::slot_type& cb) - { - mSignal.connect(cb); - } - - void run() - { - if (!mSignal.empty()) - { - mSignal(); - mSignal.disconnect_all_slots(); - } - } - - signal_t mSignal; -}; - //---------------------------------------------------------------------------- // List of entries from strings.xml to always replace @@ -564,7 +532,7 @@ static void settings_to_globals() LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize")); - LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile"); + LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile"); LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport"); LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic"); @@ -598,14 +566,14 @@ static void settings_to_globals() static void settings_modify() { - LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); - LLPipeline::sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); - LLPipeline::sRenderDeferred = LLPipeline::sRenderTransparentWater && LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred"); - LLRenderTarget::sUseFBO = LLPipeline::sRenderDeferred && gSavedSettings.getBOOL("RenderAvatarVP"); - LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); - LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4] - gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession; - gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline"); + LLPipeline::sRenderTransparentWater = gSavedSettings.getBOOL("RenderTransparentWater"); + LLPipeline::sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); + LLPipeline::sRenderDeferred = LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred"); + LLRenderTarget::sUseFBO = LLPipeline::sRenderDeferred; + LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); + LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; // square lod factor to get exponential range of [1,4] + gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession; + gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline"); } class LLFastTimerLogThread : public LLThread @@ -669,6 +637,7 @@ LLAppViewer::LLAppViewer() mLogoutMarkerFile(), mReportedCrash(false), mNumSessions(0), + mGeneralThreadPool(nullptr), mPurgeCache(false), mPurgeCacheOnExit(false), mPurgeUserDataOnExit(false), @@ -686,8 +655,7 @@ LLAppViewer::LLAppViewer() mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)), mFastTimerLogThread(NULL), mSettingsLocationList(NULL), - mIsFirstRun(false), - mMinMicroSecPerFrame(0.f) + mIsFirstRun(false) { if(NULL != sInstance) { @@ -856,8 +824,6 @@ bool LLAppViewer::init() LLNotifications::instance(); LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ; - writeSystemInfo(); - ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -964,8 +930,8 @@ bool LLAppViewer::init() } LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ; - // Initialize the repeater service. - LLMainLoopRepeater::instance().start(); + // Initialize event recorder + LLViewerEventRecorder::createInstance(); // // Initialize the window @@ -974,6 +940,9 @@ bool LLAppViewer::init() initWindow(); LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ; + // writeSystemInfo can be called after window is initialized (gViewerWindow non-null) + writeSystemInfo(); + // initWindow also initializes the Feature List, so now we can initialize this global. LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap"); @@ -998,19 +967,6 @@ bool LLAppViewer::init() return 0; } - // If we don't have the right shader requirements. - if (!gGLManager.mHasShaderObjects - || !gGLManager.mHasVertexShader - || !gGLManager.mHasFragmentShader) - { - LLUIString details = LLNotifications::instance().getGlobalString("UnsupportedShaderRequirements"); - OSMessageBox( - details.getString(), - LLStringUtil::null, - OSMB_OK); - return 0; - } - // Without SSE2 support we will crash almost immediately, warn here. if (!gSysCPU.hasSSE2()) { @@ -1136,7 +1092,7 @@ bool LLAppViewer::init() { url = LLTrans::getString("NvidiaDriverPage"); } - else if (gGLManager.mIsATI) + else if (gGLManager.mIsAMD) { url = LLTrans::getString("AMDDriverPage"); } @@ -1319,13 +1275,16 @@ bool LLAppViewer::init() joystick = LLViewerJoystick::getInstance(); joystick->setNeedsReset(true); /*----------------------------------------------------------------------*/ - - gSavedSettings.getControl("FramePerSecondLimit")->getSignal()->connect(boost::bind(&LLAppViewer::onChangeFrameLimit, this, _2)); - onChangeFrameLimit(gSavedSettings.getLLSD("FramePerSecondLimit")); - // Load User's bindings loadKeyBindings(); + //LLSimpleton creations + LLEnvironment::createInstance(); + LLEnvironment::getInstance()->initSingleton(); + LLWorld::createInstance(); + LLSelectMgr::createInstance(); + LLViewerCamera::createInstance(); + #if LL_WINDOWS if (!mSecondInstance) { @@ -1351,14 +1310,18 @@ void LLAppViewer::initMaxHeapSize() //------------------------------------------------------------------------------------------ //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB. - //F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ; - F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ; + #ifndef LL_X86_64 + F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize") ; +#else + F32Gigabytes max_heap_size_gb = (F32Gigabytes)gSavedSettings.getF32("MaxHeapSize64"); +#endif - LLMemory::initMaxHeapSizeGB(max_heap_size_gb); + LLMemory::initMaxHeapSizeGB(max_heap_size_gb); } static LLTrace::BlockTimerStatHandle FTM_MESSAGES("System Messages"); -static LLTrace::BlockTimerStatHandle FTM_SLEEP("Sleep"); +static LLTrace::BlockTimerStatHandle FTM_SLEEP1("Sleep1"); +static LLTrace::BlockTimerStatHandle FTM_SLEEP2("Sleep2"); static LLTrace::BlockTimerStatHandle FTM_YIELD("Yield"); static LLTrace::BlockTimerStatHandle FTM_TEXTURE_CACHE("Texture Cache"); @@ -1419,13 +1382,26 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { + LL_RECORD_BLOCK_TIME(FTM_FRAME); + + if (!LLWorld::instanceExists()) + { + LLWorld::createInstance(); + } + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); LLSD newFrame; - LL_RECORD_BLOCK_TIME(FTM_FRAME); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace"); + if (LLFloaterReg::instanceVisible("block_timers")) + { LLTrace::BlockTimer::processTimes(); + } + LLTrace::get_frame_recording().nextPeriod(); LLTrace::BlockTimer::logStats(); + } LLTrace::get_thread_recorder()->pullFromChildren(); @@ -1433,6 +1409,7 @@ bool LLAppViewer::doFrame() LL_CLEAR_CALLSTACKS(); { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df processMiscNativeEvents" ) pingMainloopTimeout("Main:MiscNativeWindowEvents"); if (gViewerWindow) @@ -1441,7 +1418,10 @@ bool LLAppViewer::doFrame() gViewerWindow->getWindow()->processMiscNativeEvents(); } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gatherInput" ) pingMainloopTimeout("Main:GatherInput"); + } if (gViewerWindow) { @@ -1465,13 +1445,21 @@ bool LLAppViewer::doFrame() } } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df mainloop" ) // canonical per-frame event mainloop.post(newFrame); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df suspend" ) // give listeners a chance to run llcoro::suspend(); + } if (!LLApp::isExiting()) { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df JoystickKeyboard" ) pingMainloopTimeout("Main:JoystickKeyboard"); // Scan keyboard for movement keys. Command keys and typing @@ -1492,12 +1480,20 @@ bool LLAppViewer::doFrame() // Update state based on messages, user input, object idle. { - pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) + pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! + } - LL_RECORD_BLOCK_TIME(FTM_IDLE); - idle(); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); //LL_RECORD_BLOCK_TIME(FTM_IDLE); + idle(); + } - resumeMainloopTimeout(); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) + resumeMainloopTimeout(); + } } if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED)) @@ -1518,49 +1514,51 @@ bool LLAppViewer::doFrame() // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18 if (!LLApp::isExiting() && !gHeadlessClient && gViewerWindow) { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Display" ) pingMainloopTimeout("Main:Display"); gGLActive = TRUE; display(); - static U64 last_call = 0; - if (!gTeleportDisplay) { - // Frame/draw throttling, controlled by FramePerSecondLimit - U64 elapsed_time = LLTimer::getTotalTime() - last_call; - if (elapsed_time < mMinMicroSecPerFrame) - { - LL_RECORD_BLOCK_TIME(FTM_SLEEP); - // llclamp for when time function gets funky - U64 sleep_time = llclamp(mMinMicroSecPerFrame - elapsed_time, (U64)1, (U64)1e6); - micro_sleep(sleep_time, 0); - } - } - last_call = LLTimer::getTotalTime(); - + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df Snapshot" ) pingMainloopTimeout("Main:Snapshot"); LLFloaterSnapshot::update(); // take snapshots LLFloaterOutfitSnapshot::update(); gGLActive = FALSE; } } + } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df pauseMainloopTimeout" ) pingMainloopTimeout("Main:Sleep"); pauseMainloopTimeout(); + } // Sleep and run background threads { - LL_RECORD_BLOCK_TIME(FTM_SLEEP); + //LL_RECORD_BLOCK_TIME(SLEEP2); + LL_PROFILE_ZONE_WARN( "Sleep2" ) // yield some time to the os based on command line option static LLCachedControl<S32> yield_time(gSavedSettings, "YieldTime", -1); if(yield_time >= 0) { LL_RECORD_BLOCK_TIME(FTM_YIELD); + LL_PROFILE_ZONE_NUM( yield_time ) ms_sleep(yield_time); } + if (gNonInteractive) + { + S32 non_interactive_ms_sleep_time = 100; + LLAppViewer::getTextureCache()->pause(); + LLAppViewer::getImageDecodeThread()->pause(); + ms_sleep(non_interactive_ms_sleep_time); + } + // yield cooperatively when not running as foreground window // and when not quiting (causes trouble at mac's cleanup stage) if (!LLApp::isExiting() @@ -1568,8 +1566,8 @@ bool LLAppViewer::doFrame() || !gFocusMgr.getAppHasFocus())) { // Sleep if we're not rendering, or the window is minimized. - static LLCachedControl<S32> s_bacground_yeild_time(gSavedSettings, "BackgroundYieldTime", 40); - S32 milliseconds_to_sleep = llclamp((S32)s_bacground_yeild_time, 0, 1000); + static LLCachedControl<S32> s_background_yield_time(gSavedSettings, "BackgroundYieldTime", 40); + S32 milliseconds_to_sleep = llclamp((S32)s_background_yield_time, 0, 1000); // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads // of equal priority on Windows if (milliseconds_to_sleep > 0) @@ -1616,22 +1614,29 @@ bool LLAppViewer::doFrame() total_io_pending += io_pending ; } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gMeshRepo" ) gMeshRepo.update() ; + } if(!total_work_pending) //pause texture fetching threads if nothing to process. { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df getTextureCache" ) LLAppViewer::getTextureCache()->pause(); LLAppViewer::getImageDecodeThread()->pause(); LLAppViewer::getTextureFetch()->pause(); } if(!total_io_pending) //pause file threads if nothing to process. { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df LLVFSThread" ) LLLFSThread::sLocal->pause(); } //texture fetching debugger if(LLTextureFetchDebugger::isEnabled()) { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df tex_fetch_debugger_instance" ) LLFloaterTextureFetchDebugger* tex_fetch_debugger_instance = LLFloaterReg::findTypedInstance<LLFloaterTextureFetchDebugger>("tex_fetch_debugger"); if(tex_fetch_debugger_instance) @@ -1640,8 +1645,10 @@ bool LLAppViewer::doFrame() } } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df resumeMainloopTimeout" ) resumeMainloopTimeout(); - + } pingMainloopTimeout("Main:End"); } } @@ -1667,7 +1674,7 @@ bool LLAppViewer::doFrame() LL_INFOS() << "Exiting main_loop" << LL_ENDL; } - LLPROFILE_UPDATE(); + LL_PROFILER_FRAME_END return ! LLApp::isRunning(); } @@ -1754,6 +1761,7 @@ bool LLAppViewer::cleanup() LLPluginProcessParent::shutdown(); disconnectViewer(); + LLViewerCamera::deleteSingleton(); LL_INFOS() << "Viewer disconnected" << LL_ENDL; @@ -1949,7 +1957,7 @@ bool LLAppViewer::cleanup() if (LLEnvironment::instanceExists()) { - //Store environment settings if nessesary + //Store environment settings if necessary LLEnvironment::getInstance()->saveToSettings(); } @@ -2058,6 +2066,10 @@ bool LLAppViewer::cleanup() sTextureCache->shutdown(); sImageDecodeThread->shutdown(); sPurgeDiskCacheThread->shutdown(); + if (mGeneralThreadPool) + { + mGeneralThreadPool->close(); + } sTextureFetch->shutDownTextureCacheThread() ; sTextureFetch->shutDownImageDecodeThread() ; @@ -2082,6 +2094,8 @@ bool LLAppViewer::cleanup() mFastTimerLogThread = NULL; delete sPurgeDiskCacheThread; sPurgeDiskCacheThread = NULL; + delete mGeneralThreadPool; + mGeneralThreadPool = NULL; if (LLFastTimerView::sAnalyzePerformance) { @@ -2140,12 +2154,15 @@ bool LLAppViewer::cleanup() SUBSYSTEM_CLEANUP(LLProxy); LLCore::LLHttp::cleanup(); - LLMainLoopRepeater::instance().stop(); - ll_close_fail_log(); LLError::LLCallStacks::cleanup(); + LLEnvironment::deleteSingleton(); + LLSelectMgr::deleteSingleton(); + LLViewerEventRecorder::deleteSingleton(); + LLWorld::deleteSingleton(); + // It's not at first obvious where, in this long sequence, a generic cleanup // call OUGHT to go. So let's say this: as we migrate cleanup from // explicit hand-placed calls into the generic mechanism, eventually @@ -2165,6 +2182,24 @@ bool LLAppViewer::cleanup() return true; } +void LLAppViewer::initGeneralThread() +{ + if (mGeneralThreadPool) + { + return; + } + + LLSD poolSizes{ gSavedSettings.getLLSD("ThreadPoolSizes") }; + LLSD sizeSpec{ poolSizes["General"] }; + LLSD::Integer poolSize{ sizeSpec.isInteger() ? sizeSpec.asInteger() : 3 }; + LL_DEBUGS("ThreadPool") << "Instantiating General pool with " + << poolSize << " threads" << LL_ENDL; + // We don't want anyone, especially the main thread, to have to block + // due to this ThreadPool being full. + mGeneralThreadPool = new LL::ThreadPool("General", poolSize, 1024 * 1024); + mGeneralThreadPool->start(); +} + bool LLAppViewer::initThreads() { static const bool enable_threads = true; @@ -2328,7 +2363,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, LL_INFOS("Settings") << "Attempting to load settings for the group " << file.name() << " - from location " << location_key << LL_ENDL; - LLControlGroup* settings_group = LLControlGroup::getInstance(file.name); + auto settings_group = LLControlGroup::getInstance(file.name); if(!settings_group) { LL_WARNS("Settings") << "No matching settings group for name " << file.name() << LL_ENDL; @@ -2423,6 +2458,38 @@ namespace } } // anonymous namespace +// Set a named control temporarily for this session, as when set via the command line --set option. +// Name can be specified as "<control_group>.<control_name>", with default group being Global. +bool tempSetControl(const std::string& name, const std::string& value) +{ + std::string name_part; + std::string group_part; + LLControlVariable* control = NULL; + + // Name can be further split into ControlGroup.Name, with the default control group being Global + size_t pos = name.find('.'); + if (pos != std::string::npos) + { + group_part = name.substr(0, pos); + name_part = name.substr(pos+1); + LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL; + auto g = LLControlGroup::getInstance(group_part); + if (g) control = g->getControl(name_part); + } + else + { + LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL; + control = gSavedSettings.getControl(name); + } + + if (control) + { + control->setValue(value, false); + return true; + } + return false; +} + bool LLAppViewer::initConfiguration() { //Load settings files list @@ -2473,12 +2540,7 @@ bool LLAppViewer::initConfiguration() #ifndef LL_RELEASE_FOR_DOWNLOAD // provide developer build only overrides for these control variables that are not // persisted to settings.xml - LLControlVariable* c = gSavedSettings.getControl("ShowConsoleWindow"); - if (c) - { - c->setValue(true, false); - } - c = gSavedSettings.getControl("AllowMultipleViewers"); + LLControlVariable* c = gSavedSettings.getControl("AllowMultipleViewers"); if (c) { c->setValue(true, false); @@ -2584,9 +2646,10 @@ bool LLAppViewer::initConfiguration() disableCrashlogger(); } + gNonInteractive = gSavedSettings.getBOOL("NonInteractive"); // Handle initialization from settings. // Start up the debugging console before handling other options. - if (gSavedSettings.getBOOL("ShowConsoleWindow")) + if (gSavedSettings.getBOOL("ShowConsoleWindow") && !gNonInteractive) { initConsole(); } @@ -2619,31 +2682,7 @@ bool LLAppViewer::initConfiguration() { const std::string& name = *itr; const std::string& value = *(++itr); - std::string name_part; - std::string group_part; - LLControlVariable* control = NULL; - - // Name can be further split into ControlGroup.Name, with the default control group being Global - size_t pos = name.find('.'); - if (pos != std::string::npos) - { - group_part = name.substr(0, pos); - name_part = name.substr(pos+1); - LL_INFOS() << "Setting " << group_part << "." << name_part << " to " << value << LL_ENDL; - LLControlGroup* g = LLControlGroup::getInstance(group_part); - if (g) control = g->getControl(name_part); - } - else - { - LL_INFOS() << "Setting Global." << name << " to " << value << LL_ENDL; - control = gSavedSettings.getControl(name); - } - - if (control) - { - control->setValue(value, false); - } - else + if (!tempSetControl(name,value)) { LL_WARNS() << "Failed --set " << name << ": setting name unknown." << LL_ENDL; } @@ -2731,6 +2770,19 @@ bool LLAppViewer::initConfiguration() } } + if (gNonInteractive) + { + tempSetControl("AllowMultipleViewers", "TRUE"); + tempSetControl("SLURLPassToOtherInstance", "FALSE"); + tempSetControl("RenderWater", "FALSE"); + tempSetControl("FlyingAtExit", "FALSE"); + tempSetControl("WindowWidth", "1024"); + tempSetControl("WindowHeight", "200"); + LLError::setEnabledLogTypesMask(0); + llassert_always(!gSavedSettings.getBOOL("SLURLPassToOtherInstance")); + } + + // Handle slurl use. NOTE: Don't let SL-55321 reappear. // This initial-SLURL logic, up through the call to // sendURLToOtherInstance(), must precede LLSplashScreen::show() -- @@ -3507,11 +3559,14 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); + if (gViewerWindow) + { std::vector<std::string> resolutions = gViewerWindow->getWindow()->getDisplaysResolutionList(); for (auto res_iter : resolutions) { gDebugInfo["DisplayInfo"].append(res_iter); } + } writeDebugInfo(); // Save out debug_info.log early, in case of crash. } @@ -4253,12 +4308,12 @@ bool LLAppViewer::initCache() { if (mPurgeCache) { - LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); - purgeCache(); + LLSplashScreen::update(LLTrans::getString("StartupClearingCache")); + purgeCache(); // clear the new C++ file system based cache LLDiskCache::getInstance()->clearCache(); - } + } else { // purge excessive files from the new file system based cache @@ -4285,12 +4340,12 @@ bool LLAppViewer::initCache() LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()); - return true; + return true; } void LLAppViewer::addOnIdleCallback(const boost::function<void()>& cb) { - LLDeferredTaskList::instance().addTask(cb); + gMainloopWork.post(cb); } void LLAppViewer::loadKeyBindings() @@ -4560,6 +4615,7 @@ static LLTrace::BlockTimerStatHandle FTM_HUD_EFFECTS("HUD Effects"); /////////////////////////////////////////////////////// void LLAppViewer::idle() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; pingMainloopTimeout("Main:Idle"); // Update frame timers @@ -4578,6 +4634,20 @@ void LLAppViewer::idle() LLDirPickerThread::clearDead(); F32 dt_raw = idle_timer.getElapsedTimeAndResetF32(); + // Service the WorkQueue we use for replies from worker threads. + // Use function statics for the timeslice setting so we only have to fetch + // and convert MainWorkTime once. + static F32 MainWorkTimeRaw = gSavedSettings.getF32("MainWorkTime"); + static F32Milliseconds MainWorkTimeMs(MainWorkTimeRaw); + // MainWorkTime is specified in fractional milliseconds, but std::chrono + // uses integer representations. What if we want less than a microsecond? + // Use nanoseconds. We're very sure we will never need to specify a + // MainWorkTime that would be larger than we could express in + // std::chrono::nanoseconds. + static std::chrono::nanoseconds MainWorkTimeNanoSec{ + std::chrono::nanoseconds::rep(MainWorkTimeMs.value() * 1000000)}; + gMainloopWork.runFor(MainWorkTimeNanoSec); + // Cap out-of-control frame times // Too low because in menus, swapping, debugger, etc. // Too high because idle called with no objects in view, etc. @@ -4631,7 +4701,7 @@ void LLAppViewer::idle() if (!gDisconnected) { - LL_RECORD_BLOCK_TIME(FTM_NETWORK); + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("network"); //LL_RECORD_BLOCK_TIME(FTM_NETWORK); // Update spaceserver timeinfo LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + LLUnits::Seconds::fromValue(dt_raw)); @@ -4663,7 +4733,7 @@ void LLAppViewer::idle() || (agent_force_update_time > (1.0f / (F32) AGENT_FORCE_UPDATES_PER_SECOND)); if (force_update || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND))) { - LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE); // Send avatar and camera info mLastAgentControlFlags = gAgent.getControlFlags(); mLastAgentForceUpdate = force_update ? 0 : agent_force_update_time; @@ -4900,8 +4970,10 @@ void LLAppViewer::idle() // Here, particles are updated and drawables are moved. // - LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); - gPipeline.updateMove(); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("world update"); //LL_RECORD_BLOCK_TIME(FTM_WORLD_UPDATE); + gPipeline.updateMove(); + } LLWorld::getInstance()->updateParticles(); @@ -4940,7 +5012,7 @@ void LLAppViewer::idle() LLAvatarRenderInfoAccountant::getInstance()->idle(); { - LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("audio update"); //LL_RECORD_BLOCK_TIME(FTM_AUDIO_UPDATE); if (gAudiop) { @@ -4954,9 +5026,6 @@ void LLAppViewer::idle() } } - // Execute deferred tasks. - LLDeferredTaskList::instance().run(); - // Handle shutdown process, for example, // wait for floaters to close, send quit message, // forcibly quit if it has taken too long @@ -5184,6 +5253,7 @@ static LLTrace::BlockTimerStatHandle FTM_CHECK_REGION_CIRCUIT("Check Region Circ void LLAppViewer::idleNetwork() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; pingMainloopTimeout("idleNetwork"); gObjectList.mNumNewObjects = 0; @@ -5191,7 +5261,7 @@ void LLAppViewer::idleNetwork() if (!gSavedSettings.getBOOL("SpeedTest")) { - LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode + LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode LLTimer check_message_timer; // Read all available packets from network @@ -5352,7 +5422,7 @@ void LLAppViewer::disconnectViewer() // Now we just ask the LLWorld singleton to cleanly shut down. if(LLWorld::instanceExists()) { - LLWorld::getInstance()->destroyClass(); + LLWorld::getInstance()->resetClass(); } LLVOCache::deleteSingleton(); @@ -5367,19 +5437,6 @@ void LLAppViewer::disconnectViewer() LLUrlEntryParcel::setDisconnected(gDisconnected); } -bool LLAppViewer::onChangeFrameLimit(LLSD const & evt) -{ - if (evt.asInteger() > 0) - { - mMinMicroSecPerFrame = (U64)(1000000.0f / F32(evt.asInteger())); - } - else - { - mMinMicroSecPerFrame = 0; - } - return false; -} - void LLAppViewer::forceErrorLLError() { LL_ERRS() << "This is a deliberate llerror" << LL_ENDL; diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index 0f06889d20..a86fa7d873 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -50,6 +50,8 @@ #include "lltimer.h" #include "llappcorehttp.h" +#include <boost/signals2.hpp> + class LLCommandLineParser; class LLFrameTimer; class LLPumpIO; @@ -61,6 +63,11 @@ class LLViewerJoystick; class LLPurgeDiskCacheThread; class LLViewerRegion; +namespace LL +{ + class ThreadPool; +} + extern LLTrace::BlockTimerStatHandle FTM_FRAME; class LLAppViewer : public LLApp @@ -69,13 +76,13 @@ public: LLAppViewer(); virtual ~LLAppViewer(); - /** - * @brief Access to the LLAppViewer singleton. - * - * The LLAppViewer singleton is created in main()/WinMain(). - * So don't use it in pre-entry (static initialization) code. - */ - static LLAppViewer* instance() {return sInstance; } + /** + * @brief Access to the LLAppViewer singleton. + * + * The LLAppViewer singleton is created in main()/WinMain(). + * So don't use it in pre-entry (static initialization) code. + */ + static LLAppViewer* instance() {return sInstance; } // // Main application logic @@ -93,12 +100,12 @@ public: void earlyExit(const std::string& name, const LLSD& substitutions = LLSD()); // Display an error dialog and forcibly quit. void earlyExitNoNotify(); // Do not display error dialog then forcibly quit. - void abortQuit(); // Called to abort a quit request. + void abortQuit(); // Called to abort a quit request. - bool quitRequested() { return mQuitRequested; } - bool logoutRequestSent() { return mLogoutRequestSent; } + bool quitRequested() { return mQuitRequested; } + bool logoutRequestSent() { return mLogoutRequestSent; } bool isSecondInstance() { return mSecondInstance; } - bool isUpdaterMissing() { return mUpdaterNotFound; } + bool isUpdaterMissing() { return mUpdaterNotFound; } void writeDebugInfo(bool isStatic=true); @@ -112,7 +119,7 @@ public: virtual bool restoreErrorTrap() = 0; // Require platform specific override to reset error handling mechanism. // return false if the error trap needed restoration. static void handleViewerCrash(); // Hey! The viewer crashed. Do this, soon. - void checkForCrash(); + void checkForCrash(); // Thread accessors static LLTextureCache* getTextureCache() { return sTextureCache; } @@ -124,37 +131,37 @@ public: static U32 getObjectCacheVersion() ; const std::string& getSerialNumber() { return mSerialNumber; } - + bool getPurgeCache() const { return mPurgeCache; } - + std::string getSecondLifeTitle() const; // The Second Life title. std::string getWindowTitle() const; // The window display name. - void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user. - void badNetworkHandler(); // Cause a crash state due to bad network packet. + void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user. + void badNetworkHandler(); // Cause a crash state due to bad network packet. bool hasSavedFinalSnapshot() { return mSavedFinalSnapshot; } void saveFinalSnapshot(); - void loadNameCache(); - void saveNameCache(); + void loadNameCache(); + void saveNameCache(); void loadExperienceCache(); void saveExperienceCache(); void removeMarkerFiles(); - + void removeDumpDir(); - // LLAppViewer testing helpers. - // *NOTE: These will potentially crash the viewer. Only for debugging. - virtual void forceErrorLLError(); - virtual void forceErrorBreakpoint(); - virtual void forceErrorBadMemoryAccess(); - virtual void forceErrorInfiniteLoop(); - virtual void forceErrorSoftwareException(); - virtual void forceErrorDriverCrash(); - virtual void forceErrorCoroutineCrash(); - virtual void forceErrorThreadCrash(); + // LLAppViewer testing helpers. + // *NOTE: These will potentially crash the viewer. Only for debugging. + virtual void forceErrorLLError(); + virtual void forceErrorBreakpoint(); + virtual void forceErrorBadMemoryAccess(); + virtual void forceErrorInfiniteLoop(); + virtual void forceErrorSoftwareException(); + virtual void forceErrorDriverCrash(); + virtual void forceErrorCoroutineCrash(); + virtual void forceErrorThreadCrash(); // The list is found in app_settings/settings_files.xml // but since they are used explicitly in code, @@ -187,22 +194,26 @@ public: // *NOTE:Mani Fix this for login abstraction!! void handleLoginComplete(); - LLAllocator & getAllocator() { return mAlloc; } + LLAllocator & getAllocator() { return mAlloc; } // On LoginCompleted callback typedef boost::signals2::signal<void (void)> login_completed_signal_t; login_completed_signal_t mOnLoginCompleted; - boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb ) { return mOnLoginCompleted.connect(cb); } + boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb ) + { + return mOnLoginCompleted.connect(cb); + } void addOnIdleCallback(const boost::function<void()>& cb); // add a callback to fire (once) when idle + void initGeneralThread(); void purgeUserDataOnExit() { mPurgeUserDataOnExit = true; } void purgeCache(); // Clear the local cache. void purgeCacheImmediate(); //clear local cache immediately. S32 updateTextureThreads(F32 max_time); void loadKeyBindings(); - + // mute/unmute the system's master audio virtual void setMasterSystemAudioMute(bool mute); virtual bool getMasterSystemAudioMute(); @@ -214,7 +225,7 @@ public: // llcorehttp init/shutdown/config information. LLAppCoreHttp & getAppCoreHttp() { return mAppCoreHttp; } - void updateNameLookupUrl(const LLViewerRegion* regionp); + void updateNameLookupUrl(const LLViewerRegion* regionp); protected: virtual bool initWindow(); // Initialize the viewer's window. @@ -225,7 +236,7 @@ protected: virtual bool sendURLToOtherInstance(const std::string& url); virtual bool initParseCommandLine(LLCommandLineParser& clp) - { return true; } // Allow platforms to specify the command line args. + { return true; } // Allow platforms to specify the command line args. virtual std::string generateSerialNumber() = 0; // Platforms specific classes generate this. @@ -253,24 +264,21 @@ private: void processMarkerFiles(); static void recordMarkerVersion(LLAPRFile& marker_file); bool markerIsSameVersion(const std::string& marker_name) const; - - void idle(); - void idleShutdown(); + + void idle(); + void idleShutdown(); // update avatar SLID and display name caches - void idleExperienceCache(); void idleNameCache(); - void idleNetwork(); - - void sendLogoutRequest(); - void disconnectViewer(); + void idleNetwork(); - bool onChangeFrameLimit(LLSD const & evt); + void sendLogoutRequest(); + void disconnectViewer(); // *FIX: the app viewer class should be some sort of singleton, no? // Perhaps its child class is the singleton and this should be an abstract base. static LLAppViewer* sInstance; - bool mSecondInstance; // Is this a second instance of the app? + bool mSecondInstance; // Is this a second instance of the app? bool mUpdaterNotFound; // True when attempt to start updater failed std::string mMarkerFileName; @@ -288,6 +296,7 @@ private: static LLImageDecodeThread* sImageDecodeThread; static LLTextureFetch* sTextureFetch; static LLPurgeDiskCacheThread* sPurgeDiskCacheThread; + LL::ThreadPool* mGeneralThreadPool; S32 mNumSessions; @@ -302,8 +311,8 @@ private: boost::optional<U32> mForceGraphicsLevel; - bool mQuitRequested; // User wants to quit, may have modified documents open. - bool mLogoutRequestSent; // Disconnect message sent to simulator, no longer safe to send messages to the sim. + bool mQuitRequested; // User wants to quit, may have modified documents open. + bool mLogoutRequestSent; // Disconnect message sent to simulator, no longer safe to send messages to the sim. U32 mLastAgentControlFlags; F32 mLastAgentForceUpdate; struct SettingsFiles* mSettingsLocationList; @@ -317,15 +326,12 @@ private: bool mAgentRegionLastAlive; LLUUID mAgentRegionLastID; - LLAllocator mAlloc; + LLAllocator mAlloc; // llcorehttp library init/shutdown helper LLAppCoreHttp mAppCoreHttp; - bool mIsFirstRun; - U64 mMinMicroSecPerFrame; // frame throttling - - + bool mIsFirstRun; }; // consts from viewer.h diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index ee533875b6..a39ec7f51b 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -329,6 +329,11 @@ int APIENTRY WINMAIN(HINSTANCE hInstance, PWSTR pCmdLine, int nCmdShow) { + // Call Tracy first thing to have it allocate memory + // https://github.com/wolfpld/tracy/issues/196 + LL_PROFILER_FRAME_END; + LL_PROFILER_SET_THREAD_NAME("App"); + const S32 MAX_HEAPS = 255; DWORD heap_enable_lfh_error[MAX_HEAPS]; S32 num_heaps = 0; diff --git a/indra/newview/llavatarrenderinfoaccountant.cpp b/indra/newview/llavatarrenderinfoaccountant.cpp index 04dbf03e31..fe94cd27b6 100644 --- a/indra/newview/llavatarrenderinfoaccountant.cpp +++ b/indra/newview/llavatarrenderinfoaccountant.cpp @@ -82,7 +82,15 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoGetCoro(std::string url, U64 LLSD result = httpAdapter->getAndSuspend(httpRequest, url); - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + LLWorld *world_inst = LLWorld::getInstance(); + if (!world_inst) + { + LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but world no longer exists " + << regionHandle << LL_ENDL; + return; + } + + LLViewerRegion * regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) { LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight info received but region not found for " @@ -183,7 +191,15 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("AvatarRenderInfoAccountant", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); - LLViewerRegion * regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + LLWorld *world_inst = LLWorld::getInstance(); + if (!world_inst) + { + LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight calculation but world no longer exists " + << regionHandle << LL_ENDL; + return; + } + + LLViewerRegion * regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) { LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight calculation but region not found for " @@ -239,9 +255,18 @@ void LLAvatarRenderInfoAccountant::avatarRenderInfoReportCoro(std::string url, U report[KEY_AGENTS] = agents; regionp = NULL; + world_inst = NULL; LLSD result = httpAdapter->postAndSuspend(httpRequest, url, report); - regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + world_inst = LLWorld::getInstance(); + if (!world_inst) + { + LL_WARNS("AvatarRenderInfoAccountant") << "Avatar render weight POST result but world no longer exists " + << regionHandle << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) { LL_INFOS("AvatarRenderInfoAccountant") << "Avatar render weight POST result received but region not found for " diff --git a/indra/newview/llbrowsernotification.cpp b/indra/newview/llbrowsernotification.cpp index 7614624306..036215a845 100644 --- a/indra/newview/llbrowsernotification.cpp +++ b/indra/newview/llbrowsernotification.cpp @@ -43,14 +43,14 @@ LLBrowserNotification::LLBrowserNotification() bool LLBrowserNotification::processNotification(const LLNotificationPtr& notification, bool should_log) { LLUUID media_id = notification->getPayload()["media_id"].asUUID(); - LLMediaCtrl* media_instance = LLMediaCtrl::getInstance(media_id); + auto media_instance = LLMediaCtrl::getInstance(media_id); if (media_instance) { media_instance->showNotification(notification); } else if (LLViewerMediaFocus::instance().getControlsMediaID() == media_id) { - LLViewerMediaImpl* impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(media_id); + auto impl = LLViewerMedia::getInstance()->getMediaImplFromTextureID(media_id); if (impl) { impl->showNotification(notification); diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index 43e39d3073..bddbc79df4 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -257,7 +257,6 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds) LLAvatarName av_name; LLAvatarNameCache::get(agent_id, &av_name); - addChangedMask(LLFriendObserver::ADD, agent_id); LL_DEBUGS() << "Added buddy " << agent_id << ", " << (mBuddyInfo[agent_id]->isOnline() ? "Online" : "Offline") << ", TO: " << mBuddyInfo[agent_id]->getRightsGrantedTo() @@ -493,6 +492,7 @@ void LLAvatarTracker::notifyObservers() // new masks and ids will be processed later from idle. return; } + LL_PROFILE_ZONE_SCOPED mIsNotifyObservers = TRUE; observer_list_t observers(mObservers); @@ -679,6 +679,7 @@ void LLAvatarTracker::processChangeUserRights(LLMessageSystem* msg, void**) void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) { + LL_PROFILE_ZONE_SCOPED S32 count = msg->getNumberOfBlocksFast(_PREHASH_AgentBlock); BOOL chat_notify = gSavedSettings.getBOOL("ChatOnlineNotification"); @@ -713,8 +714,6 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) // we were tracking someone who went offline deleteTrackingData(); } - // *TODO: get actual inventory id - gInventory.addChangedMask(LLInventoryObserver::CALLING_CARD, LLUUID::null); } if(chat_notify) { diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp index c110e0d815..cdf82c77c1 100644 --- a/indra/newview/llchathistory.cpp +++ b/indra/newview/llchathistory.cpp @@ -752,7 +752,7 @@ public: if ( chat.mSourceType == CHAT_SOURCE_OBJECT) { std::string slurl = args["slurl"].asString(); - if (slurl.empty()) + if (slurl.empty() && LLWorld::instanceExists()) { LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent); if(region) diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index fab249f988..4a87273372 100644 --- a/indra/newview/llcontrolavatar.cpp +++ b/indra/newview/llcontrolavatar.cpp @@ -241,7 +241,7 @@ void LLControlAvatar::matchVolumeTransform() if (skin_info) { LL_DEBUGS("BindShape") << getFullname() << " bind shape " << skin_info->mBindShapeMatrix << LL_ENDL; - bind_rot = LLSkinningUtil::getUnscaledQuaternion(skin_info->mBindShapeMatrix); + bind_rot = LLSkinningUtil::getUnscaledQuaternion(LLMatrix4(skin_info->mBindShapeMatrix)); } #endif setRotation(bind_rot*obj_rot); @@ -299,7 +299,6 @@ void LLControlAvatar::updateVolumeGeom() mRootVolp->mDrawable->makeActive(); gPipeline.markMoved(mRootVolp->mDrawable); gPipeline.markTextured(mRootVolp->mDrawable); // face may need to change draw pool to/from POOL_HUD - mRootVolp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); LLViewerObject::const_child_list_t& child_list = mRootVolp->getChildren(); for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); @@ -308,7 +307,6 @@ void LLControlAvatar::updateVolumeGeom() LLViewerObject* childp = *iter; if (childp && childp->mDrawable.notNull()) { - childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD gPipeline.markMoved(childp->mDrawable); } diff --git a/indra/newview/lldonotdisturbnotificationstorage.cpp b/indra/newview/lldonotdisturbnotificationstorage.cpp index cb5f9c8a2c..7d4961c598 100644 --- a/indra/newview/lldonotdisturbnotificationstorage.cpp +++ b/indra/newview/lldonotdisturbnotificationstorage.cpp @@ -96,11 +96,9 @@ void LLDoNotDisturbNotificationStorage::resetDirty() mDirty = false; } -static LLTrace::BlockTimerStatHandle FTM_SAVE_DND_NOTIFICATIONS("Save DND Notifications"); - void LLDoNotDisturbNotificationStorage::saveNotifications() { - LL_RECORD_BLOCK_TIME(FTM_SAVE_DND_NOTIFICATIONS); + LL_PROFILE_ZONE_SCOPED; LLNotificationChannelPtr channelPtr = getCommunicationChannel(); const LLCommunicationChannel *commChannel = dynamic_cast<LLCommunicationChannel*>(channelPtr.get()); diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 4fe7e516cc..4a0c9d399f 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -58,8 +58,6 @@ const F32 MIN_INTERPOLATE_DISTANCE_SQUARED = 0.001f * 0.001f; const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f; -static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound"); - extern bool gShiftFrame; @@ -93,7 +91,6 @@ void LLDrawable::incrementVisible() LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry) : LLViewerOctreeEntryData(LLViewerOctreeEntry::LLDRAWABLE), - LLTrace::MemTrackable<LLDrawable, 16>("LLDrawable"), mVObjp(vobj) { init(new_entry); @@ -101,6 +98,8 @@ LLDrawable::LLDrawable(LLViewerObject *vobj, bool new_entry) void LLDrawable::init(bool new_entry) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + // mXform mParent = NULL; mRenderType = 0; @@ -150,21 +149,6 @@ void LLDrawable::unload() { LLVOVolume *pVVol = getVOVolume(); pVVol->setNoLOD(); - - for (S32 i = 0; i < getNumFaces(); i++) - { - LLFace* facep = getFace(i); - if (facep->isState(LLFace::RIGGED)) - { - LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*)facep->getPool(); - if (pool) { - pool->removeRiggedFace(facep); - } - facep->setVertexBuffer(NULL); - } - facep->clearState(LLFace::RIGGED); - } - pVVol->markForUpdate(TRUE); } @@ -261,19 +245,13 @@ BOOL LLDrawable::isLight() const } } -static LLTrace::BlockTimerStatHandle FTM_CLEANUP_DRAWABLE("Cleanup Drawable"); -static LLTrace::BlockTimerStatHandle FTM_DEREF_DRAWABLE("Deref"); -static LLTrace::BlockTimerStatHandle FTM_DELETE_FACES("Faces"); - void LLDrawable::cleanupReferences() { - LL_RECORD_BLOCK_TIME(FTM_CLEANUP_DRAWABLE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; - { - LL_RECORD_BLOCK_TIME(FTM_DELETE_FACES); - std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); - mFaces.clear(); - } + + std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); + mFaces.clear(); gObjectList.removeDrawable(this); @@ -281,12 +259,9 @@ void LLDrawable::cleanupReferences() removeFromOctree(); - { - LL_RECORD_BLOCK_TIME(FTM_DEREF_DRAWABLE); - // Cleanup references to other objects - mVObjp = NULL; - mParent = NULL; - } + // Cleanup references to other objects + mVObjp = NULL; + mParent = NULL; } void LLDrawable::removeFromOctree() @@ -331,14 +306,12 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep) return count; } -static LLTrace::BlockTimerStatHandle FTM_ALLOCATE_FACE("Allocate Face"); - LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE LLFace *face; { - LL_RECORD_BLOCK_TIME(FTM_ALLOCATE_FACE); face = new LLFace(this, mVObjp); } @@ -363,13 +336,12 @@ LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep) LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep) { - LLFace *face; + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE - { - LL_RECORD_BLOCK_TIME(FTM_ALLOCATE_FACE); - face = new LLFace(this, mVObjp); - } + LLFace *face; + face = new LLFace(this, mVObjp); + face->setTEOffset(mFaces.size()); face->setTexture(texturep); face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep)); @@ -387,6 +359,8 @@ LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep) LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + LLFace *face; face = new LLFace(this, mVObjp); @@ -408,6 +382,8 @@ LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + LLFace *face; face = new LLFace(this, mVObjp); @@ -430,6 +406,8 @@ LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + if (newFaces == (S32)mFaces.size()) { return; @@ -453,6 +431,8 @@ void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerText void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2) { return; @@ -476,6 +456,8 @@ void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewer void LLDrawable::mergeFaces(LLDrawable* src) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + U32 face_count = mFaces.size() + src->mFaces.size(); mFaces.reserve(face_count); @@ -509,6 +491,8 @@ void LLDrawable::updateMaterial() void LLDrawable::makeActive() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + #if !LL_RELEASE_FOR_DOWNLOAD if (mVObjp.notNull()) { @@ -572,6 +556,8 @@ void LLDrawable::makeActive() void LLDrawable::makeStatic(BOOL warning_enabled) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + if (isState(ACTIVE) && !isState(ACTIVE_CHILD) && !mVObjp->isAttachment() && @@ -618,6 +604,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled) // Returns "distance" between target destination and resulting xfrom F32 LLDrawable::updateXform(BOOL undamped) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + BOOL damped = !undamped; // Position @@ -769,6 +757,8 @@ void LLDrawable::moveUpdatePipeline(BOOL moved) void LLDrawable::movePartition() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + LLSpatialPartition* part = getSpatialPartition(); if (part) { @@ -813,6 +803,8 @@ BOOL LLDrawable::updateMoveUndamped() void LLDrawable::updatePartition() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + if (!getVOVolume()) { movePartition(); @@ -830,6 +822,8 @@ void LLDrawable::updatePartition() BOOL LLDrawable::updateMoveDamped() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + F32 dist_squared = updateXform(FALSE); mGeneration++; @@ -853,6 +847,8 @@ BOOL LLDrawable::updateMoveDamped() void LLDrawable::updateDistance(LLCamera& camera, bool force_update) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + if (LLViewerCamera::sCurCameraID != LLViewerCamera::CAMERA_WORLD) { LL_WARNS() << "Attempted to update distance for non-world camera." << LL_ENDL; @@ -957,6 +953,8 @@ void LLDrawable::updateTexture() BOOL LLDrawable::updateGeometry(BOOL priority) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + llassert(mVObjp.notNull()); BOOL res = mVObjp && mVObjp->updateGeometry(this); return res; @@ -1034,6 +1032,8 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const void LLDrawable::updateSpatialExtents() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + if (mVObjp) { const LLVector4a* exts = getSpatialExtents(); @@ -1162,19 +1162,26 @@ void LLDrawable::setGroup(LLViewerOctreeGroup *groupp) LLViewerOctreeEntryData::setGroup(groupp); } +/* +* Get the SpatialPartition this Drawable should use. +* Checks current SpatialPartition assignment and corrects if it is invalid. +*/ LLSpatialPartition* LLDrawable::getSpatialPartition() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + LLSpatialPartition* retval = NULL; - + if (!mVObjp || !getVOVolume() || isStatic()) { - retval = gPipeline.getSpatialPartition((LLViewerObject*) mVObjp); + retval = gPipeline.getSpatialPartition((LLViewerObject*)mVObjp); } else if (isRoot()) { - if (mSpatialBridge) + // determine if the spatial bridge has changed + if (mSpatialBridge) { U32 partition_type = mSpatialBridge->asPartition()->mPartitionType; bool is_hud = mVObjp->isHUDAttachment(); @@ -1191,14 +1198,14 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() { // Was/became part of animesh // remove obsolete bridge - mSpatialBridge->markDead(); + mSpatialBridge->markDead(); setSpatialBridge(NULL); } else if ((partition_type == LLViewerRegion::PARTITION_AVATAR) != is_attachment) { // Was/became part of avatar // remove obsolete bridge - mSpatialBridge->markDead(); + mSpatialBridge->markDead(); setSpatialBridge(NULL); } } @@ -1209,17 +1216,20 @@ LLSpatialPartition* LLDrawable::getSpatialPartition() { setSpatialBridge(new LLHUDBridge(this, getRegion())); } - else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) - { - setSpatialBridge(new LLControlAVBridge(this, getRegion())); - } + else if (mVObjp->isAnimatedObject() && mVObjp->getControlAvatar()) + { + setSpatialBridge(new LLControlAVBridge(this, getRegion())); + } // check HUD first, because HUD is also attachment else if (mVObjp->isAttachment()) { + // Attachment + // Use AvatarBridge of root object in attachment linkset setSpatialBridge(new LLAvatarBridge(this, getRegion())); } else { + // Moving linkset, use VolumeBridge of root object in linkset setSpatialBridge(new LLVolumeBridge(this, getRegion())); } } @@ -1247,6 +1257,8 @@ LLSpatialBridge::LLSpatialBridge(LLDrawable* root, BOOL render_by_group, U32 dat LLDrawable(root->getVObj(), true), LLSpatialPartition(data_mask, render_by_group, GL_STREAM_DRAW_ARB, regionp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + mBridge = this; mDrawable = root; root->setSpatialBridge(this); @@ -1292,12 +1304,11 @@ void LLSpatialBridge::destroyTree() void LLSpatialBridge::updateSpatialExtents() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); - { - LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND); - root->rebound(); - } + root->rebound(); const LLVector4a* root_bounds = root->getBounds(); LLVector4a offset; @@ -1392,10 +1403,21 @@ LLCamera LLSpatialBridge::transformCamera(LLCamera& camera) ret.setOrigin(delta); ret.setAxes(lookAt, left_axis, up_axis); - + return ret; } +void LLSpatialBridge::transformExtents(const LLVector4a* src, LLVector4a* dst) +{ + LLMatrix4 mat = mDrawable->getXform()->getWorldMatrix(); + mat.invert(); + + LLMatrix4a world_to_bridge(mat); + + matMulBoundBox(world_to_bridge, src, dst); +} + + void LLDrawable::setVisible(LLCamera& camera, std::vector<LLDrawable*>* results, BOOL for_select) { LLViewerOctreeEntryData::setVisible(); @@ -1455,6 +1477,8 @@ public: void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* results, BOOL for_select) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + if (!gPipeline.hasRenderType(mDrawableType)) { return; @@ -1552,6 +1576,8 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>* void LLSpatialBridge::updateDistance(LLCamera& camera_in, bool force_update) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE + if (mDrawable == NULL) { markDead(); @@ -1723,6 +1749,17 @@ void LLDrawable::updateFaceSize(S32 idx) } } +LLDrawable* LLDrawable::getRoot() +{ + LLDrawable* ret = this; + while (!ret->isRoot()) + { + ret = ret->getParent(); + } + + return ret; +} + LLBridgePartition::LLBridgePartition(LLViewerRegion* regionp) : LLSpatialPartition(0, FALSE, 0, regionp) { diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 14d782d6f2..2372ea01a6 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -59,14 +59,15 @@ const U32 SILHOUETTE_HIGHLIGHT = 0; // All data for new renderer goes into this class. LL_ALIGN_PREFIX(16) -class LLDrawable -: public LLViewerOctreeEntryData, - public LLTrace::MemTrackable<LLDrawable, 16> +class LLDrawable + : public LLViewerOctreeEntryData { + LL_ALIGN_NEW; public: + typedef std::vector<LLFace*> face_list_t; + LLDrawable(const LLDrawable& rhs) - : LLTrace::MemTrackable<LLDrawable, 16>("LLDrawable"), - LLViewerOctreeEntryData(rhs) + : LLViewerOctreeEntryData(rhs) { *this = rhs; } @@ -120,6 +121,7 @@ public: BOOL isAvatar() const { return mVObjp.notNull() && mVObjp->isAvatar(); } BOOL isRoot() const { return !mParent || mParent->isAvatar(); } + LLDrawable* getRoot(); BOOL isSpatialRoot() const { return !mParent || mParent->isAvatar(); } virtual BOOL isSpatialBridge() const { return FALSE; } virtual LLSpatialPartition* asPartition() { return NULL; } @@ -130,6 +132,7 @@ public: inline LLFace* getFace(const S32 i) const; inline S32 getNumFaces() const; + face_list_t& getFaces() { return mFaces; } //void removeFace(const S32 i); // SJB: Avoid using this, it's slow LLFace* addFace(LLFacePool *poolp, LLViewerTexture *texturep); @@ -253,38 +256,34 @@ public: { IN_REBUILD_Q1 = 0x00000001, IN_REBUILD_Q2 = 0x00000002, - IN_LIGHT_Q = 0x00000004, - EARLY_MOVE = 0x00000008, - MOVE_UNDAMPED = 0x00000010, - ON_MOVE_LIST = 0x00000020, - USE_BACKLIGHT = 0x00000040, - UV = 0x00000080, - UNLIT = 0x00000100, - LIGHT = 0x00000200, - LIGHTING_BUILT = 0x00000400, - REBUILD_VOLUME = 0x00000800, //volume changed LOD or parameters, or vertex buffer changed - REBUILD_TCOORD = 0x00001000, //texture coordinates changed - REBUILD_COLOR = 0x00002000, //color changed - REBUILD_POSITION= 0x00004000, //vertex positions/normals changed + EARLY_MOVE = 0x00000004, + MOVE_UNDAMPED = 0x00000008, + ON_MOVE_LIST = 0x00000010, + UV = 0x00000020, + UNLIT = 0x00000040, + LIGHT = 0x00000080, + REBUILD_VOLUME = 0x00000100, //volume changed LOD or parameters, or vertex buffer changed + REBUILD_TCOORD = 0x00000200, //texture coordinates changed + REBUILD_COLOR = 0x00000400, //color changed + REBUILD_POSITION= 0x00000800, //vertex positions/normals changed REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR, REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR, REBUILD_ALL = REBUILD_GEOMETRY|REBUILD_VOLUME, - REBUILD_RIGGED = 0x00008000, - ON_SHIFT_LIST = 0x00010000, - BLOCKER = 0x00020000, - ACTIVE = 0x00040000, - DEAD = 0x00080000, - INVISIBLE = 0x00100000, // stay invisible until flag is cleared - NEARBY_LIGHT = 0x00200000, // In gPipeline.mNearbyLightSet - BUILT = 0x00400000, - FORCE_INVISIBLE = 0x00800000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned) - REBUILD_SHADOW = 0x02000000, - HAS_ALPHA = 0x04000000, - RIGGED = 0x08000000, - PARTITION_MOVE = 0x10000000, - ANIMATED_CHILD = 0x20000000, - ACTIVE_CHILD = 0x40000000, - FOR_UNLOAD = 0x80000000, //should be unload from memory + REBUILD_RIGGED = 0x00001000, + ON_SHIFT_LIST = 0x00002000, + ACTIVE = 0x00004000, + DEAD = 0x00008000, + INVISIBLE = 0x00010000, // stay invisible until flag is cleared + NEARBY_LIGHT = 0x00020000, // In gPipeline.mNearbyLightSet + BUILT = 0x00040000, + FORCE_INVISIBLE = 0x00080000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned) + HAS_ALPHA = 0x00100000, + RIGGED = 0x00200000, //has a rigged face + RIGGED_CHILD = 0x00400000, //has a child with a rigged face + PARTITION_MOVE = 0x00800000, + ANIMATED_CHILD = 0x01000000, + ACTIVE_CHILD = 0x02000000, + FOR_UNLOAD = 0x04000000, //should be unload from memory } EDrawableFlags; public: @@ -298,8 +297,6 @@ public: static F32 sCurPixelAngle; //current pixels per radian private: - typedef std::vector<LLFace*> face_list_t; - U32 mState; S32 mRenderType; LLPointer<LLViewerObject> mVObjp; diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index d583a692f9..a3837fe10c 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -50,6 +50,9 @@ #include "lldrawpoolwlsky.h" #include "llglslshader.h" #include "llglcommonfunc.h" +#include "llvoavatar.h" +#include "llviewershadermgr.h" + S32 LLDrawPool::sNumDrawPools = 0; @@ -385,25 +388,48 @@ LLRenderPass::~LLRenderPass() } void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) -{ +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo *pparams = *k; - if (pparams) { + if (pparams) + { pushBatch(*pparams, mask, texture); } } } -void LLRenderPass::renderTexture(U32 type, U32 mask, BOOL batch_textures) +void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) { - pushBatches(type, mask, true, batch_textures); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + mask |= LLVertexBuffer::MAP_WEIGHT4; + + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) + { + LLDrawInfo* pparams = *k; + if (pparams) + { + if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash) + { + uploadMatrixPalette(*pparams); + lastAvatar = pparams->mAvatar; + lastMeshId = pparams->mSkinInfo->mHash; + } + + pushBatch(*pparams, mask, texture); + } + } } void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; @@ -414,27 +440,74 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text } } +void LLRenderPass::pushRiggedBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + mask |= LLVertexBuffer::MAP_WEIGHT4; + for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) + { + LLDrawInfo* pparams = *i; + if (pparams) + { + if (pparams->mAvatar.notNull() && (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash)) + { + uploadMatrixPalette(*pparams); + lastAvatar = pparams->mAvatar; + lastMeshId = pparams->mSkinInfo->mHash; + } + + pushBatch(*pparams, mask, texture, batch_textures); + } + } +} + void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) { LLDrawInfo* pparams = *i; if (pparams) { - if (LLGLSLShader::sCurBoundShaderPtr) - { - LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); - } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, pparams->mAlphaMaskCutoff); - } - + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); pushBatch(*pparams, mask, texture, batch_textures); } } } +void LLRenderPass::pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) + { + LLDrawInfo* pparams = *i; + if (pparams) + { + if (LLGLSLShader::sCurBoundShaderPtr) + { + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); + } + else + { + gGL.flush(); + } + + if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash) + { + uploadMatrixPalette(*pparams); + lastAvatar = pparams->mAvatar; + lastMeshId = pparams->mSkinInfo->mHash; + } + + pushBatch(*pparams, mask | LLVertexBuffer::MAP_WEIGHT4, texture, batch_textures); + } + } +} + void LLRenderPass::applyModelMatrix(const LLDrawInfo& params) { if (params.mModelMatrix != gGLLastMatrix) @@ -452,6 +525,7 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params) void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; if (!params.mCount) { return; @@ -469,7 +543,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba { if (params.mTextureList[i].notNull()) { - gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE); + gGL.getTexUnit(i)->bindFast(params.mTextureList[i]); } } } @@ -477,8 +551,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba { //not batching textures or batch has only 1 texture -- might need a texture matrix if (params.mTexture.notNull()) { - params.mTexture->addTextureStats(params.mVSize); - gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ; + gGL.getTexUnit(0)->bindFast(params.mTexture); if (params.mTextureMatrix) { tex_setup = true; @@ -490,24 +563,20 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba } else { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->unbindFast(LLTexUnit::TT_TEXTURE); } } } - if (params.mVertexBuffer.notNull()) - { - if (params.mGroup) - { - params.mGroup->rebuildMesh(); - } + if (params.mGroup) + { + params.mGroup->rebuildMesh(); + } - LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test); - - params.mVertexBuffer->setBuffer(mask); - params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); - gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); - } + LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test); + + params.mVertexBuffer->setBufferFast(mask); + params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); if (tex_setup) { @@ -517,7 +586,34 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL ba } } -void LLRenderPass::renderGroups(U32 type, U32 mask, BOOL texture) +// static +bool LLRenderPass::uploadMatrixPalette(LLDrawInfo& params) +{ + // upload matrix palette to shader + return uploadMatrixPalette(params.mAvatar, params.mSkinInfo); +} + +//static +bool LLRenderPass::uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo) { - gPipeline.renderGroups(this, type, mask, texture); + if (!avatar) + { + return false; + } + const LLVOAvatar::MatrixPaletteCache& mpc = avatar->updateSkinInfoMatrixPalette(skinInfo); + U32 count = mpc.mMatrixPalette.size(); + + if (count == 0) + { + //skin info not loaded yet, don't render + return false; + } + + LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, + count, + FALSE, + (GLfloat*)&(mpc.mGLMp[0])); + + return true; } + diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index ecd9bd034f..fd1b022e5b 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -37,6 +37,8 @@ class LLViewerTexture; class LLViewerFetchedTexture; class LLSpatialGroup; class LLDrawInfo; +class LLVOAvatar; +class LLMeshSkinInfo; class LLDrawPool { @@ -125,38 +127,69 @@ protected: class LLRenderPass : public LLDrawPool { public: + // list of possible LLRenderPass types to assign a render batch to + // NOTE: "rigged" variant MUST be non-rigged variant + 1 enum { PASS_SIMPLE = NUM_POOL_TYPES, + PASS_SIMPLE_RIGGED, PASS_GRASS, PASS_FULLBRIGHT, + PASS_FULLBRIGHT_RIGGED, PASS_INVISIBLE, - PASS_INVISI_SHINY, + PASS_INVISIBLE_RIGGED, + PASS_INVISI_SHINY, + PASS_INVISI_SHINY_RIGGED, PASS_FULLBRIGHT_SHINY, + PASS_FULLBRIGHT_SHINY_RIGGED, PASS_SHINY, + PASS_SHINY_RIGGED, PASS_BUMP, + PASS_BUMP_RIGGED, PASS_POST_BUMP, + PASS_POST_BUMP_RIGGED, PASS_MATERIAL, + PASS_MATERIAL_RIGGED, PASS_MATERIAL_ALPHA, + PASS_MATERIAL_ALPHA_RIGGED, PASS_MATERIAL_ALPHA_MASK, // Diffuse texture used as alpha mask + PASS_MATERIAL_ALPHA_MASK_RIGGED, PASS_MATERIAL_ALPHA_EMISSIVE, + PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, PASS_SPECMAP, + PASS_SPECMAP_RIGGED, PASS_SPECMAP_BLEND, + PASS_SPECMAP_BLEND_RIGGED, PASS_SPECMAP_MASK, // Diffuse texture used as alpha mask and specular texture(map) + PASS_SPECMAP_MASK_RIGGED, PASS_SPECMAP_EMISSIVE, + PASS_SPECMAP_EMISSIVE_RIGGED, PASS_NORMMAP, + PASS_NORMMAP_RIGGED, PASS_NORMMAP_BLEND, + PASS_NORMMAP_BLEND_RIGGED, PASS_NORMMAP_MASK, // Diffuse texture used as alpha mask and normal map + PASS_NORMMAP_MASK_RIGGED, PASS_NORMMAP_EMISSIVE, + PASS_NORMMAP_EMISSIVE_RIGGED, PASS_NORMSPEC, - PASS_NORMSPEC_BLEND, + PASS_NORMSPEC_RIGGED, + PASS_NORMSPEC_BLEND, + PASS_NORMSPEC_BLEND_RIGGED, PASS_NORMSPEC_MASK, // Diffuse texture used as alpha mask with normal and specular map + PASS_NORMSPEC_MASK_RIGGED, PASS_NORMSPEC_EMISSIVE, + PASS_NORMSPEC_EMISSIVE_RIGGED, PASS_GLOW, + PASS_GLOW_RIGGED, PASS_ALPHA, + PASS_ALPHA_RIGGED, PASS_ALPHA_MASK, + PASS_ALPHA_MASK_RIGGED, PASS_FULLBRIGHT_ALPHA_MASK, // Diffuse texture used as alpha mask and fullbright + PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, PASS_ALPHA_INVISIBLE, + PASS_ALPHA_INVISIBLE_RIGGED, NUM_RENDER_TYPES, }; @@ -169,12 +202,14 @@ public: static void applyModelMatrix(const LLDrawInfo& params); virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE); + virtual void pushRiggedBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE); virtual void pushMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE); + virtual void pushRiggedMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE); virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE); + static bool uploadMatrixPalette(LLDrawInfo& params); + static bool uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo); virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE); - virtual void renderGroups(U32 type, U32 mask, BOOL texture = TRUE); - virtual void renderTexture(U32 type, U32 mask, BOOL batch_textures = TRUE); - + virtual void renderRiggedGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE); }; class LLFacePool : public LLDrawPool diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 91b0e40aa9..eebd89f77f 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -48,34 +48,25 @@ #include "lldrawpoolwater.h" #include "llspatialpartition.h" #include "llglcommonfunc.h" +#include "llvoavatar.h" BOOL LLDrawPoolAlpha::sShowDebugAlpha = FALSE; +#define current_shader (LLGLSLShader::sCurBoundShaderPtr) + static BOOL deferred_render = FALSE; -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SETUP("Alpha Setup"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_GROUP_LOOP("Alpha Group"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_PUSH("Alpha Push Verts"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED("Alpha Deferred"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SETBUFFER("Alpha SetBuffer"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DRAW("Alpha Draw"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_TEX_BINDS("Alpha Tex Binds"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MATS("Alpha Mat Tex Binds"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_GLOW("Alpha Glow Binds"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_SHADER_BINDS("Alpha Shader Binds"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS("Alpha Def Binds"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS("Alpha Def Tex Binds"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MESH_REBUILD("Alpha Mesh Rebuild"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_EMISSIVE("Alpha Emissive"); -static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_LIGHT_SETUP("Alpha Light Setup"); +// minimum alpha before discarding a fragment +static const F32 MINIMUM_ALPHA = 0.004f; // ~ 1/255 +// minimum alpha before discarding a fragment when rendering impostors +static const F32 MINIMUM_IMPOSTOR_ALPHA = 0.1f; LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) : - LLRenderPass(type), current_shader(NULL), target_shader(NULL), - simple_shader(NULL), fullbright_shader(NULL), emissive_shader(NULL), + LLRenderPass(type), target_shader(NULL), mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF), mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF) { - + } LLDrawPoolAlpha::~LLDrawPoolAlpha() @@ -86,232 +77,203 @@ LLDrawPoolAlpha::~LLDrawPoolAlpha() void LLDrawPoolAlpha::prerender() { mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); + + // TODO: is this even necessay? These are probably set to never discard + LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(1024.f*1024.f); + LLViewerFetchedTexture::sWhiteImagep->addTextureStats(1024.f * 1024.f); } S32 LLDrawPoolAlpha::getNumPostDeferredPasses() { - if (LLPipeline::sImpostorRender) - { //skip depth buffer filling pass when rendering impostors - return 1; - } - else if (gSavedSettings.getBOOL("RenderDepthOfField")) - { - return 2; - } - else - { - return 1; - } + return 1; } -void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED); +// set some common parameters on the given shader to prepare for alpha rendering +static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool deferredEnvironment) +{ + static LLCachedControl<F32> displayGamma(gSavedSettings, "RenderDeferredDisplayGamma"); + F32 gamma = displayGamma; + + // Does this deferred shader need environment uniforms set such as sun_dir, etc. ? + // NOTE: We don't actually need a gbuffer since we are doing forward rendering (for transparency) post deferred rendering + // TODO: bindDeferredShader() probably should have the updating of the environment uniforms factored out into updateShaderEnvironmentUniforms() + // i.e. shaders\class1\deferred\alphaF.glsl + if (deferredEnvironment) + { + gPipeline.bindDeferredShader( *shader ); + } + else + { + shader->bind(); + } + shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0); + shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f)); + + if (LLPipeline::sImpostorRender) + { + shader->setMinimumAlpha(MINIMUM_IMPOSTOR_ALPHA); + } + else + { + shader->setMinimumAlpha(MINIMUM_ALPHA); + } + if (textureGamma) + { + shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + } - F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + //also prepare rigged variant + if (shader->mRiggedVariant && shader->mRiggedVariant != shader) + { + prepare_alpha_shader(shader->mRiggedVariant, textureGamma, deferredEnvironment); + } +} + +void LLDrawPoolAlpha::renderPostDeferred(S32 pass) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + deferred_render = TRUE; + // prepare shaders emissive_shader = (LLPipeline::sRenderDeferred) ? &gDeferredEmissiveProgram : (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; + prepare_alpha_shader(emissive_shader, true, false); - emissive_shader->bind(); - emissive_shader->uniform1i(LLShaderMgr::NO_ATMO, (LLPipeline::sRenderingHUDs) ? 1 : 0); - emissive_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - emissive_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); + fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightAlphaMaskProgram : + (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightAlphaMaskProgram; + prepare_alpha_shader(fullbright_shader, true, false); - if (pass == 0) - { - fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram : - (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram; + simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : + (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram; + prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms) - fullbright_shader->bind(); - fullbright_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - fullbright_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); - fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); - fullbright_shader->unbind(); - simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram : - (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram; + // first pass, render rigged objects only and render to depth buffer + forwardRender(true); - //prime simple shader (loads shadow relevant uniforms) - gPipeline.bindDeferredShader(*simple_shader); + // second pass, regular forward alpha rendering + forwardRender(); - simple_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); - } - else if (!LLPipeline::sImpostorRender) - { - //update depth buffer sampler - gPipeline.mScreen.flush(); - gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(), - 0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); - gPipeline.mDeferredDepth.bindTarget(); - simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram; - gObjectFullbrightAlphaMaskProgram.bind(); - gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f); - } + // final pass, render to depth for depth of field effects + if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField")) + { + //update depth buffer sampler + gPipeline.mScreen.flush(); + gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(), + 0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST); + gPipeline.mDeferredDepth.bindTarget(); + simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram; - deferred_render = TRUE; - if (mShaderLevel > 0) - { - // Start out with no shaders. - current_shader = target_shader = NULL; - } - gPipeline.enableLightsDynamic(); -} + simple_shader->bind(); + simple_shader->setMinimumAlpha(0.33f); -void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED); + // mask off color buffer writes as we're only writing to depth buffer + gGL.setColorMask(false, false); - if (pass == 1 && !LLPipeline::sImpostorRender) - { - gPipeline.mDeferredDepth.flush(); - gPipeline.mScreen.bindTarget(); - gObjectFullbrightAlphaMaskProgram.unbind(); - } + // If the face is more than 90% transparent, then don't update the Depth buffer for Dof + // We don't want the nearly invisible objects to cause of DoF effects + renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, + true); // <--- discard mostly transparent faces + + gPipeline.mDeferredDepth.flush(); + gPipeline.mScreen.bindTarget(); + gGL.setColorMask(true, false); + } - deferred_render = FALSE; - endRenderPass(pass); + deferred_render = FALSE; } -void LLDrawPoolAlpha::renderPostDeferred(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED); - render(pass); +//set some generic parameters for forward (non-deferred) rendering +static void prepare_forward_shader(LLGLSLShader* shader, F32 minimum_alpha) +{ + shader->bind(); + shader->setMinimumAlpha(minimum_alpha); + shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); + + //also prepare rigged variant + if (shader->mRiggedVariant && shader->mRiggedVariant != shader) + { + prepare_forward_shader(shader->mRiggedVariant, minimum_alpha); + } } -void LLDrawPoolAlpha::beginRenderPass(S32 pass) +void LLDrawPoolAlpha::render(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SETUP); - - simple_shader = (LLPipeline::sImpostorRender) ? &gObjectSimpleImpostorProgram : - (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram : &gObjectSimpleProgram; + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + + simple_shader = (LLPipeline::sImpostorRender) ? &gObjectSimpleImpostorProgram : + (LLPipeline::sUnderWaterRender) ? &gObjectSimpleWaterProgram : &gObjectSimpleAlphaMaskProgram; - fullbright_shader = (LLPipeline::sImpostorRender) ? &gObjectFullbrightProgram : - (LLPipeline::sUnderWaterRender) ? &gObjectFullbrightWaterProgram : &gObjectFullbrightProgram; + fullbright_shader = (LLPipeline::sImpostorRender) ? &gObjectFullbrightAlphaMaskProgram : + (LLPipeline::sUnderWaterRender) ? &gObjectFullbrightWaterProgram : &gObjectFullbrightAlphaMaskProgram; - emissive_shader = (LLPipeline::sImpostorRender) ? &gObjectEmissiveProgram : - (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; + emissive_shader = (LLPipeline::sImpostorRender) ? &gObjectEmissiveProgram : + (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; + F32 minimum_alpha = MINIMUM_ALPHA; if (LLPipeline::sImpostorRender) - { - if (mShaderLevel > 0) - { - fullbright_shader->bind(); - fullbright_shader->setMinimumAlpha(0.5f); - fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); - simple_shader->bind(); - simple_shader->setMinimumAlpha(0.5f); - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); - } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); //OK - } - } - else - { - if (mShaderLevel > 0) - { - fullbright_shader->bind(); - fullbright_shader->setMinimumAlpha(0.f); - fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); - simple_shader->bind(); - simple_shader->setMinimumAlpha(0.f); - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, LLPipeline::sRenderingHUDs ? 1 : 0); - } - else - { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK - } + { + minimum_alpha = MINIMUM_IMPOSTOR_ALPHA; } - gPipeline.enableLightsDynamic(); + prepare_forward_shader(fullbright_shader, minimum_alpha); + prepare_forward_shader(simple_shader, minimum_alpha); - LLGLSLShader::bindNoShader(); - current_shader = NULL; -} - -void LLDrawPoolAlpha::endRenderPass( S32 pass ) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SETUP); - LLRenderPass::endRenderPass(pass); + //first pass -- rigged only and drawn to depth buffer + forwardRender(true); - if(gPipeline.canUseWindLightShaders()) - { - LLGLSLShader::bindNoShader(); - } + //second pass -- non-rigged, no depth buffer writes + forwardRender(); } -void LLDrawPoolAlpha::render(S32 pass) +void LLDrawPoolAlpha::forwardRender(bool rigged) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA); + gPipeline.enableLightsDynamic(); - LLGLSPipelineAlpha gls_pipeline_alpha; + LLGLSPipelineAlpha gls_pipeline_alpha; - if (deferred_render && pass == 1) - { //depth only - gGL.setColorMask(false, false); - } - else - { - gGL.setColorMask(true, true); - } - - bool write_depth = LLDrawPoolWater::sSkipScreenCopy - || (deferred_render && pass == 1) - // we want depth written so that rendered alpha will - // contribute to the alpha mask used for impostors - || LLPipeline::sImpostorRenderAlphaDepthPass; + //enable writing to alpha for emissive effects + gGL.setColorMask(true, true); - LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE); + bool write_depth = rigged || + LLDrawPoolWater::sSkipScreenCopy + // we want depth written so that rendered alpha will + // contribute to the alpha mask used for impostors + || LLPipeline::sImpostorRenderAlphaDepthPass; - if (deferred_render && pass == 1) - { - gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA); - } - else - { - mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend - mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } - mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression - mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } - gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - } + LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE); - if (mShaderLevel > 0) - { - renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass); - } - else - { - renderAlpha(getVertexDataMask(), pass); - } + mColorSFactor = LLRender::BF_SOURCE_ALPHA; // } regular alpha blend + mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } + mAlphaSFactor = LLRender::BF_ZERO; // } glow suppression + mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // } + gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - gGL.setColorMask(true, false); + // If the face is more than 90% transparent, then don't update the Depth buffer for Dof + // We don't want the nearly invisible objects to cause of DoF effects + renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged); - if (deferred_render && pass == 1) - { - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } + gGL.setColorMask(true, false); + + if (!rigged) + { //render "highlight alpha" on final non-rigged pass + // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender" + // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state + // variables above are still in scope + renderDebugAlpha(); + } +} +void LLDrawPoolAlpha::renderDebugAlpha() +{ if (sShowDebugAlpha) { - BOOL shaders = gPipeline.canUseVertexShaders(); - if(shaders) - { - gHighlightProgram.bind(); - } - else - { - gPipeline.enableLightsFullbright(); - } + gHighlightProgram.bind(); + gGL.diffuseColor4f(1, 0, 0, 1); + LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f * 1024.f); + gGL.getTexUnit(0)->bindFast(LLViewerFetchedTexture::sSmokeImagep); - gGL.diffuseColor4f(1,0,0,1); - - LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f); - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep, TRUE) ; - renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_TEXCOORD0); + renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD0); pushBatches(LLRenderPass::PASS_ALPHA_MASK, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); pushBatches(LLRenderPass::PASS_ALPHA_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); @@ -327,43 +289,85 @@ void LLDrawPoolAlpha::render(S32 pass) gGL.diffuseColor4f(0, 1, 0, 1); pushBatches(LLRenderPass::PASS_INVISIBLE, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); - if(shaders) - { - gHighlightProgram.unbind(); - } + gHighlightProgram.mRiggedVariant->bind(); + gGL.diffuseColor4f(1, 0, 0, 1); + + pushRiggedBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushRiggedBatches(LLRenderPass::PASS_ALPHA_INVISIBLE_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + + // Material alpha mask + gGL.diffuseColor4f(0, 0, 1, 1); + pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushRiggedBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushRiggedBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + + gGL.diffuseColor4f(0, 1, 0, 1); + pushRiggedBatches(LLRenderPass::PASS_INVISIBLE_RIGGED, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, FALSE); + LLGLSLShader::sCurBoundShaderPtr->unbind(); } } void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask) { - for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) - { - LLSpatialGroup* group = *i; - if (group->getSpatialPartition()->mRenderByGroup && - !group->isDead()) - { - LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; + for (int pass = 0; pass < 2; ++pass) + { //two passes, one rigged and one not + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) - { - LLDrawInfo& params = **k; - - if (params.mParticle) - { - continue; - } + LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups(); + LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups(); - LLRenderPass::applyModelMatrix(params); - if (params.mGroup) - { - params.mGroup->rebuildMesh(); - } - params.mVertexBuffer->setBuffer(mask); - params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); - gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); - } - } - } + for (LLCullResult::sg_iterator i = begin; i != end; ++i) + { + LLSpatialGroup* group = *i; + if (group->getSpatialPartition()->mRenderByGroup && + !group->isDead()) + { + LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass + + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) + { + LLDrawInfo& params = **k; + + if (params.mParticle) + { + continue; + } + + bool rigged = (params.mAvatar != nullptr); + gHighlightProgram.bind(rigged); + gGL.diffuseColor4f(1, 0, 0, 1); + + if (rigged) + { + if (lastAvatar != params.mAvatar || + lastMeshId != params.mSkinInfo->mHash) + { + if (!uploadMatrixPalette(params)) + { + continue; + } + lastAvatar = params.mAvatar; + lastMeshId = params.mSkinInfo->mHash; + } + } + + LLRenderPass::applyModelMatrix(params); + if (params.mGroup) + { + params.mGroup->rebuildMesh(); + } + params.mVertexBuffer->setBufferFast(rigged ? mask | LLVertexBuffer::MAP_WEIGHT4 : mask); + params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); + } + } + } + } + + // make sure static version of highlight shader is bound before returning + gHighlightProgram.bind(); } inline bool IsFullbright(LLDrawInfo& params) @@ -383,47 +387,41 @@ inline bool IsEmissive(LLDrawInfo& params) inline void Draw(LLDrawInfo* draw, U32 mask) { - draw->mVertexBuffer->setBuffer(mask); + draw->mVertexBuffer->setBufferFast(mask); LLRenderPass::applyModelMatrix(*draw); - draw->mVertexBuffer->drawRange(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); - gPipeline.addTrianglesDrawn(draw->mCount, draw->mDrawMode); + draw->mVertexBuffer->drawRangeFast(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); } -bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_material, LLGLSLShader* current_shader) +bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_material) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_TEX_BINDS); - bool tex_setup = false; if (deferred_render && use_material && current_shader) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS); if (draw->mNormalMap) - { + { draw->mNormalMap->addTextureStats(draw->mVSize); current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap); } - + if (draw->mSpecularMap) { draw->mSpecularMap->addTextureStats(draw->mVSize); current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap); } } - else if (current_shader == simple_shader) + else if (current_shader == simple_shader || current_shader == simple_shader->mRiggedVariant) { - LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(draw->mVSize); - LLViewerFetchedTexture::sWhiteImagep->addTextureStats(draw->mVSize); - current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); + current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); } - if (use_shaders && draw->mTextureList.size() > 1) + if (draw->mTextureList.size() > 1) { for (U32 i = 0; i < draw->mTextureList.size(); ++i) { if (draw->mTextureList[i].notNull()) { - gGL.getTexUnit(i)->bind(draw->mTextureList[i], TRUE); + gGL.getTexUnit(i)->bindFast(draw->mTextureList[i]); } } } @@ -431,16 +429,15 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_mate { //not batching textures or batch has only 1 texture -- might need a texture matrix if (draw->mTexture.notNull()) { - draw->mTexture->addTextureStats(draw->mVSize); - if (use_shaders && use_material) + if (use_material) { current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, draw->mTexture); } else { - gGL.getTexUnit(0)->bind(draw->mTexture, TRUE) ; + gGL.getTexUnit(0)->bindFast(draw->mTexture); } - + if (draw->mTextureMatrix) { tex_setup = true; @@ -452,7 +449,7 @@ bool LLDrawPoolAlpha::TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_mate } else { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->unbindFast(LLTexUnit::TT_TEXTURE); } } @@ -470,160 +467,83 @@ void LLDrawPoolAlpha::RestoreTexSetup(bool tex_setup) } } -void LLDrawPoolAlpha::renderSimples(U32 mask, std::vector<LLDrawInfo*>& simples) +void LLDrawPoolAlpha::drawEmissive(U32 mask, LLDrawInfo* draw) { - gPipeline.enableLightsDynamic(); - simple_shader->bind(); - simple_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep); - simple_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep); - simple_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, 1.0f, 1.0f, 1.0f, 1.0f); - simple_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, 0.0f); - simple_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 0.0f); - bool use_shaders = gPipeline.canUseVertexShaders(); - for (LLDrawInfo* draw : simples) - { - bool tex_setup = TexSetup(draw, use_shaders, false, simple_shader); - LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); - gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); - - Draw(draw, mask); - RestoreTexSetup(tex_setup); - } - simple_shader->unbind(); + LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); + draw->mVertexBuffer->setBufferFast((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE); + draw->mVertexBuffer->drawRangeFast(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); } -void LLDrawPoolAlpha::renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& fullbrights) -{ - gPipeline.enableLightsFullbright(); - fullbright_shader->bind(); - fullbright_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.0f); - bool use_shaders = gPipeline.canUseVertexShaders(); - for (LLDrawInfo* draw : fullbrights) - { - bool tex_setup = TexSetup(draw, use_shaders, false, fullbright_shader); - LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); - gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); +void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives) +{ + emissive_shader->bind(); + emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); - Draw(draw, mask & ~(LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2)); + for (LLDrawInfo* draw : emissives) + { + bool tex_setup = TexSetup(draw, false); + drawEmissive(mask, draw); RestoreTexSetup(tex_setup); } - fullbright_shader->unbind(); } -void LLDrawPoolAlpha::renderMaterials(U32 mask, std::vector<LLDrawInfo*>& materials) +void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives) { - LLGLSLShader::bindNoShader(); - current_shader = NULL; + LLGLDepthTest depth(GL_TRUE, GL_FALSE); //disable depth writes since "emissive" is additive so sorting doesn't matter + LLGLSLShader* shader = emissive_shader->mRiggedVariant; + shader->bind(); + shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); - gPipeline.enableLightsDynamic(); - bool use_shaders = gPipeline.canUseVertexShaders(); - for (LLDrawInfo* draw : materials) - { - U32 mask = draw->mShaderMask; + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; - llassert(mask < LLMaterial::SHADER_COUNT); - target_shader = (LLPipeline::sUnderWaterRender) ? &(gDeferredMaterialWaterProgram[mask]) : &(gDeferredMaterialProgram[mask]); - - if (current_shader != target_shader) - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS); - if (current_shader) - { - gPipeline.unbindDeferredShader(*current_shader); - } - gPipeline.bindDeferredShader(*target_shader); - current_shader = target_shader; - } - - bool tex_setup = TexSetup(draw, use_shaders, true, current_shader); - - current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, draw->mSpecColor.mV[0], draw->mSpecColor.mV[1], draw->mSpecColor.mV[2], draw->mSpecColor.mV[3]); - current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, draw->mEnvIntensity); - current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, draw->mFullbright ? 1.f : 0.f); + mask |= LLVertexBuffer::MAP_WEIGHT4; + for (LLDrawInfo* draw : emissives) + { + bool tex_setup = TexSetup(draw, false); + if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_TEX_BINDS); - if (draw->mNormalMap) - { - draw->mNormalMap->addTextureStats(draw->mVSize); - current_shader->bindTexture(LLShaderMgr::BUMP_MAP, draw->mNormalMap); - } - - if (draw->mSpecularMap) - { - draw->mSpecularMap->addTextureStats(draw->mVSize); - current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, draw->mSpecularMap); - } + if (!uploadMatrixPalette(*draw)) + { // failed to upload matrix palette, skip rendering + continue; + } + lastAvatar = draw->mAvatar; + lastMeshId = draw->mSkinInfo->mHash; } - - LLGLEnableFunc stencil_test(GL_STENCIL_TEST, draw->mSelected, &LLGLCommonFunc::selected_stencil_test); - gGL.blendFunc((LLRender::eBlendFactor) draw->mBlendFuncSrc, (LLRender::eBlendFactor) draw->mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); - - Draw(draw, mask); + drawEmissive(mask, draw); RestoreTexSetup(tex_setup); } } -void LLDrawPoolAlpha::drawEmissive(U32 mask, LLDrawInfo* draw) +void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) { - draw->mVertexBuffer->setBuffer((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE); - draw->mVertexBuffer->drawRange(draw->mDrawMode, draw->mStart, draw->mEnd, draw->mCount, draw->mOffset); - gPipeline.addTrianglesDrawn(draw->mCount, draw->mDrawMode); -} + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + BOOL initialized_lighting = FALSE; + BOOL light_enabled = TRUE; -void LLDrawPoolAlpha::drawEmissiveInline(U32 mask, LLDrawInfo* draw) -{ - // install glow-accumulating blend mode - gGL.blendFunc( - LLRender::BF_ZERO, LLRender::BF_ONE, // don't touch color - LLRender::BF_ONE, LLRender::BF_ONE); // add to alpha (glow) - - emissive_shader->bind(); - - drawEmissive(mask, draw); + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + LLGLSLShader* lastAvatarShader = nullptr; - // restore our alpha blend mode - gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - - current_shader->bind(); -} + LLCullResult::sg_iterator begin; + LLCullResult::sg_iterator end; -void LLDrawPoolAlpha::renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives) -{ - emissive_shader->bind(); - emissive_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, 1.f); - - gPipeline.enableLightsDynamic(); - - // install glow-accumulating blend mode - // don't touch color, add to alpha (glow) - gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE); - bool use_shaders = gPipeline.canUseVertexShaders(); - for (LLDrawInfo* draw : emissives) + if (rigged) { - bool tex_setup = TexSetup(draw, use_shaders, false, emissive_shader); - drawEmissive(mask, draw); - RestoreTexSetup(tex_setup); + begin = gPipeline.beginRiggedAlphaGroups(); + end = gPipeline.endRiggedAlphaGroups(); + } + else + { + begin = gPipeline.beginAlphaGroups(); + end = gPipeline.endAlphaGroups(); } - // restore our alpha blend mode - gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); - - emissive_shader->unbind(); -} - -void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) -{ - static LLCachedControl<bool> batch_fullbrights(gSavedSettings, "RenderAlphaBatchFullbrights"); - static LLCachedControl<bool> batch_emissives(gSavedSettings, "RenderAlphaBatchEmissives"); - bool initialized_lighting = FALSE; - bool light_enabled = TRUE; - - bool use_shaders = gPipeline.canUseVertexShaders(); - - for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i) + for (LLCullResult::sg_iterator i = begin; i != end; ++i) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group"); LLSpatialGroup* group = *i; llassert(group); llassert(group->getSpatialPartition()); @@ -631,25 +551,31 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) if (group->getSpatialPartition()->mRenderByGroup && !group->isDead()) { - std::vector<LLDrawInfo*> emissives; - std::vector<LLDrawInfo*> fullbrights; + static std::vector<LLDrawInfo*> emissives; + static std::vector<LLDrawInfo*> rigged_emissives; + emissives.resize(0); + rigged_emissives.resize(0); bool is_particle_or_hud_particle = group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_PARTICLE || group->getSpatialPartition()->mPartitionType == LLViewerRegion::PARTITION_HUD_PARTICLE; bool draw_glow_for_this_partition = mShaderLevel > 0; // no shaders = no glow. - - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_GROUP_LOOP); - bool disable_cull = is_particle_or_hud_particle; LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0); - LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA]; + LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA]; for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; + if ((bool)params.mAvatar != rigged) + { + continue; + } + + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch") + U32 have_mask = params.mVertexBuffer->getTypeMask() & mask; if (have_mask != mask) { //FIXME! @@ -659,29 +585,21 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) continue; } - // Fix for bug - NORSPEC-271 - // If the face is more than 90% transparent, then don't update the Depth buffer for Dof - // We don't want the nearly invisible objects to cause of DoF effects - if(pass == 1 && !LLPipeline::sImpostorRender) + if(depth_only) { + // when updating depth buffer, discard faces that are more than 90% transparent LLFace* face = params.mFace; if(face) { const LLTextureEntry* tep = face->getTextureEntry(); if(tep) - { - if(tep->getColor().mV[3] < 0.1f) + { // don't render faces that are more than 90% transparent + if(tep->getColor().mV[3] < MINIMUM_IMPOSTOR_ALPHA) continue; } } } - if (params.mFullbright && batch_fullbrights) - { - fullbrights.push_back(¶ms); - continue; - } - LLRenderPass::applyModelMatrix(params); LLMaterial* mat = NULL; @@ -696,34 +614,17 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) // Turn off lighting if it hasn't already been so. if (light_enabled || !initialized_lighting) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_LIGHT_SETUP); - initialized_lighting = TRUE; - if (use_shaders) - { - target_shader = fullbright_shader; - } - else - { - gPipeline.enableLightsFullbright(); - } + target_shader = fullbright_shader; + light_enabled = FALSE; } } // Turn on lighting if it isn't already. else if (!light_enabled || !initialized_lighting) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_LIGHT_SETUP); - initialized_lighting = TRUE; - if (use_shaders) - { - target_shader = simple_shader; - } - else - { - gPipeline.enableLightsDynamic(); - } + target_shader = simple_shader; light_enabled = TRUE; } @@ -739,11 +640,15 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) target_shader = &(gDeferredMaterialWaterProgram[mask]); } + if (params.mAvatar != nullptr) + { + llassert(target_shader->mRiggedVariant != nullptr); + target_shader = target_shader->mRiggedVariant; + } + if (current_shader != target_shader) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DEFERRED_SHADER_BINDS); gPipeline.bindDeferredShader(*target_shader); - current_shader = target_shader; } } else if (!params.mFullbright) @@ -755,25 +660,23 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) target_shader = fullbright_shader; } - if(use_shaders && (current_shader != target_shader)) - {// If we need shaders, and we're not ALREADY using the proper shader, then bind it - // (this way we won't rebind shaders unnecessarily). - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_SHADER_BINDS); - current_shader = target_shader; - current_shader->bind(); - } - else if (!use_shaders && current_shader != NULL) - { - LLGLSLShader::bindNoShader(); - current_shader = NULL; - } + if (params.mAvatar != nullptr) + { + target_shader = target_shader->mRiggedVariant; + } + + if (current_shader != target_shader) + {// If we need shaders, and we're not ALREADY using the proper shader, then bind it + // (this way we won't rebind shaders unnecessarily). + target_shader->bind(); + } LLVector4 spec_color(1, 1, 1, 1); F32 env_intensity = 0.0f; F32 brightness = 1.0f; // We have a material. Supply the appropriate data here. - if (use_shaders && mat && deferred_render) + if (mat && deferred_render) { spec_color = params.mSpecColor; env_intensity = params.mEnvIntensity; @@ -782,7 +685,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) if (current_shader) { - current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]); + current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, spec_color.mV[0], spec_color.mV[1], spec_color.mV[2], spec_color.mV[3]); current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env_intensity); current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, brightness); } @@ -792,38 +695,54 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) params.mGroup->rebuildMesh(); } - bool tex_setup = TexSetup(¶ms, use_shaders, use_shaders && (mat != nullptr), current_shader); + if (params.mAvatar != nullptr) + { + if (lastAvatar != params.mAvatar || + lastMeshId != params.mSkinInfo->mHash || + lastAvatarShader != LLGLSLShader::sCurBoundShaderPtr) + { + if (!uploadMatrixPalette(params)) + { + continue; + } + lastAvatar = params.mAvatar; + lastMeshId = params.mSkinInfo->mHash; + lastAvatarShader = LLGLSLShader::sCurBoundShaderPtr; + } + } + + bool tex_setup = TexSetup(¶ms, (mat != nullptr)); { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_PUSH); - LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test); gGL.blendFunc((LLRender::eBlendFactor) params.mBlendFuncSrc, (LLRender::eBlendFactor) params.mBlendFuncDst, mAlphaSFactor, mAlphaDFactor); - params.mVertexBuffer->setBuffer(mask & ~(params.mFullbright ? (LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2) : 0)); - + U32 drawMask = mask; + if (params.mFullbright) + { + drawMask &= ~(LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2); + } + if (params.mAvatar != nullptr) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_DRAW); - params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); - gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); + drawMask |= LLVertexBuffer::MAP_WEIGHT4; } + + params.mVertexBuffer->setBufferFast(drawMask); + params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); } // If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow). Interleaving these state-changing calls is expensive, but glow must be drawn Z-sorted with alpha. - if (current_shader && - draw_glow_for_this_partition && + if (draw_glow_for_this_partition && params.mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE)) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_EMISSIVE); - - if (batch_emissives) + if (params.mAvatar != nullptr) { - emissives.push_back(¶ms); + rigged_emissives.push_back(¶ms); } else { - drawEmissiveInline(mask, ¶ms); - } + emissives.push_back(¶ms); + } } if (tex_setup) @@ -835,31 +754,71 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass) } } - if (batch_fullbrights) + // render emissive faces into alpha channel for bloom effects + if (!depth_only) { - light_enabled = false; - renderFullbrights(mask, fullbrights); - } + gPipeline.enableLightsDynamic(); - if (batch_emissives) - { - light_enabled = true; - renderEmissives(mask, emissives); - } + // install glow-accumulating blend mode + // don't touch color, add to alpha (glow) + gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, LLRender::BF_ONE, LLRender::BF_ONE); - if (current_shader) - { - current_shader->bind(); + bool rebind = false; + LLGLSLShader* lastShader = current_shader; + if (!emissives.empty()) + { + light_enabled = true; + renderEmissives(mask, emissives); + rebind = true; + } + + if (!rigged_emissives.empty()) + { + light_enabled = true; + renderRiggedEmissives(mask, rigged_emissives); + rebind = true; + } + + // restore our alpha blend mode + gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor); + + if (lastShader && rebind) + { + lastShader->bind(); + } } - } + } } gGL.setSceneBlendType(LLRender::BT_ALPHA); - LLVertexBuffer::unbind(); - + LLVertexBuffer::unbind(); + if (!light_enabled) { gPipeline.enableLightsDynamic(); } } + +bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params) +{ + if (params.mAvatar.isNull()) + { + return false; + } + const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo); + U32 count = mpc.mMatrixPalette.size(); + + if (count == 0) + { + //skin info not loaded yet, don't render + return false; + } + + LLGLSLShader::sCurBoundShaderPtr->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, + count, + FALSE, + (GLfloat*)&(mpc.mGLMp[0])); + + return true; +} diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h index a069f805e8..fa8ef0f227 100644 --- a/indra/newview/lldrawpoolalpha.h +++ b/indra/newview/lldrawpoolalpha.h @@ -51,39 +51,34 @@ public: /*virtual*/ ~LLDrawPoolAlpha(); /*virtual*/ S32 getNumPostDeferredPasses(); - /*virtual*/ void beginPostDeferredPass(S32 pass); - /*virtual*/ void endPostDeferredPass(S32 pass); /*virtual*/ void renderPostDeferred(S32 pass); - - /*virtual*/ void beginRenderPass(S32 pass = 0); - /*virtual*/ void endRenderPass( S32 pass ); /*virtual*/ S32 getNumPasses() { return 1; } virtual void render(S32 pass = 0); + void forwardRender(bool write_depth = false); /*virtual*/ void prerender(); + void renderDebugAlpha(); + void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE); - void renderAlpha(U32 mask, S32 pass); + void renderAlpha(U32 mask, bool depth_only = false, bool rigged = false); void renderAlphaHighlight(U32 mask); - + bool uploadMatrixPalette(const LLDrawInfo& params); + static BOOL sShowDebugAlpha; private: - LLGLSLShader* current_shader; LLGLSLShader* target_shader; - LLGLSLShader* simple_shader; - LLGLSLShader* fullbright_shader; - LLGLSLShader* emissive_shader; - void renderSimples(U32 mask, std::vector<LLDrawInfo*>& simples); - void renderFullbrights(U32 mask, std::vector<LLDrawInfo*>& fullbrights); - void renderMaterials(U32 mask, std::vector<LLDrawInfo*>& fullbrights); - void renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives); + // setup by beginFooPass, [0] is static variant, [1] is rigged variant + LLGLSLShader* simple_shader = nullptr; + LLGLSLShader* fullbright_shader = nullptr; + LLGLSLShader* emissive_shader = nullptr; void drawEmissive(U32 mask, LLDrawInfo* draw); - void drawEmissiveInline(U32 mask, LLDrawInfo* draw); - - bool TexSetup(LLDrawInfo* draw, bool use_shaders, bool use_material, LLGLSLShader* current_shader); + void renderEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives); + void renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>& emissives); + bool TexSetup(LLDrawInfo* draw, bool use_material); void RestoreTexSetup(bool tex_setup); // our 'normal' alpha blend function for this pass @@ -91,6 +86,9 @@ private: LLRender::eBlendFactor mColorDFactor; LLRender::eBlendFactor mAlphaSFactor; LLRender::eBlendFactor mAlphaDFactor; + + // if true, we're executing a rigged render pass + bool mRigged = false; }; class LLDrawPoolAlphaPostWater : public LLDrawPoolAlpha diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 76cbe85b7e..4a9a3caaec 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -103,8 +103,6 @@ S32 normal_channel = -1; S32 specular_channel = -1; S32 cube_channel = -1; -static LLTrace::BlockTimerStatHandle FTM_SHADOW_AVATAR("Avatar Shadow"); - LLDrawPoolAvatar::LLDrawPoolAvatar(U32 type) : LLFacePool(type) { @@ -121,28 +119,27 @@ LLDrawPoolAvatar::~LLDrawPoolAvatar() // virtual BOOL LLDrawPoolAvatar::isDead() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + if (!LLFacePool::isDead()) { return FALSE; } - for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) - { - if (mRiggedFace[i].size() > 0) - { - return FALSE; - } - } return TRUE; } S32 LLDrawPoolAvatar::getShaderLevel() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + return (S32) LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR); } void LLDrawPoolAvatar::prerender() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_AVATAR); sShaderLevel = mShaderLevel; @@ -155,20 +152,12 @@ void LLDrawPoolAvatar::prerender() { sBufferUsage = GL_STREAM_DRAW_ARB; } - - if (!mDrawFace.empty()) - { - const LLFace *facep = mDrawFace[0]; - if (facep && facep->getDrawable()) - { - LLVOAvatar* avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); - updateRiggedVertexBuffers(avatarp); - } - } } LLMatrix4& LLDrawPoolAvatar::getModelView() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + static LLMatrix4 ret; ret.initRows(LLVector4(gGLModelView+0), @@ -187,7 +176,7 @@ LLMatrix4& LLDrawPoolAvatar::getModelView() void LLDrawPoolAvatar::beginDeferredPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; sSkipTransparent = TRUE; is_deferred_render = true; @@ -208,21 +197,12 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass) case 2: beginDeferredSkinned(); break; - case 3: - beginDeferredRiggedSimple(); - break; - case 4: - beginDeferredRiggedBump(); - break; - default: - beginDeferredRiggedMaterial(pass-5); - break; } } void LLDrawPoolAvatar::endDeferredPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; sSkipTransparent = FALSE; is_deferred_render = false; @@ -243,58 +223,25 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass) case 2: endDeferredSkinned(); break; - case 3: - endDeferredRiggedSimple(); - break; - case 4: - endDeferredRiggedBump(); - break; - default: - endDeferredRiggedMaterial(pass-5); - break; } } void LLDrawPoolAvatar::renderDeferred(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + render(pass); } S32 LLDrawPoolAvatar::getNumPostDeferredPasses() { - return 10; + return 1; } void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass) { - switch (pass) - { - case 0: - beginPostDeferredAlpha(); - break; - case 1: - beginRiggedFullbright(); - break; - case 2: - beginRiggedFullbrightShiny(); - break; - case 3: - beginDeferredRiggedAlpha(); - break; - case 4: - beginRiggedFullbrightAlpha(); - break; - case 9: - beginRiggedGlow(); - break; - default: - beginDeferredRiggedMaterialAlpha(pass-5); - break; - } -} + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR -void LLDrawPoolAvatar::beginPostDeferredAlpha() -{ sSkipOpaque = TRUE; sShaderLevel = mShaderLevel; sVertexProgram = &gDeferredAvatarAlphaProgram; @@ -307,80 +254,9 @@ void LLDrawPoolAvatar::beginPostDeferredAlpha() sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } -void LLDrawPoolAvatar::beginDeferredRiggedAlpha() -{ - sVertexProgram = &gDeferredSkinnedAlphaProgram; - gPipeline.bindDeferredShader(*sVertexProgram); - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - gPipeline.enableLightsDynamic(); -} - -void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass) -{ - switch (pass) - { - case 0: pass = 1; break; - case 1: pass = 5; break; - case 2: pass = 9; break; - default: pass = 13; break; - } - - pass += LLMaterial::SHADER_COUNT; - - sVertexProgram = &gDeferredMaterialProgram[pass]; - - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &(gDeferredMaterialWaterProgram[pass]); - } - - gPipeline.bindDeferredShader(*sVertexProgram); - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); - specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP); - gPipeline.enableLightsDynamic(); -} - -void LLDrawPoolAvatar::endDeferredRiggedAlpha() -{ - LLVertexBuffer::unbind(); - gPipeline.unbindDeferredShader(*sVertexProgram); - sDiffuseChannel = 0; - normal_channel = -1; - specular_channel = -1; - sVertexProgram = NULL; -} - void LLDrawPoolAvatar::endPostDeferredPass(S32 pass) { - switch (pass) - { - case 0: - endPostDeferredAlpha(); - break; - case 1: - endRiggedFullbright(); - break; - case 2: - endRiggedFullbrightShiny(); - break; - case 3: - endDeferredRiggedAlpha(); - break; - case 4: - endRiggedFullbrightAlpha(); - break; - case 5: - endRiggedGlow(); - break; - default: - endDeferredRiggedAlpha(); - break; - } -} - -void LLDrawPoolAvatar::endPostDeferredAlpha() -{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done sRenderingSkinned = FALSE; sSkipOpaque = FALSE; @@ -392,29 +268,17 @@ void LLDrawPoolAvatar::endPostDeferredAlpha() void LLDrawPoolAvatar::renderPostDeferred(S32 pass) { - static const S32 actual_pass[] = - { //map post deferred pass numbers to what render() expects - 2, //skinned - 4, // rigged fullbright - 6, //rigged fullbright shiny - 7, //rigged alpha - 8, //rigged fullbright alpha - 9, //rigged material alpha 1 - 10,//rigged material alpha 2 - 11,//rigged material alpha 3 - 12,//rigged material alpha 4 - 13, //rigged glow - }; - - S32 p = actual_pass[pass]; + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + is_post_deferred_render = true; if (LLPipeline::sImpostorRender) { //HACK for impostors so actual pass ends up being proper pass - p -= 2; + render(0); + } + else + { + render(2); } - - is_post_deferred_render = true; - render(p); is_post_deferred_render = false; } @@ -427,7 +291,7 @@ S32 LLDrawPoolAvatar::getNumShadowPasses() void LLDrawPoolAvatar::beginShadowPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (pass == SHADOW_PASS_AVATAR_OPAQUE) { @@ -439,7 +303,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) sVertexProgram->bind(); } - gGL.diffuseColor4f(1,1,1,1); + gGL.diffuseColor4f(1, 1, 1, 1); } else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND) { @@ -459,7 +323,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) sVertexProgram->bind(); } - gGL.diffuseColor4f(1,1,1,1); + gGL.diffuseColor4f(1, 1, 1, 1); } else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK) { @@ -479,69 +343,13 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) sVertexProgram->bind(); } - gGL.diffuseColor4f(1,1,1,1); - } - else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND) - { - sVertexProgram = &gDeferredAttachmentAlphaShadowProgram; - - // bind diffuse tex so we can reference the alpha channel... - S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); - sDiffuseChannel = 0; - if (loc != -1) - { - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - - if ((sShaderLevel > 0)) // for hardware blending - { - sRenderingSkinned = TRUE; - sVertexProgram->bind(); - } - - gGL.diffuseColor4f(1,1,1,1); - } - else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK) - { - sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram; - - // bind diffuse tex so we can reference the alpha channel... - S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); - sDiffuseChannel = 0; - if (loc != -1) - { - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - - if ((sShaderLevel > 0)) // for hardware blending - { - sRenderingSkinned = TRUE; - sVertexProgram->bind(); - } - - gGL.diffuseColor4f(1,1,1,1); - } - else // SHADOW_PASS_ATTACHMENT_OPAQUE - { - sVertexProgram = &gDeferredAttachmentShadowProgram; - S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); - sDiffuseChannel = 0; - if (loc != -1) - { - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - sVertexProgram->bind(); + gGL.diffuseColor4f(1, 1, 1, 1); } } void LLDrawPoolAvatar::endShadowPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); - - if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE) - { - LLVertexBuffer::unbind(); - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (sShaderLevel > 0) { @@ -554,7 +362,7 @@ void LLDrawPoolAvatar::endShadowPass(S32 pass) void LLDrawPoolAvatar::renderShadow(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (mDrawFace.empty()) { @@ -574,9 +382,9 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) } LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); - if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE)) + if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE)) { - // No shadows for impostored (including jellydolled) or invisible avs. + // No shadows for impostored (including jellydolled) or invisible avs. return; } @@ -600,79 +408,23 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) avatarp->renderSkinned(); LLDrawPoolAvatar::sSkipOpaque = false; } - else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND) // rigged alpha - { - LLDrawPoolAvatar::sSkipOpaque = true; - renderRigged(avatarp, RIGGED_MATERIAL_ALPHA); - renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE); - renderRigged(avatarp, RIGGED_ALPHA); - renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA); - renderRigged(avatarp, RIGGED_GLOW); - renderRigged(avatarp, RIGGED_SPECMAP_BLEND); - renderRigged(avatarp, RIGGED_NORMMAP_BLEND); - renderRigged(avatarp, RIGGED_NORMSPEC_BLEND); - LLDrawPoolAvatar::sSkipOpaque = false; - } - else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK) // rigged alpha mask - { - LLDrawPoolAvatar::sSkipOpaque = true; - renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK); - renderRigged(avatarp, RIGGED_NORMMAP_MASK); - renderRigged(avatarp, RIGGED_SPECMAP_MASK); - renderRigged(avatarp, RIGGED_NORMSPEC_MASK); - renderRigged(avatarp, RIGGED_GLOW); - LLDrawPoolAvatar::sSkipOpaque = false; - } - else // rigged opaque (SHADOW_PASS_ATTACHMENT_OPAQUE - { - LLDrawPoolAvatar::sSkipTransparent = true; - renderRigged(avatarp, RIGGED_MATERIAL); - renderRigged(avatarp, RIGGED_SPECMAP); - renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE); - renderRigged(avatarp, RIGGED_NORMMAP); - renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE); - renderRigged(avatarp, RIGGED_NORMSPEC); - renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE); - renderRigged(avatarp, RIGGED_SIMPLE); - renderRigged(avatarp, RIGGED_FULLBRIGHT); - renderRigged(avatarp, RIGGED_SHINY); - renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY); - renderRigged(avatarp, RIGGED_GLOW); - renderRigged(avatarp, RIGGED_DEFERRED_BUMP); - renderRigged(avatarp, RIGGED_DEFERRED_SIMPLE); - LLDrawPoolAvatar::sSkipTransparent = false; - } } S32 LLDrawPoolAvatar::getNumPasses() { - if (LLPipeline::sImpostorRender) - { - return 8; - } - else - { - return 10; - } + return 3; } S32 LLDrawPoolAvatar::getNumDeferredPasses() { - if (LLPipeline::sImpostorRender) - { - return 19; - } - else - { - return 21; - } + return 3; } void LLDrawPoolAvatar::render(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (LLPipeline::sImpostorRender) { renderAvatars(NULL, pass+2); @@ -684,7 +436,7 @@ void LLDrawPoolAvatar::render(S32 pass) void LLDrawPoolAvatar::beginRenderPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; //reset vertex buffer mappings LLVertexBuffer::unbind(); @@ -704,27 +456,6 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass) case 2: beginSkinned(); break; - case 3: - beginRiggedSimple(); - break; - case 4: - beginRiggedFullbright(); - break; - case 5: - beginRiggedShinySimple(); - break; - case 6: - beginRiggedFullbrightShiny(); - break; - case 7: - beginRiggedAlpha(); - break; - case 8: - beginRiggedFullbrightAlpha(); - break; - case 9: - beginRiggedGlow(); - break; } if (pass == 0) @@ -735,7 +466,7 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass) void LLDrawPoolAvatar::endRenderPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (LLPipeline::sImpostorRender) { @@ -753,43 +484,21 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass) case 2: endSkinned(); break; - case 3: - endRiggedSimple(); - break; - case 4: - endRiggedFullbright(); - break; - case 5: - endRiggedShinySimple(); - break; - case 6: - endRiggedFullbrightShiny(); - break; - case 7: - endRiggedAlpha(); - break; - case 8: - endRiggedFullbrightAlpha(); - break; - case 9: - endRiggedGlow(); - break; } } void LLDrawPoolAvatar::beginImpostor() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + if (!LLPipeline::sReflectionRender) { LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f); LLVOAvatar::sNumVisibleAvatars = 0; } - if (LLGLSLShader::sNoFixedFunction) - { gImpostorProgram.bind(); gImpostorProgram.setMinimumAlpha(0.01f); - } gPipeline.enableLightsFullbright(); sDiffuseChannel = 0; @@ -797,16 +506,17 @@ void LLDrawPoolAvatar::beginImpostor() void LLDrawPoolAvatar::endImpostor() { - if (LLGLSLShader::sNoFixedFunction) - { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + gImpostorProgram.unbind(); - } gPipeline.enableLightsDynamic(); } void LLDrawPoolAvatar::beginRigid() { - if (gPipeline.canUseVertexShaders()) + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + + if (gPipeline.shadersLoaded()) { if (LLPipeline::sUnderWaterRender) { @@ -839,6 +549,8 @@ void LLDrawPoolAvatar::beginRigid() void LLDrawPoolAvatar::endRigid() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + sShaderLevel = mShaderLevel; if (sVertexProgram != NULL) { @@ -848,6 +560,8 @@ void LLDrawPoolAvatar::endRigid() void LLDrawPoolAvatar::beginDeferredImpostor() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + if (!LLPipeline::sReflectionRender) { LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f); @@ -864,6 +578,8 @@ void LLDrawPoolAvatar::beginDeferredImpostor() void LLDrawPoolAvatar::endDeferredImpostor() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + sShaderLevel = mShaderLevel; sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL); sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP); @@ -875,6 +591,8 @@ void LLDrawPoolAvatar::endDeferredImpostor() void LLDrawPoolAvatar::beginDeferredRigid() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + sVertexProgram = &gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram; sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->bind(); @@ -891,6 +609,8 @@ void LLDrawPoolAvatar::beginDeferredRigid() void LLDrawPoolAvatar::endDeferredRigid() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + sShaderLevel = mShaderLevel; sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); sVertexProgram->unbind(); @@ -900,6 +620,8 @@ void LLDrawPoolAvatar::endDeferredRigid() void LLDrawPoolAvatar::beginSkinned() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + if (sShaderLevel > 0) { if (LLPipeline::sUnderWaterRender) @@ -942,7 +664,7 @@ void LLDrawPoolAvatar::beginSkinned() } else { - if(gPipeline.canUseVertexShaders()) + if(gPipeline.shadersLoaded()) { // software skinning, use a basic shader for windlight. // TODO: find a better fallback method for software skinning. @@ -958,14 +680,13 @@ void LLDrawPoolAvatar::beginSkinned() } } - if (LLGLSLShader::sNoFixedFunction) - { sVertexProgram->setMinimumAlpha(LLDrawPoolAvatar::sMinimumAlpha); - } } void LLDrawPoolAvatar::endSkinned() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done if (sShaderLevel > 0) { @@ -977,7 +698,7 @@ void LLDrawPoolAvatar::endSkinned() } else { - if(gPipeline.canUseVertexShaders()) + if(gPipeline.shadersLoaded()) { // software skinning, use a basic shader for windlight. // TODO: find a better fallback method for software skinning. @@ -988,424 +709,10 @@ void LLDrawPoolAvatar::endSkinned() gGL.getTexUnit(0)->activate(); } -void LLDrawPoolAvatar::beginRiggedSimple() -{ - if (sShaderLevel > 0) - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectSimpleWaterProgram; - } - else - { - sVertexProgram = &gSkinnedObjectSimpleProgram; - } - } - else - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectSimpleNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectSimpleNonIndexedProgram; - } - } - - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sDiffuseChannel = 0; - sVertexProgram->bind(); - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - } -} - -void LLDrawPoolAvatar::endRiggedSimple() -{ - LLVertexBuffer::unbind(); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sVertexProgram->unbind(); - sVertexProgram = NULL; - } -} - -void LLDrawPoolAvatar::beginRiggedAlpha() -{ - beginRiggedSimple(); -} - -void LLDrawPoolAvatar::endRiggedAlpha() -{ - endRiggedSimple(); -} - - -void LLDrawPoolAvatar::beginRiggedFullbrightAlpha() -{ - beginRiggedFullbright(); -} - -void LLDrawPoolAvatar::endRiggedFullbrightAlpha() -{ - endRiggedFullbright(); -} - -void LLDrawPoolAvatar::beginRiggedGlow() -{ - if (sShaderLevel > 0) - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectEmissiveWaterProgram; - } - else - { - sVertexProgram = &gSkinnedObjectEmissiveProgram; - } - } - else - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectEmissiveNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectEmissiveNonIndexedProgram; - } - } - - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sDiffuseChannel = 0; - sVertexProgram->bind(); - - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f); - - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - - F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); - sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); - } -} - -void LLDrawPoolAvatar::endRiggedGlow() -{ - endRiggedFullbright(); -} - -void LLDrawPoolAvatar::beginRiggedFullbright() -{ - if (sShaderLevel > 0) - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectFullbrightWaterProgram; - } - else - { - if (LLPipeline::sRenderDeferred) - { - sVertexProgram = &gDeferredSkinnedFullbrightProgram; - } - else - { - sVertexProgram = &gSkinnedObjectFullbrightProgram; - } - } - } - else - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectFullbrightNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectFullbrightNonIndexedProgram; - } - } - - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sDiffuseChannel = 0; - sVertexProgram->bind(); - - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else if (LLPipeline::sRenderDeferred) - { - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); - sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); - } - else - { - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - } -} - -void LLDrawPoolAvatar::endRiggedFullbright() -{ - LLVertexBuffer::unbind(); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sVertexProgram->unbind(); - sVertexProgram = NULL; - } -} - -void LLDrawPoolAvatar::beginRiggedShinySimple() -{ - if (sShaderLevel > 0) - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectShinySimpleWaterProgram; - } - else - { - sVertexProgram = &gSkinnedObjectShinySimpleProgram; - } - } - else - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectShinyNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectShinyNonIndexedProgram; - } - } - - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sVertexProgram->bind(); - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); - } -} - -void LLDrawPoolAvatar::endRiggedShinySimple() -{ - LLVertexBuffer::unbind(); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); - sVertexProgram->unbind(); - sVertexProgram = NULL; - } -} - -void LLDrawPoolAvatar::beginRiggedFullbrightShiny() -{ - if (sShaderLevel > 0) - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gSkinnedObjectFullbrightShinyWaterProgram; - } - else - { - if (LLPipeline::sRenderDeferred) - { - sVertexProgram = &gDeferredSkinnedFullbrightShinyProgram; - } - else - { - sVertexProgram = &gSkinnedObjectFullbrightShinyProgram; - } - } - } - else - { - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &gObjectFullbrightShinyNonIndexedWaterProgram; - } - else - { - sVertexProgram = &gObjectFullbrightShinyNonIndexedProgram; - } - } - - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - sVertexProgram->bind(); - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); - - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else if (LLPipeline::sRenderDeferred) - { - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); - sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f)); - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - else - { - sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - } -} - -void LLDrawPoolAvatar::endRiggedFullbrightShiny() -{ - LLVertexBuffer::unbind(); - if (sShaderLevel > 0 || gPipeline.canUseVertexShaders()) - { - LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false); - sVertexProgram->unbind(); - sVertexProgram = NULL; - } -} - - -void LLDrawPoolAvatar::beginDeferredRiggedSimple() -{ - sVertexProgram = &gDeferredSkinnedDiffuseProgram; - sDiffuseChannel = 0; - sVertexProgram->bind(); - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } -} - -void LLDrawPoolAvatar::endDeferredRiggedSimple() -{ - LLVertexBuffer::unbind(); - sVertexProgram->unbind(); - sVertexProgram = NULL; -} - -void LLDrawPoolAvatar::beginDeferredRiggedBump() -{ - sVertexProgram = &gDeferredSkinnedBumpProgram; - sVertexProgram->bind(); - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); -} - -void LLDrawPoolAvatar::endDeferredRiggedBump() -{ - LLVertexBuffer::unbind(); - sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP); - sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - sVertexProgram->unbind(); - normal_channel = -1; - sDiffuseChannel = 0; - sVertexProgram = NULL; -} - -void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass) -{ - if (pass == 1 || - pass == 5 || - pass == 9 || - pass == 13) - { //skip alpha passes - return; - } - sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT]; - - if (LLPipeline::sUnderWaterRender) - { - sVertexProgram = &(gDeferredMaterialWaterProgram[pass+LLMaterial::SHADER_COUNT]); - } - - sVertexProgram->bind(); - if (LLPipeline::sRenderingHUDs) - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - sVertexProgram->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP); - specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP); - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); -} - -void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass) -{ - if (pass == 1 || - pass == 5 || - pass == 9 || - pass == 13) - { - return; - } - - LLVertexBuffer::unbind(); - sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP); - sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP); - sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - sVertexProgram->unbind(); - normal_channel = -1; - sDiffuseChannel = 0; - sVertexProgram = NULL; -} - void LLDrawPoolAvatar::beginDeferredSkinned() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + sShaderLevel = mShaderLevel; sVertexProgram = &gDeferredAvatarProgram; sRenderingSkinned = TRUE; @@ -1427,6 +734,8 @@ void LLDrawPoolAvatar::beginDeferredSkinned() void LLDrawPoolAvatar::endDeferredSkinned() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + // if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done sRenderingSkinned = FALSE; sVertexProgram->unbind(); @@ -1438,12 +747,9 @@ void LLDrawPoolAvatar::endDeferredSkinned() gGL.getTexUnit(0)->activate(); } -static LLTrace::BlockTimerStatHandle FTM_RENDER_AVATARS("renderAvatars"); - - void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_AVATARS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; //LL_RECORD_BLOCK_TIME(FTM_RENDER_CHARACTERS); if (pass == -1) { @@ -1564,142 +870,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } - if (pass == 3) - { - if (is_deferred_render) - { - renderDeferredRiggedSimple(avatarp); - } - else - { - renderRiggedSimple(avatarp); - - if (LLPipeline::sRenderDeferred) - { //render "simple" materials - renderRigged(avatarp, RIGGED_MATERIAL); - renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK); - renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE); - renderRigged(avatarp, RIGGED_NORMMAP); - renderRigged(avatarp, RIGGED_NORMMAP_MASK); - renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE); - renderRigged(avatarp, RIGGED_SPECMAP); - renderRigged(avatarp, RIGGED_SPECMAP_MASK); - renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE); - renderRigged(avatarp, RIGGED_NORMSPEC); - renderRigged(avatarp, RIGGED_NORMSPEC_MASK); - renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE); - } - } - return; - } - - if (pass == 4) - { - if (is_deferred_render) - { - renderDeferredRiggedBump(avatarp); - } - else - { - renderRiggedFullbright(avatarp); - } - - return; - } - - if (is_deferred_render && pass >= 5 && pass <= 21) - { - S32 p = pass-5; - - if (p != 1 && - p != 5 && - p != 9 && - p != 13) - { - renderDeferredRiggedMaterial(avatarp, p); - } - return; - } - - - - - if (pass == 5) - { - renderRiggedShinySimple(avatarp); - - return; - } - - if (pass == 6) - { - renderRiggedFullbrightShiny(avatarp); - return; - } - - if (pass >= 7 && pass < 13) - { - if (pass == 7) - { - renderRiggedAlpha(avatarp); - - if (LLPipeline::sRenderDeferred && !is_post_deferred_render) - { //render transparent materials under water - LLGLEnable blend(GL_BLEND); - - gGL.setColorMask(true, true); - gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, - LLRender::BF_ONE_MINUS_SOURCE_ALPHA, - LLRender::BF_ZERO, - LLRender::BF_ONE_MINUS_SOURCE_ALPHA); - - renderRigged(avatarp, RIGGED_MATERIAL_ALPHA); - renderRigged(avatarp, RIGGED_SPECMAP_BLEND); - renderRigged(avatarp, RIGGED_NORMMAP_BLEND); - renderRigged(avatarp, RIGGED_NORMSPEC_BLEND); - - gGL.setColorMask(true, false); - } - return; - } - - if (pass == 8) - { - renderRiggedFullbrightAlpha(avatarp); - return; - } - - if (LLPipeline::sRenderDeferred && is_post_deferred_render) - { - S32 p = 0; - switch (pass) - { - case 9: p = 1; break; - case 10: p = 5; break; - case 11: p = 9; break; - case 12: p = 13; break; - } - - { - LLGLEnable blend(GL_BLEND); - renderDeferredRiggedMaterial(avatarp, p); - } - return; - } - else if (pass == 9) - { - renderRiggedGlow(avatarp); - return; - } - } - - if (pass == 13) - { - renderRiggedGlow(avatarp); - - return; - } - if ((sShaderLevel >= SHADER_LEVEL_CLOTH)) { LLMatrix4 rot_mat; @@ -1731,748 +901,15 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) } } -void LLDrawPoolAvatar::getRiggedGeometry( - LLFace* face, - LLPointer<LLVertexBuffer>& buffer, - U32 data_mask, - const LLMeshSkinInfo* skin, - LLVolume* volume, - const LLVolumeFace& vol_face) -{ - face->setGeomIndex(0); - face->setIndicesIndex(0); - - if (face->getTextureIndex() != FACE_DO_NOT_BATCH_TEXTURES) - { - face->setDrawInfo(NULL); - } - - //rigged faces do not batch textures - face->setTextureIndex(FACE_DO_NOT_BATCH_TEXTURES); - - if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable()) - { - // make a new buffer - if (sShaderLevel > 0) - { - buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB); - } - else - { - buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB); - } - - if (!buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true)) - { - LL_WARNS("LLDrawPoolAvatar") << "Failed to allocate Vertex Buffer to " - << vol_face.mNumVertices << " vertices and " - << vol_face.mNumIndices << " indices" << LL_ENDL; - // allocate dummy triangle - buffer->allocateBuffer(1, 3, true); - memset((U8*)buffer->getMappedData(), 0, buffer->getSize()); - memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize()); - } - } - else - { - //resize existing buffer - if(!buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices)) - { - LL_WARNS("LLDrawPoolAvatar") << "Failed to resize Vertex Buffer to " - << vol_face.mNumVertices << " vertices and " - << vol_face.mNumIndices << " indices" << LL_ENDL; - // allocate dummy triangle - buffer->resizeBuffer(1, 3); - memset((U8*)buffer->getMappedData(), 0, buffer->getSize()); - memset((U8*)buffer->getMappedIndices(), 0, buffer->getIndicesSize()); - } - } - - face->setSize(buffer->getNumVerts(), buffer->getNumIndices()); - face->setVertexBuffer(buffer); - - U16 offset = 0; - - LLMatrix4 mat_vert = skin->mBindShapeMatrix; - glh::matrix4f m((F32*) mat_vert.mMatrix); - m = m.inverse().transpose(); - - F32 mat3[] = - { m.m[0], m.m[1], m.m[2], - m.m[4], m.m[5], m.m[6], - m.m[8], m.m[9], m.m[10] }; - - LLMatrix3 mat_normal(mat3); - - //let getGeometryVolume know if alpha should override shiny - U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture()); - - if (type == LLDrawPool::POOL_ALPHA) - { - face->setPoolType(LLDrawPool::POOL_ALPHA); - } - else - { - face->setPoolType(mType); // either POOL_AVATAR or POOL_CONTROL_AV - } - - //LL_INFOS() << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << LL_ENDL; - - // Let getGeometryVolume know if a texture matrix is in play - if (face->mTextureMatrix) - { - face->setState(LLFace::TEXTURE_ANIM); - } - else - { - face->clearState(LLFace::TEXTURE_ANIM); - } - face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true); - - buffer->flush(); -} - -void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( - LLVOAvatar* avatar, - LLFace* face, - const LLMeshSkinInfo* skin, - LLVolume* volume, - LLVolumeFace& vol_face) -{ - LLVector4a* weights = vol_face.mWeights; - if (!weights) - { - return; - } - - LLPointer<LLVertexBuffer> buffer = face->getVertexBuffer(); - LLDrawable* drawable = face->getDrawable(); - - if (drawable->getVOVolume() && drawable->getVOVolume()->isNoLOD()) - { - return; - } - - const U32 max_joints = LLSkinningUtil::getMaxJointCount(); - -#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS - #define CONDITION_WEIGHT(f) ((U8)llclamp((S32)f, (S32)0, (S32)max_joints-1)) - LLVector4a* just_weights = vol_face.mJustWeights; - // we need to calculate the separated indices and store just the matrix weights for this vol... - if (!vol_face.mJointIndices) - { - // not very consty after all... - vol_face.allocateJointIndices(vol_face.mNumVertices); - just_weights = vol_face.mJustWeights; - - U8* joint_indices_cursor = vol_face.mJointIndices; - for (int i = 0; i < vol_face.mNumVertices; i++) - { - F32* w = weights[i].getF32ptr(); - F32* w_ = just_weights[i].getF32ptr(); - - F32 w0 = floorf(w[0]); - F32 w1 = floorf(w[1]); - F32 w2 = floorf(w[2]); - F32 w3 = floorf(w[3]); - - joint_indices_cursor[0] = CONDITION_WEIGHT(w0); - joint_indices_cursor[1] = CONDITION_WEIGHT(w1); - joint_indices_cursor[2] = CONDITION_WEIGHT(w2); - joint_indices_cursor[3] = CONDITION_WEIGHT(w3); - - // remove joint portion of combined weight - w_[0] = w[0] - w0; - w_[1] = w[1] - w1; - w_[2] = w[2] - w2; - w_[3] = w[3] - w3; - - joint_indices_cursor += 4; - } - } -#endif - - // FIXME ugly const cast - LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin)); - - U32 data_mask = face->getRiggedVertexBufferDataMask(); - - if (!vol_face.mWeightsScrubbed) - { - LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin); - vol_face.mWeightsScrubbed = TRUE; - } - - if (buffer.isNull() || - buffer->getTypeMask() != data_mask || - buffer->getNumVerts() != vol_face.mNumVertices || - buffer->getNumIndices() != vol_face.mNumIndices || - (drawable && drawable->isState(LLDrawable::REBUILD_ALL))) - { - if (drawable && drawable->isState(LLDrawable::REBUILD_ALL)) - { - //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues - for (S32 i = 0; i < drawable->getNumFaces(); ++i) - { - LLFace* facep = drawable->getFace(i); - U32 face_data_mask = facep->getRiggedVertexBufferDataMask(); - if (face_data_mask) - { - LLPointer<LLVertexBuffer> cur_buffer = facep->getVertexBuffer(); - const LLVolumeFace& cur_vol_face = volume->getVolumeFace(i); - getRiggedGeometry(facep, cur_buffer, face_data_mask, skin, volume, cur_vol_face); - } - } - drawable->clearState(LLDrawable::REBUILD_ALL); - - buffer = face->getVertexBuffer(); - } - else - { - //just rebuild this face - getRiggedGeometry(face, buffer, data_mask, skin, volume, vol_face); - } - } - - if (buffer.isNull() || - buffer->getNumVerts() != vol_face.mNumVertices || - buffer->getNumIndices() != vol_face.mNumIndices) - { - // Allocation failed - return; - } - - if (!buffer.isNull() && - sShaderLevel <= 0 && - face->mLastSkinTime < avatar->getLastSkinTime()) - { - //perform software vertex skinning for this face - LLStrider<LLVector3> position; - LLStrider<LLVector3> normal; - - bool has_normal = buffer->hasDataType(LLVertexBuffer::TYPE_NORMAL); - buffer->getVertexStrider(position); - - if (has_normal) - { - buffer->getNormalStrider(normal); - } - - LLVector4a* pos = (LLVector4a*) position.get(); - - 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); - LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin); - - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); - -#if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS - U8* joint_indices_cursor = vol_face.mJointIndices; - // fast path with joint indices separate from weights - if (joint_indices_cursor) - { - LLMatrix4a src[4]; - for (U32 j = 0; j < buffer->getNumVerts(); ++j) - { - LLMatrix4a final_mat; - //LLMatrix4a final_mat_correct; - - F32* jw = just_weights[j].getF32ptr(); - - LLSkinningUtil::getPerVertexSkinMatrixWithIndices(jw, joint_indices_cursor, mat, final_mat, src); - - joint_indices_cursor += 4; - - LLVector4a& v = vol_face.mPositions[j]; - - LLVector4a t; - LLVector4a dst; - bind_shape_matrix.affineTransform(v, t); - final_mat.affineTransform(t, dst); - pos[j] = dst; - - if (norm) - { - LLVector4a& n = vol_face.mNormals[j]; - bind_shape_matrix.rotate(n, t); - final_mat.rotate(t, dst); - dst.normalize3fast(); - norm[j] = dst; - } - } - } - // slow path with joint indices calculated from weights - else -#endif - { - for (U32 j = 0; j < buffer->getNumVerts(); ++j) - { - LLMatrix4a final_mat; - LLSkinningUtil::getPerVertexSkinMatrix(weights[j].getF32ptr(), mat, false, final_mat, max_joints); - - LLVector4a& v = vol_face.mPositions[j]; - LLVector4a t; - LLVector4a dst; - bind_shape_matrix.affineTransform(v, t); - final_mat.affineTransform(t, dst); - pos[j] = dst; - - if (norm) - { - LLVector4a& n = vol_face.mNormals[j]; - bind_shape_matrix.rotate(n, t); - final_mat.rotate(t, dst); - //dst.normalize3fast(); - norm[j] = dst; - } - } - } - } -} - -void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) -{ - if (!avatar->shouldRenderRigged()) - { - return; - } - - stop_glerror(); - - for (U32 i = 0; i < mRiggedFace[type].size(); ++i) - { - LLFace* face = mRiggedFace[type][i]; - - S32 offset = face->getIndicesStart(); - U32 count = face->getIndicesCount(); - - U16 start = face->getGeomStart(); - U16 end = start + face->getGeomCount()-1; - - LLDrawable* drawable = face->getDrawable(); - if (!drawable) - { - continue; - } - - LLVOVolume* vobj = drawable->getVOVolume(); - - if (!vobj) - { - continue; - } - - LLVolume* volume = vobj->getVolume(); - S32 te = face->getTEOffset(); - - if (!volume || volume->getNumVolumeFaces() <= te || !volume->isMeshAssetLoaded()) - { - continue; - } - - const LLMeshSkinInfo* skin = vobj->getSkinInfo(); - if (!skin) - { - continue; - } - - //stop_glerror(); - - //const LLVolumeFace& vol_face = volume->getVolumeFace(te); - //updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face); - - //stop_glerror(); - - U32 data_mask = LLFace::getRiggedDataMask(type); - - LLVertexBuffer* buff = face->getVertexBuffer(); - - const LLTextureEntry* tex_entry = face->getTextureEntry(); - LLMaterial* mat = tex_entry ? tex_entry->getMaterialParams().get() : nullptr; - - if (LLDrawPoolAvatar::sShadowPass >= 0) - { - bool is_alpha_blend = false; - bool is_alpha_mask = false; - - LLViewerTexture* tex = face->getTexture(LLRender::DIFFUSE_MAP); - if (tex) - { - if (tex->getIsAlphaMask()) - { - is_alpha_mask = true; - } - } - - if (tex) - { - LLGLenum image_format = tex->getPrimaryFormat(); - if (!is_alpha_mask && (image_format == GL_RGBA || image_format == GL_ALPHA)) - { - is_alpha_blend = true; - } - } - - if (tex_entry) - { - if (tex_entry->getAlpha() <= 0.99f) - { - is_alpha_blend = true; - } - } - - if (mat) - { - switch (LLMaterial::eDiffuseAlphaMode(mat->getDiffuseAlphaMode())) - { - case LLMaterial::DIFFUSE_ALPHA_MODE_MASK: - { - is_alpha_mask = true; - is_alpha_blend = false; - } - break; - - case LLMaterial::DIFFUSE_ALPHA_MODE_BLEND: - { - is_alpha_blend = true; - is_alpha_mask = false; - } - break; - - case LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE: - case LLMaterial::DIFFUSE_ALPHA_MODE_DEFAULT: - case LLMaterial::DIFFUSE_ALPHA_MODE_NONE: - default: - is_alpha_blend = false; - is_alpha_mask = false; - break; - } - } - - // if this is alpha mask content and we're doing opaques or a non-alpha-mask shadow pass... - if (is_alpha_mask && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_MASK)) - { - return; - } - - // if this is alpha blend content and we're doing opaques or a non-alpha-blend shadow pass... - if (is_alpha_blend && (LLDrawPoolAvatar::sSkipTransparent || LLDrawPoolAvatar::sShadowPass != SHADOW_PASS_ATTACHMENT_ALPHA_BLEND)) - { - return; - } - - // if this is opaque content and we're skipping opaques... - if (!is_alpha_mask && !is_alpha_blend && LLDrawPoolAvatar::sSkipOpaque) - { - return; - } - } - - if (buff) - { - 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); - - stop_glerror(); - - F32 mp[LL_MAX_JOINTS_PER_MESH_OBJECT*12]; - - for (U32 i = 0; i < count; ++i) - { - F32* m = (F32*) mat[i].mMatrix[0].getF32ptr(); - - U32 idx = i*12; - - mp[idx+0] = m[0]; - mp[idx+1] = m[1]; - mp[idx+2] = m[2]; - mp[idx+3] = m[12]; - - mp[idx+4] = m[4]; - mp[idx+5] = m[5]; - mp[idx+6] = m[6]; - mp[idx+7] = m[13]; - - mp[idx+8] = m[8]; - mp[idx+9] = m[9]; - mp[idx+10] = m[10]; - mp[idx+11] = m[14]; - } - - LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, - count, - FALSE, - (GLfloat*) mp); - - stop_glerror(); - } - else - { - data_mask &= ~LLVertexBuffer::MAP_WEIGHT4; - } - - /*if (glow) - { - gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow()); - }*/ - - if (mat) - { - //order is important here LLRender::DIFFUSE_MAP should be last, becouse it change - //(gGL).mCurrTextureUnitIndex - LLViewerTexture* specular = NULL; - if (LLPipeline::sImpostorRender) - { - specular = LLViewerTextureManager::findFetchedTexture(gBlackSquareID, TEX_LIST_STANDARD); - llassert(NULL != specular); - } - else - { - specular = face->getTexture(LLRender::SPECULAR_MAP); - } - if (specular) - { - gGL.getTexUnit(specular_channel)->bind(specular); - } - - gGL.getTexUnit(normal_channel)->bind(face->getTexture(LLRender::NORMAL_MAP)); - gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture(LLRender::DIFFUSE_MAP), false, true); - - - LLColor4 col = mat->getSpecularLightColor(); - F32 spec = mat->getSpecularLightExponent()/255.f; - - F32 env = mat->getEnvironmentIntensity()/255.f; - - if (mat->getSpecularID().isNull()) - { - env = tex_entry->getShiny()*0.25f; - col.set(env,env,env,0); - spec = env; - } - - BOOL fullbright = tex_entry->getFullbright(); - - sVertexProgram->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, fullbright ? 1.f : 0.f); - sVertexProgram->uniform4f(LLShaderMgr::SPECULAR_COLOR, col.mV[0], col.mV[1], col.mV[2], spec); - sVertexProgram->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env); - - if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK) - { - F32 cutoff = mat->getAlphaMaskCutoff()/255.f; - sVertexProgram->setMinimumAlpha(cutoff); - } - else - { - sVertexProgram->setMinimumAlpha(0.f); - } - - for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i) - { - LLViewerTexture* tex = face->getTexture(i); - if (tex) - { - tex->addTextureStats(avatar->getPixelArea()); - } - } - } - else - { - gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture()); - sVertexProgram->setMinimumAlpha(0.f); - if (normal_channel > -1) - { - LLDrawPoolBump::bindBumpMap(face, normal_channel); - } - } - - if (face->mTextureMatrix && vobj->mTexAnimMode) - { - U32 tex_index = gGL.getCurrentTexUnitIndex(); - - if (tex_index <= 1) - { - gGL.matrixMode(LLRender::eMatrixMode(LLRender::MM_TEXTURE0 + tex_index)); - gGL.pushMatrix(); - gGL.loadMatrix((F32*) face->mTextureMatrix->mMatrix); - } - - buff->setBuffer(data_mask); - buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); - - if (tex_index <= 1) - { - gGL.matrixMode(LLRender::eMatrixMode(LLRender::MM_TEXTURE0 + tex_index)); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } - } - else - { - buff->setBuffer(data_mask); - buff->drawRange(LLRender::TRIANGLES, start, end, count, offset); - } - - gPipeline.addTrianglesDrawn(count, LLRender::TRIANGLES); - } - } -} - -void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar) -{ - renderRigged(avatar, RIGGED_DEFERRED_SIMPLE); -} - -void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar) -{ - renderRigged(avatar, RIGGED_DEFERRED_BUMP); -} - -void LLDrawPoolAvatar::renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass) -{ - renderRigged(avatar, pass); -} - static LLTrace::BlockTimerStatHandle FTM_RIGGED_VBO("Rigged VBO"); -void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) -{ - LL_RECORD_BLOCK_TIME(FTM_RIGGED_VBO); - - //update rigged vertex buffers - for (U32 type = 0; type < NUM_RIGGED_PASSES; ++type) - { - for (U32 i = 0; i < mRiggedFace[type].size(); ++i) - { - LLFace* face = mRiggedFace[type][i]; - LLDrawable* drawable = face->getDrawable(); - if (!drawable) - { - continue; - } - - LLVOVolume* vobj = drawable->getVOVolume(); - - if (!vobj || vobj->isNoLOD()) - { - continue; - } - - LLVolume* volume = vobj->getVolume(); - S32 te = face->getTEOffset(); - - if (!volume || volume->getNumVolumeFaces() <= te) - { - continue; - } - - const LLMeshSkinInfo* skin = vobj->getSkinInfo(); - if (!skin) - { - continue; - } - - stop_glerror(); - - LLVolumeFace& vol_face = volume->getVolumeFace(te); - updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face); - } - } -} - -void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar) -{ - renderRigged(avatar, RIGGED_SIMPLE); -} - -void LLDrawPoolAvatar::renderRiggedFullbright(LLVOAvatar* avatar) -{ - renderRigged(avatar, RIGGED_FULLBRIGHT); -} - - -void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar) -{ - renderRigged(avatar, RIGGED_SHINY); -} - -void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar) -{ - renderRigged(avatar, RIGGED_FULLBRIGHT_SHINY); -} - -void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar) -{ - if (!mRiggedFace[RIGGED_ALPHA].empty()) - { - LLGLEnable blend(GL_BLEND); - - gGL.setColorMask(true, true); - gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, - LLRender::BF_ONE_MINUS_SOURCE_ALPHA, - LLRender::BF_ZERO, - LLRender::BF_ONE_MINUS_SOURCE_ALPHA); - - renderRigged(avatar, RIGGED_ALPHA); - gGL.setColorMask(true, false); - } -} - -void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar) -{ - if (!mRiggedFace[RIGGED_FULLBRIGHT_ALPHA].empty()) - { - LLGLEnable blend(GL_BLEND); - - gGL.setColorMask(true, true); - gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, - LLRender::BF_ONE_MINUS_SOURCE_ALPHA, - LLRender::BF_ZERO, - LLRender::BF_ONE_MINUS_SOURCE_ALPHA); - - renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA); - gGL.setColorMask(true, false); - } -} - -void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar) -{ - if (!mRiggedFace[RIGGED_GLOW].empty()) - { - LLGLEnable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - gGL.flush(); - - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); - gGL.setSceneBlendType(LLRender::BT_ADD); - - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - gGL.setColorMask(false, true); - - renderRigged(avatar, RIGGED_GLOW, true); - - gGL.setColorMask(true, false); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - } -} - - - //----------------------------------------------------------------------------- // getDebugTexture() //----------------------------------------------------------------------------- LLViewerTexture *LLDrawPoolAvatar::getDebugTexture() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR + if (mReferences.empty()) { return NULL; @@ -2494,68 +931,12 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const return LLColor3(0.f, 1.f, 0.f); } -void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type) -{ - llassert (facep->isState(LLFace::RIGGED)); - llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV); - if (facep->getPool() && facep->getPool() != this) - { - LL_ERRS() << "adding rigged face that's already in another pool" << LL_ENDL; - } - if (type >= NUM_RIGGED_PASSES) - { - LL_ERRS() << "Invalid rigged face type." << LL_ENDL; - } - if (facep->getRiggedIndex(type) != -1) - { - LL_ERRS() << "Tried to add a rigged face that's referenced elsewhere." << LL_ENDL; - } - - facep->setRiggedIndex(type, mRiggedFace[type].size()); - facep->setPool(this); - mRiggedFace[type].push_back(facep); -} - -void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep) -{ - llassert (facep->isState(LLFace::RIGGED)); - llassert(getType() == LLDrawPool::POOL_AVATAR || getType() == LLDrawPool::POOL_CONTROL_AV); - if (facep->getPool() != this) - { - LL_ERRS() << "Tried to remove a rigged face from the wrong pool" << LL_ENDL; - } - facep->setPool(NULL); - - for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i) - { - S32 index = facep->getRiggedIndex(i); - - if (index > -1) - { - if (mRiggedFace[i].size() > index && mRiggedFace[i][index] == facep) - { - facep->setRiggedIndex(i,-1); - mRiggedFace[i].erase(mRiggedFace[i].begin()+index); - for (U32 j = index; j < mRiggedFace[i].size(); ++j) - { //bump indexes down for faces referenced after erased face - mRiggedFace[i][j]->setRiggedIndex(i, j); - } - } - else - { - LL_ERRS() << "Face reference data corrupt for rigged type " << i - << ((mRiggedFace[i].size() <= index) ? "; wrong index (out of bounds)" : (mRiggedFace[i][index] != facep) ? "; wrong face pointer" : "") - << LL_ENDL; - } - } - } -} LLVertexBufferAvatar::LLVertexBufferAvatar() : LLVertexBuffer(sDataMask, GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets { - + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR } diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 92a8538958..21add39b21 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -28,14 +28,18 @@ #define LL_LLDRAWPOOLAVATAR_H #include "lldrawpool.h" +#include "llmodel.h" + +#include <unordered_map> class LLVOAvatar; +class LLVOVolume; class LLGLSLShader; class LLFace; -class LLMeshSkinInfo; class LLVolume; class LLVolumeFace; +extern U32 gFrameCount; class LLDrawPoolAvatar : public LLFacePool { @@ -58,119 +62,11 @@ public: ~LLDrawPoolAvatar(); /*virtual*/ BOOL isDead(); - typedef enum - { - RIGGED_MATERIAL=0, - RIGGED_MATERIAL_ALPHA, - RIGGED_MATERIAL_ALPHA_MASK, - RIGGED_MATERIAL_ALPHA_EMISSIVE, - RIGGED_SPECMAP, - RIGGED_SPECMAP_BLEND, - RIGGED_SPECMAP_MASK, - RIGGED_SPECMAP_EMISSIVE, - RIGGED_NORMMAP, - RIGGED_NORMMAP_BLEND, - RIGGED_NORMMAP_MASK, - RIGGED_NORMMAP_EMISSIVE, - RIGGED_NORMSPEC, - RIGGED_NORMSPEC_BLEND, - RIGGED_NORMSPEC_MASK, - RIGGED_NORMSPEC_EMISSIVE, - RIGGED_SIMPLE, - RIGGED_FULLBRIGHT, - RIGGED_SHINY, - RIGGED_FULLBRIGHT_SHINY, - RIGGED_GLOW, - RIGGED_ALPHA, - RIGGED_FULLBRIGHT_ALPHA, - RIGGED_DEFERRED_BUMP, - RIGGED_DEFERRED_SIMPLE, - NUM_RIGGED_PASSES, - RIGGED_UNKNOWN, - } eRiggedPass; - - typedef enum - { - RIGGED_MATERIAL_MASK = - LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4, - RIGGED_MATERIAL_ALPHA_VMASK = RIGGED_MATERIAL_MASK, - RIGGED_MATERIAL_ALPHA_MASK_MASK = RIGGED_MATERIAL_MASK, - RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK = RIGGED_MATERIAL_MASK, - RIGGED_SPECMAP_VMASK = - LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_TEXCOORD2 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4, - RIGGED_SPECMAP_BLEND_MASK = RIGGED_SPECMAP_VMASK, - RIGGED_SPECMAP_MASK_MASK = RIGGED_SPECMAP_VMASK, - RIGGED_SPECMAP_EMISSIVE_MASK = RIGGED_SPECMAP_VMASK, - RIGGED_NORMMAP_VMASK = - LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TANGENT | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_TEXCOORD1 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4, - RIGGED_NORMMAP_BLEND_MASK = RIGGED_NORMMAP_VMASK, - RIGGED_NORMMAP_MASK_MASK = RIGGED_NORMMAP_VMASK, - RIGGED_NORMMAP_EMISSIVE_MASK = RIGGED_NORMMAP_VMASK, - RIGGED_NORMSPEC_VMASK = - LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TANGENT | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_TEXCOORD1 | - LLVertexBuffer::MAP_TEXCOORD2 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4, - RIGGED_NORMSPEC_BLEND_MASK = RIGGED_NORMSPEC_VMASK, - RIGGED_NORMSPEC_MASK_MASK = RIGGED_NORMSPEC_VMASK, - RIGGED_NORMSPEC_EMISSIVE_MASK = RIGGED_NORMSPEC_VMASK, - RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4, - RIGGED_FULLBRIGHT_MASK = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4, - RIGGED_SHINY_MASK = RIGGED_SIMPLE_MASK, - RIGGED_FULLBRIGHT_SHINY_MASK = RIGGED_SIMPLE_MASK, - RIGGED_GLOW_MASK = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_EMISSIVE | - LLVertexBuffer::MAP_WEIGHT4, - RIGGED_ALPHA_MASK = RIGGED_SIMPLE_MASK, - RIGGED_FULLBRIGHT_ALPHA_MASK = RIGGED_FULLBRIGHT_MASK, - RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_TANGENT | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4, - RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_NORMAL | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_WEIGHT4, - } eRiggedDataMask; - typedef enum { SHADOW_PASS_AVATAR_OPAQUE, SHADOW_PASS_AVATAR_ALPHA_BLEND, SHADOW_PASS_AVATAR_ALPHA_MASK, - SHADOW_PASS_ATTACHMENT_ALPHA_BLEND, - SHADOW_PASS_ATTACHMENT_ALPHA_MASK, - SHADOW_PASS_ATTACHMENT_OPAQUE, NUM_SHADOW_PASSES } eShadowPass; @@ -211,78 +107,19 @@ typedef enum void endImpostor(); void endSkinned(); - void beginDeferredImpostor(); - void beginDeferredRigid(); - void beginDeferredSkinned(); - - void endDeferredImpostor(); - void endDeferredRigid(); - void endDeferredSkinned(); - - void beginPostDeferredAlpha(); - void endPostDeferredAlpha(); - - void beginRiggedSimple(); - void beginRiggedFullbright(); - void beginRiggedFullbrightShiny(); - void beginRiggedShinySimple(); - void beginRiggedAlpha(); - void beginRiggedFullbrightAlpha(); - void beginRiggedGlow(); - void beginDeferredRiggedAlpha(); - void beginDeferredRiggedMaterial(S32 pass); - void beginDeferredRiggedMaterialAlpha(S32 pass); + void beginDeferredRigid(); + void beginDeferredImpostor(); + void beginDeferredSkinned(); - void endRiggedSimple(); - void endRiggedFullbright(); - void endRiggedFullbrightShiny(); - void endRiggedShinySimple(); - void endRiggedAlpha(); - void endRiggedFullbrightAlpha(); - void endRiggedGlow(); - void endDeferredRiggedAlpha(); - void endDeferredRiggedMaterial(S32 pass); - void endDeferredRiggedMaterialAlpha(S32 pass); - - void beginDeferredRiggedSimple(); - void beginDeferredRiggedBump(); - - void endDeferredRiggedSimple(); - void endDeferredRiggedBump(); - - void getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face); - void updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, - LLFace* facep, - const LLMeshSkinInfo* skin, - LLVolume* volume, - LLVolumeFace& vol_face); - void updateRiggedVertexBuffers(LLVOAvatar* avatar); - - void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false); - void renderRiggedSimple(LLVOAvatar* avatar); - void renderRiggedAlpha(LLVOAvatar* avatar); - void renderRiggedFullbrightAlpha(LLVOAvatar* avatar); - void renderRiggedFullbright(LLVOAvatar* avatar); - void renderRiggedShinySimple(LLVOAvatar* avatar); - void renderRiggedFullbrightShiny(LLVOAvatar* avatar); - void renderRiggedGlow(LLVOAvatar* avatar); - void renderDeferredRiggedSimple(LLVOAvatar* avatar); - void renderDeferredRiggedBump(LLVOAvatar* avatar); - void renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass); - - - - void addRiggedFace(LLFace* facep, U32 type); - void removeRiggedFace(LLFace* facep); - - std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES]; + void endDeferredRigid(); + void endDeferredImpostor(); + void endDeferredSkinned(); /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null. - static BOOL sSkipOpaque; static BOOL sSkipTransparent; static S32 sShadowPass; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 14069fa6c2..2892fc6f9f 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -47,12 +47,16 @@ #include "pipeline.h" #include "llspatialpartition.h" #include "llviewershadermgr.h" +#include "llmodel.h" //#include "llimagebmp.h" //#include "../tools/imdebug/imdebug.h" // static LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT]; +LL::WorkQueue::weak_t LLBumpImageList::sMainQueue; +LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue; +LLRenderTarget LLBumpImageList::sRenderTarget; // static U32 LLStandardBumpmap::sStandardBumpmapCount = 0; @@ -73,6 +77,8 @@ static S32 cube_channel = -1; static S32 diffuse_channel = -1; static S32 bump_channel = -1; +#define LL_BUMPLIST_MULTITHREADED 0 // TODO -- figure out why this doesn't work + // static void LLStandardBumpmap::init() { @@ -199,32 +205,7 @@ void LLDrawPoolBump::prerender() // static S32 LLDrawPoolBump::numBumpPasses() { - if (gSavedSettings.getBOOL("RenderObjectBump")) - { - if (mShaderLevel > 1) - { - if (LLPipeline::sImpostorRender) - { - return 2; - } - else - { - return 3; - } - } - else if (LLPipeline::sImpostorRender) - { - return 1; - } - else - { - return 2; - } - } - else - { - return 0; - } + return 1; } S32 LLDrawPoolBump::getNumPasses() @@ -232,140 +213,79 @@ S32 LLDrawPoolBump::getNumPasses() return numBumpPasses(); } -void LLDrawPoolBump::beginRenderPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - switch( pass ) - { - case 0: - beginShiny(); - break; - case 1: - if (mShaderLevel > 1) - { - beginFullbrightShiny(); - } - else - { - beginBump(); - } - break; - case 2: - beginBump(); - break; - default: - llassert(0); - break; - } -} - void LLDrawPoolBump::render(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - - if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE)) - { - return; - } - - switch( pass ) - { - case 0: - renderShiny(); - break; - case 1: - if (mShaderLevel > 1) - { - renderFullbrightShiny(); - } - else - { - renderBump(); - } - break; - case 2: - renderBump(); - break; - default: - llassert(0); - break; - } -} + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); -void LLDrawPoolBump::endRenderPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - switch( pass ) - { - case 0: - endShiny(); - break; - case 1: - if (mShaderLevel > 1) - { - endFullbrightShiny(); - } - else - { - endBump(); - } - break; - case 2: - endBump(); - break; - default: - llassert(0); - break; - } + if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE)) + { + return; + } + + for (int i = 0; i < 2; ++i) + { + mRigged = i == 1; + + // first pass -- shiny + beginShiny(); + renderShiny(); + endShiny(); - //to cleanup texture channels - LLRenderPass::endRenderPass(pass); + //second pass -- fullbright shiny + if (mShaderLevel > 1) + { + beginFullbrightShiny(); + renderFullbrightShiny(); + endFullbrightShiny(); + } + + //third pass -- bump + beginBump(); + renderBump(LLRenderPass::PASS_BUMP); + endBump(); + } } + //static -void LLDrawPoolBump::beginShiny(bool invisible) +void LLDrawPoolBump::beginShiny() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| - (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) - { - return; - } - + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + mShiny = TRUE; sVertexMask = VERTEX_MASK_SHINY; // Second pass: environment map - if (!invisible && mShaderLevel > 1) + if (mShaderLevel > 1) { sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; } - if (getShaderLevel() > 0) + if (LLPipeline::sUnderWaterRender) { - if (LLPipeline::sUnderWaterRender) - { - shader = &gObjectShinyWaterProgram; - } - else - { - shader = &gObjectShinyProgram; - } - shader->bind(); - if (LLPipeline::sRenderingHUDs) - { - shader->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - shader->uniform1i(LLShaderMgr::NO_ATMO, 0); - } + shader = &gObjectShinyWaterProgram; } else { - shader = NULL; + shader = &gObjectShinyProgram; } - bindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible); + if (mRigged) + { + llassert(shader->mRiggedVariant); + shader = shader->mRiggedVariant; + } + + shader->bind(); + if (LLPipeline::sRenderingHUDs) + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } + + bindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel); if (mShaderLevel > 1) { //indexed texture rendering, channel 0 is always diffuse @@ -374,12 +294,12 @@ void LLDrawPoolBump::beginShiny(bool invisible) } //static -void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible) +void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) { LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { - if (!invisible && shader ) + if (shader ) { LLMatrix4 mat; mat.initRows(LLVector4(gGLModelView+0), @@ -391,19 +311,16 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); if (shader_level > 1) { - cube_map->setMatrix(1); // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for // the cube map in the one pass shiny shaders cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); cube_map->enableTexture(cube_channel); - cube_map->enableTextureCoords(1); diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); } else { cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); diffuse_channel = -1; - cube_map->setMatrix(0); cube_map->enable(cube_channel); } gGL.getTexUnit(cube_channel)->bind(cube_map); @@ -415,49 +332,50 @@ void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& di diffuse_channel = -1; gGL.getTexUnit(0)->disable(); cube_map->enable(0); - cube_map->setMatrix(0); gGL.getTexUnit(0)->bind(cube_map); - - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_VERT_ALPHA); } } } -void LLDrawPoolBump::renderShiny(bool invisible) +void LLDrawPoolBump::renderShiny() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| - (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) - { - return; - } - + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + if( gSky.mVOSkyp->getCubeMap() ) { LLGLEnable blend_enable(GL_BLEND); - if (!invisible && mShaderLevel > 1) + if (mShaderLevel > 1) { - LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + if (mRigged) + { + LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_SHINY_RIGGED, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + } + else + { + LLRenderPass::pushBatches(LLRenderPass::PASS_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + } } - else if (!invisible) + else { - renderGroups(LLRenderPass::PASS_SHINY, sVertexMask); + if (mRigged) + { + gPipeline.renderRiggedGroups(this, LLRenderPass::PASS_SHINY_RIGGED, sVertexMask, TRUE); + } + else + { + gPipeline.renderGroups(this, LLRenderPass::PASS_SHINY, sVertexMask, TRUE); + } } - //else // invisible (deprecated) - //{ - //renderGroups(LLRenderPass::PASS_INVISI_SHINY, sVertexMask); - //} } } //static -void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible) +void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel) { LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { - if (!invisible && shader_level > 1) + if (shader_level > 1) { shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); @@ -472,29 +390,14 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& // Moved below shader->disableTexture call to avoid false alarms from auto-re-enable of textures on stage 0 // MAINT-755 cube_map->disable(); - cube_map->restoreMatrix(); - } - - if (!LLGLSLShader::sNoFixedFunction) - { - gGL.getTexUnit(diffuse_channel)->disable(); - gGL.getTexUnit(cube_channel)->disable(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } } -void LLDrawPoolBump::endShiny(bool invisible) +void LLDrawPoolBump::endShiny() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| - (invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY))) - { - return; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel, invisible); + unbindCubeMap(shader, mShaderLevel, diffuse_channel, cube_channel); if (shader) { shader->unbind(); @@ -507,12 +410,8 @@ void LLDrawPoolBump::endShiny(bool invisible) void LLDrawPoolBump::beginFullbrightShiny() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) - { - return; - } - + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); + sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0; // Second pass: environment map @@ -533,6 +432,12 @@ void LLDrawPoolBump::beginFullbrightShiny() } } + if (mRigged) + { + llassert(shader->mRiggedVariant); + shader = shader->mRiggedVariant; + } + LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { @@ -553,15 +458,13 @@ void LLDrawPoolBump::beginFullbrightShiny() LLVector3 vec = LLVector3(gShinyOrigin) * mat; LLVector4 vec4(vec, gShinyOrigin.mV[3]); - shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); + shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV); - cube_map->setMatrix(1); // Make sure that texture coord generation happens for tex unit 1, as that's the one we use for // the cube map in the one pass shiny shaders gGL.getTexUnit(1)->disable(); cube_channel = shader->enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); cube_map->enableTexture(cube_channel); - cube_map->enableTextureCoords(1); diffuse_channel = shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); gGL.getTexUnit(cube_channel)->bind(cube_map); @@ -578,11 +481,7 @@ void LLDrawPoolBump::beginFullbrightShiny() void LLDrawPoolBump::renderFullbrightShiny() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) - { - return; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); if( gSky.mVOSkyp->getCubeMap() ) { @@ -590,43 +489,40 @@ void LLDrawPoolBump::renderFullbrightShiny() if (mShaderLevel > 1) { - LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + if (mRigged) + { + LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + } + else + { + LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + } } else { - LLRenderPass::renderTexture(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask); + if (mRigged) + { + LLRenderPass::pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, sVertexMask); + } + else + { + LLRenderPass::pushBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY, sVertexMask); + } } } } void LLDrawPoolBump::endFullbrightShiny() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); - if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) - { - return; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SHINY); LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL; if( cube_map ) { cube_map->disable(); - cube_map->restoreMatrix(); - - /*if (diffuse_channel != 0) - { - shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);*/ - shader->unbind(); - //gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } - //gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - //gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - diffuse_channel = -1; cube_channel = 0; mShiny = FALSE; @@ -677,6 +573,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel) //static BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsize, S32 channel) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //Note: texture atlas does not support bump texture now. LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ; if(!tex) @@ -693,7 +590,7 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi break; case BE_BRIGHTNESS: case BE_DARKNESS: - bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code ); + bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code ); break; default: @@ -709,12 +606,13 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi { if (channel == -2) { - gGL.getTexUnit(1)->bind(bump); - gGL.getTexUnit(0)->bind(bump); + gGL.getTexUnit(1)->bindFast(bump); + gGL.getTexUnit(0)->bindFast(bump); } else { - gGL.getTexUnit(channel)->bind(bump); + // NOTE: do not use bindFast here (see SL-16222) + gGL.getTexUnit(channel)->bind(bump); } return TRUE; @@ -724,53 +622,22 @@ BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsi } //static -void LLDrawPoolBump::beginBump(U32 pass) -{ - if (!gPipeline.hasRenderBatches(pass)) - { - return; - } - +void LLDrawPoolBump::beginBump() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); sVertexMask = VERTEX_MASK_BUMP; - LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); // Optional second pass: emboss bump map stop_glerror(); - if (LLGLSLShader::sNoFixedFunction) - { - gObjectBumpProgram.bind(); - } - else - { - // TEXTURE UNIT 0 - // Output.rgb = texture at texture coord 0 - gGL.getTexUnit(0)->activate(); - - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); + shader = &gObjectBumpProgram; - // TEXTURE UNIT 1 - gGL.getTexUnit(1)->activate(); - - gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE); + if (mRigged) + { + llassert(shader->mRiggedVariant); + shader = shader->mRiggedVariant; + } - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD_SIGNED, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_ONE_MINUS_TEX_ALPHA); - gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); - - // src = tex0 + (1 - tex1) - 0.5 - // = (bump0/2 + 0.5) + (1 - (bump1/2 + 0.5)) - 0.5 - // = (1 + bump0 - bump1) / 2 - - - // Blend: src * dst + dst * src - // = 2 * src * dst - // = 2 * ((1 + bump0 - bump1) / 2) * dst [0 - 2 * dst] - // = (1 + bump0 - bump1) * dst.rgb - // = dst.rgb + dst.rgb * (bump0 - bump1) - - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(1)->unbind(LLTexUnit::TT_TEXTURE); - } + shader->bind(); gGL.setSceneBlendType(LLRender::BT_MULT_X2); stop_glerror(); @@ -779,12 +646,7 @@ void LLDrawPoolBump::beginBump(U32 pass) //static void LLDrawPoolBump::renderBump(U32 pass) { - if (!gPipeline.hasRenderBatches(pass)) - { - return; - } - - LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); LLGLDisable fog(GL_FOG); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL); LLGLEnable blend(GL_BLEND); @@ -798,28 +660,9 @@ void LLDrawPoolBump::renderBump(U32 pass) //static void LLDrawPoolBump::endBump(U32 pass) { - if (!gPipeline.hasRenderBatches(pass)) - { - return; - } + gObjectBumpProgram.unbind(); - if (LLGLSLShader::sNoFixedFunction) - { - gObjectBumpProgram.unbind(); - } - else - { - // Disable texture blending on unit 1 - gGL.getTexUnit(1)->activate(); - gGL.getTexUnit(1)->disable(); - gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT); - - // Disable texture blending on unit 0 - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } - - gGL.setSceneBlendType(LLRender::BT_ALPHA); + gGL.setSceneBlendType(LLRender::BT_ALPHA); } S32 LLDrawPoolBump::getNumDeferredPasses() @@ -834,101 +677,81 @@ S32 LLDrawPoolBump::getNumDeferredPasses() } } -void LLDrawPoolBump::beginDeferredPass(S32 pass) -{ - if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP)) - { - return; - } - LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - mShiny = TRUE; - gDeferredBumpProgram.bind(); - diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - bump_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::BUMP_MAP); - gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE); -} - -void LLDrawPoolBump::endDeferredPass(S32 pass) -{ - if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP)) - { - return; - } - LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - mShiny = FALSE; - gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP); - gDeferredBumpProgram.unbind(); - gGL.getTexUnit(0)->activate(); -} - void LLDrawPoolBump::renderDeferred(S32 pass) { - if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP)) - { - return; - } - LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - U32 type = LLRenderPass::PASS_BUMP; - LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); - LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + mShiny = TRUE; + for (int i = 0; i < 2; ++i) + { + bool rigged = i == 1; + gDeferredBumpProgram.bind(rigged); + diffuse_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + bump_channel = LLGLSLShader::sCurBoundShaderPtr->enableTexture(LLViewerShaderMgr::BUMP_MAP); + gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(bump_channel)->unbind(LLTexUnit::TT_TEXTURE); - U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; - - for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) - { - LLDrawInfo& params = **i; + U32 type = rigged ? LLRenderPass::PASS_BUMP_RIGGED : LLRenderPass::PASS_BUMP; + LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); + LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); - gDeferredBumpProgram.setMinimumAlpha(params.mAlphaMaskCutoff); - LLDrawPoolBump::bindBumpMap(params, bump_channel); - pushBatch(params, mask, TRUE); - } -} + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR; -void LLDrawPoolBump::beginPostDeferredPass(S32 pass) -{ - switch (pass) - { - case 0: - beginFullbrightShiny(); - break; - case 1: - beginBump(LLRenderPass::PASS_POST_BUMP); - break; - } -} + LLVOAvatar* avatar = nullptr; + U64 skin = 0; -void LLDrawPoolBump::endPostDeferredPass(S32 pass) -{ - switch (pass) - { - case 0: - endFullbrightShiny(); - break; - case 1: - endBump(LLRenderPass::PASS_POST_BUMP); - break; - } + for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) + { + LLDrawInfo& params = **i; + + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(params.mAlphaMaskCutoff); + LLDrawPoolBump::bindBumpMap(params, bump_channel); + + if (rigged) + { + if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash) + { + uploadMatrixPalette(params); + avatar = params.mAvatar; + skin = params.mSkinInfo->mHash; + } + pushBatch(params, mask | LLVertexBuffer::MAP_WEIGHT4, TRUE, FALSE); + } + else + { + pushBatch(params, mask, TRUE, FALSE); + } + } - //to disable texture channels - LLRenderPass::endRenderPass(pass); + LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + LLGLSLShader::sCurBoundShaderPtr->disableTexture(LLViewerShaderMgr::BUMP_MAP); + LLGLSLShader::sCurBoundShaderPtr->unbind(); + gGL.getTexUnit(0)->activate(); + } + + mShiny = FALSE; } + void LLDrawPoolBump::renderPostDeferred(S32 pass) { - switch (pass) - { - case 0: - renderFullbrightShiny(); - break; - case 1: - renderBump(LLRenderPass::PASS_POST_BUMP); - break; - } + for (int i = 0; i < 2; ++i) + { // two passes -- static and rigged + mRigged = (i == 1); + + // render shiny + beginFullbrightShiny(); + renderFullbrightShiny(); + endFullbrightShiny(); + + //render bump + beginBump(); + renderBump(LLRenderPass::PASS_POST_BUMP); + endBump(); + } } + //////////////////////////////////////////////////////////////// // List of bump-maps created from other textures. @@ -943,6 +766,8 @@ void LLBumpImageList::init() LLStandardBumpmap::init(); LLStandardBumpmap::restoreGL(); + sMainQueue = LL::WorkQueue::getInstance("mainloop"); + sTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader. } void LLBumpImageList::clear() @@ -952,6 +777,8 @@ void LLBumpImageList::clear() mBrightnessEntries.clear(); mDarknessEntries.clear(); + sRenderTarget.release(); + LLStandardBumpmap::clear(); } @@ -1061,6 +888,7 @@ void LLBumpImageList::updateImages() // Note: the caller SHOULD NOT keep the pointer that this function returns. It may be updated as more data arrives. LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) ); LLViewerTexture* bump = NULL; @@ -1090,10 +918,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText } else { - LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1); - raw->clear(0x77, 0x77, 0xFF, 0xFF); - - (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE); + (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( TRUE ); bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image } @@ -1113,11 +938,10 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText } -static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_STANDARD_LOADED("Bump Standard Callback"); - // static void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLUUID* source_asset_id = (LLUUID*)userdata; LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS ); if( final ) @@ -1137,22 +961,17 @@ void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTextu } } -static LLTrace::BlockTimerStatHandle FTM_BUMP_GEN_NORMAL("Generate Normal Map"); -static LLTrace::BlockTimerStatHandle FTM_BUMP_CREATE_TEXTURE("Create GL Normal Map"); - void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { if (success && LLPipeline::sRenderDeferred) { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_STANDARD_LOADED); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4); { - LL_RECORD_BLOCK_TIME(FTM_BUMP_GEN_NORMAL); generateNormalMapFromAlpha(src, nrm_image); } src_vi->setExplicitFormat(GL_RGBA, GL_RGBA); { - LL_RECORD_BLOCK_TIME(FTM_BUMP_CREATE_TEXTURE); src_vi->createGLTexture(src_vi->getDiscardLevel(), nrm_image); } } @@ -1213,43 +1032,32 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr } } - -static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_LOADED("Bump Source Loaded"); -static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_ENTRIES_UPDATE("Entries Update"); -static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_MIN_MAX("Min/Max"); -static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_RGB2LUM("RGB to Luminance"); -static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_RESCALE("Rescale"); -static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_GEN_NORMAL("Generate Normal"); -static LLTrace::BlockTimerStatHandle FTM_BUMP_SOURCE_CREATE("Bump Source Create"); - // static void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) { + LL_PROFILE_ZONE_SCOPED; + if( success ) { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_LOADED); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries ); bump_image_map_t::iterator iter = entries_list.find(source_asset_id); { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_ENTRIES_UPDATE); if (iter == entries_list.end() || iter->second.isNull() || iter->second->getWidth() != src->getWidth() || iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution { //make sure an entry exists for this image - LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1); - raw->clear(0x77, 0x77, 0xFF, 0xFF); - - entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE); + entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(TRUE); iter = entries_list.find(src_vi->getID()); } } - //if (iter->second->getWidth() != src->getWidth() || - // iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution + if (iter->second->getWidth() != src->getWidth() || + iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution { LLPointer<LLImageRaw> dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1); U8* dst_data = dst_image->getData(); @@ -1277,7 +1085,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI case 1: case 2: { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_MIN_MAX); if( src_data_size == dst_data_size * src_components ) { for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) @@ -1303,7 +1110,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI case 3: case 4: { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_RGB2LUM); if( src_data_size == dst_data_size * src_components ) { for( S32 i = 0, j=0; i < dst_data_size; i++, j+= src_components ) @@ -1336,7 +1142,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI if( maximum > minimum ) { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_RESCALE); U8 bias_and_scale_lut[256]; F32 twice_one_over_range = 2.f / (maximum - minimum); S32 i; @@ -1366,113 +1171,146 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI } //--------------------------------------------------- - // immediately assign bump to a global smart pointer in case some local smart pointer + // immediately assign bump to a smart pointer in case some local smart pointer // accidentally releases it. - LLPointer<LLViewerTexture> bump = LLViewerTextureManager::getLocalTexture( TRUE ); + LLPointer<LLViewerTexture> bump = iter->second; if (!LLPipeline::sRenderDeferred) { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_CREATE); bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA); - bump->createGLTexture(0, dst_image); + +#if LL_BUMPLIST_MULTITHREADED + auto tex_queue = LLImageGLThread::sEnabled ? sTexUpdateQueue.lock() : nullptr; + + if (tex_queue) + { //dispatch creation to background thread + LLImageRaw* dst_ptr = dst_image; + LLViewerTexture* bump_ptr = bump; + dst_ptr->ref(); + bump_ptr->ref(); + tex_queue->post( + [=]() + { + LL_PROFILE_ZONE_NAMED("bil - create texture"); + bump_ptr->createGLTexture(0, dst_ptr); + bump_ptr->unref(); + dst_ptr->unref(); + }); + + } + else +#endif + { + bump->createGLTexture(0, dst_image); + } } else { //convert to normal map - - //disable compression on normal maps to prevent errors below - bump->getGLTexture()->setAllowCompression(false); - - { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_CREATE); - bump->setExplicitFormat(GL_RGBA8, GL_ALPHA); - bump->createGLTexture(0, dst_image); - } - - { - LL_RECORD_BLOCK_TIME(FTM_BUMP_SOURCE_GEN_NORMAL); - gPipeline.mScreen.bindTarget(); - - LLGLDepthTest depth(GL_FALSE); - LLGLDisable cull(GL_CULL_FACE); - LLGLDisable blend(GL_BLEND); - gGL.setColorMask(TRUE, TRUE); - gNormalMapGenProgram.bind(); - - static LLStaticHashedString sNormScale("norm_scale"); - static LLStaticHashedString sStepX("stepX"); - static LLStaticHashedString sStepY("stepY"); - - gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); - gNormalMapGenProgram.uniform1f(sStepX, 1.f/bump->getWidth()); - gNormalMapGenProgram.uniform1f(sStepY, 1.f/bump->getHeight()); - - LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(), - (F32) bump->getHeight()/gPipeline.mScreen.getHeight()); - - gGL.getTexUnit(0)->bind(bump); - - S32 width = bump->getWidth(); - S32 height = bump->getHeight(); - - S32 screen_width = gPipeline.mScreen.getWidth(); - S32 screen_height = gPipeline.mScreen.getHeight(); - - glViewport(0, 0, screen_width, screen_height); - - for (S32 left = 0; left < width; left += screen_width) - { - S32 right = left + screen_width; - right = llmin(right, width); - - F32 left_tc = (F32) left/ width; - F32 right_tc = (F32) right/width; - - for (S32 bottom = 0; bottom < height; bottom += screen_height) - { - S32 top = bottom+screen_height; - top = llmin(top, height); - - F32 bottom_tc = (F32) bottom/height; - F32 top_tc = (F32)(bottom+screen_height)/height; - top_tc = llmin(top_tc, 1.f); - - F32 screen_right = (F32) (right-left)/screen_width; - F32 screen_top = (F32) (top-bottom)/screen_height; - - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(left_tc, bottom_tc); - gGL.vertex2f(0, 0); - - gGL.texCoord2f(left_tc, top_tc); - gGL.vertex2f(0, screen_top); - - gGL.texCoord2f(right_tc, bottom_tc); - gGL.vertex2f(screen_right, 0); - - gGL.texCoord2f(right_tc, top_tc); - gGL.vertex2f(screen_right, screen_top); - - gGL.end(); - - gGL.flush(); - - S32 w = right-left; - S32 h = top-bottom; - - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h); - } - } - - glGenerateMipmap(GL_TEXTURE_2D); + LL_PROFILE_ZONE_NAMED("bil - create normal map"); + LLImageGL* img = bump->getGLTexture(); + LLImageRaw* dst_ptr = dst_image.get(); + LLGLTexture* bump_ptr = bump.get(); + + dst_ptr->ref(); + img->ref(); + bump_ptr->ref(); + auto create_func = [=]() + { + img->setUseMipMaps(TRUE); + // upload dst_image to GPU (greyscale in red channel) + img->setExplicitFormat(GL_RED, GL_RED); + + bump_ptr->createGLTexture(0, dst_ptr); + dst_ptr->unref(); + }; + + auto generate_func = [=]() + { + // Allocate an empty RGBA texture at "tex_name" the same size as bump + // Note: bump will still point at GPU copy of dst_image + bump_ptr->setExplicitFormat(GL_RGBA, GL_RGBA); + LLGLuint tex_name; + img->createGLTexture(0, nullptr, 0, 0, true, &tex_name); + + // point render target at empty buffer + sRenderTarget.setColorAttachment(img, tex_name); + + // generate normal map in empty texture + { + sRenderTarget.bindTarget(); + + LLGLDepthTest depth(GL_FALSE); + LLGLDisable cull(GL_CULL_FACE); + LLGLDisable blend(GL_BLEND); + gGL.setColorMask(TRUE, TRUE); + + gNormalMapGenProgram.bind(); + + static LLStaticHashedString sNormScale("norm_scale"); + static LLStaticHashedString sStepX("stepX"); + static LLStaticHashedString sStepY("stepY"); + + gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale")); + gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth()); + gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight()); + + gGL.getTexUnit(0)->bind(bump_ptr); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(0, 0); + gGL.vertex2f(0, 0); + + gGL.texCoord2f(0, 1); + gGL.vertex2f(0, 1); + + gGL.texCoord2f(1, 0); + gGL.vertex2f(1, 0); + + gGL.texCoord2f(1, 1); + gGL.vertex2f(1, 1); + + gGL.end(); + + gGL.flush(); + + gNormalMapGenProgram.unbind(); + + sRenderTarget.flush(); + sRenderTarget.releaseColorAttachment(); + } + + // point bump at normal map and free gpu copy of dst_image + img->syncTexName(tex_name); + + // generate mipmap + gGL.getTexUnit(0)->bind(img); + glGenerateMipmap(GL_TEXTURE_2D); + gGL.getTexUnit(0)->disable(); + + bump_ptr->unref(); + img->unref(); + }; + +#if LL_BUMPLIST_MULTITHREADED + auto main_queue = LLImageGLThread::sEnabled ? sMainQueue.lock() : nullptr; + + if (main_queue) + { //dispatch texture upload to background thread, issue GPU commands to generate normal map on main thread + main_queue->postTo( + sTexUpdateQueue, + create_func, + generate_func); + } + else +#endif + { // immediate upload texture and generate normal map + create_func(); + generate_func(); + } - gPipeline.mScreen.flush(); - gNormalMapGenProgram.unbind(); - - //generateNormalMapFromAlpha(dst_image, nrm_image); - } } - + iter->second = bump; // derefs (and deletes) old image //--------------------------------------------------- } @@ -1481,8 +1319,17 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI void LLDrawPoolBump::renderBump(U32 type, U32 mask) { - LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); - LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); + LLVOAvatar* avatar = nullptr; + U64 skin = 0; + + if (mRigged) + { // nudge type enum and include skinweights for rigged pass + type += 1; + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type); + LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type); for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i) { @@ -1490,6 +1337,21 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) if (LLDrawPoolBump::bindBumpMap(params)) { + if (mRigged) + { + if (avatar != params.mAvatar || skin != params.mSkinInfo->mHash) + { + if (uploadMatrixPalette(params)) + { + avatar = params.mAvatar; + skin = params.mSkinInfo->mHash; + } + else + { + continue; + } + } + } pushBatch(params, mask, FALSE); } } @@ -1497,6 +1359,7 @@ void LLDrawPoolBump::renderBump(U32 type, U32 mask) void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; applyModelMatrix(params); bool tex_setup = false; @@ -1507,7 +1370,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL { if (params.mTextureList[i].notNull()) { - gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE); + gGL.getTexUnit(i)->bindFast(params.mTextureList[i]); } } } @@ -1522,13 +1385,6 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL } else { - if (!LLGLSLShader::sNoFixedFunction) - { - gGL.getTexUnit(1)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); - } - gGL.getTexUnit(0)->activate(); gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); @@ -1545,8 +1401,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL { if (params.mTexture.notNull()) { - gGL.getTexUnit(diffuse_channel)->bind(params.mTexture); - params.mTexture->addTextureStats(params.mVSize); + gGL.getTexUnit(diffuse_channel)->bindFast(params.mTexture); } else { @@ -1559,10 +1414,10 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL { params.mGroup->rebuildMesh(); } - params.mVertexBuffer->setBuffer(mask); - params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); - gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); - if (tex_setup) + params.mVertexBuffer->setBufferFast(mask); + params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); + + if (tex_setup) { if (mShiny) { @@ -1570,12 +1425,6 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL } else { - if (!LLGLSLShader::sNoFixedFunction) - { - gGL.getTexUnit(1)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadIdentity(); - } gGL.getTexUnit(0)->activate(); gGL.matrixMode(LLRender::MM_TEXTURE); } @@ -1586,9 +1435,9 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL void LLDrawPoolInvisible::render(S32 pass) { //render invisiprims - LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE); - if (gPipeline.canUseVertexShaders()) + if (gPipeline.shadersLoaded()) { gOcclusionProgram.bind(); } @@ -1600,48 +1449,8 @@ void LLDrawPoolInvisible::render(S32 pass) gGL.setColorMask(true, false); glStencilMask(0xFFFFFFFF); - if (gPipeline.canUseVertexShaders()) + if (gPipeline.shadersLoaded()) { gOcclusionProgram.unbind(); } - - if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) - { - beginShiny(true); - renderShiny(true); - endShiny(true); - } -} - -void LLDrawPoolInvisible::beginDeferredPass(S32 pass) -{ - beginRenderPass(pass); -} - -void LLDrawPoolInvisible::endDeferredPass( S32 pass ) -{ - endRenderPass(pass); -} - -void LLDrawPoolInvisible::renderDeferred( S32 pass ) -{ //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff -#if 0 - LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE); - - U32 invisi_mask = LLVertexBuffer::MAP_VERTEX; - glStencilMask(0); - glStencilOp(GL_ZERO, GL_KEEP, GL_REPLACE); - gGL.setColorMask(false, false); - pushBatches(LLRenderPass::PASS_INVISIBLE, invisi_mask, FALSE); - gGL.setColorMask(true, true); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - glStencilMask(0xFFFFFFFF); - - if (gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) - { - beginShiny(true); - renderShiny(true); - endShiny(true); - } -#endif } diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 476b1d41b7..e8a027967b 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -32,6 +32,8 @@ #include "lltextureentry.h" #include "lluuid.h" +#include <unordered_map> + class LLImageRaw; class LLSpatialGroup; class LLDrawInfo; @@ -46,52 +48,47 @@ public: static U32 sVertexMask; BOOL mShiny; - virtual U32 getVertexDataMask() { return sVertexMask; } + virtual U32 getVertexDataMask() override { return sVertexMask; } LLDrawPoolBump(); - virtual void render(S32 pass = 0); - virtual void beginRenderPass( S32 pass ); - virtual void endRenderPass( S32 pass ); - virtual S32 getNumPasses(); - /*virtual*/ void prerender(); - /*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE); + virtual void render(S32 pass = 0) override; + virtual S32 getNumPasses() override; + /*virtual*/ void prerender() override; + void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE) override; void renderBump(U32 type, U32 mask); - void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture); + void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture) override; S32 numBumpPasses(); - void beginShiny(bool invisible = false); - void renderShiny(bool invisible = false); - void endShiny(bool invisible = false); + void beginShiny(); + void renderShiny(); + void endShiny(); void beginFullbrightShiny(); void renderFullbrightShiny(); void endFullbrightShiny(); - void beginBump(U32 pass = LLRenderPass::PASS_BUMP); + void beginBump(); void renderBump(U32 pass = LLRenderPass::PASS_BUMP); void endBump(U32 pass = LLRenderPass::PASS_BUMP); - static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible); - static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible); + static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel); + static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel); - virtual S32 getNumDeferredPasses(); - /*virtual*/ void beginDeferredPass(S32 pass); - /*virtual*/ void endDeferredPass(S32 pass); - /*virtual*/ void renderDeferred(S32 pass); + virtual S32 getNumDeferredPasses() override; + /*virtual*/ void renderDeferred(S32 pass) override; - virtual S32 getNumPostDeferredPasses() { return 2; } - /*virtual*/ void beginPostDeferredPass(S32 pass); - /*virtual*/ void endPostDeferredPass(S32 pass); - /*virtual*/ void renderPostDeferred(S32 pass); + virtual S32 getNumPostDeferredPasses() override { return 1; } + /*virtual*/ void renderPostDeferred(S32 pass) override; static BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2); static BOOL bindBumpMap(LLFace* face, S32 channel = -2); private: static BOOL bindBumpMap(U8 bump_code, LLViewerTexture* tex, F32 vsize, S32 channel); + bool mRigged = false; // if true, doing a rigged pass }; @@ -161,17 +158,20 @@ private: static void onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump ); private: - typedef std::map<LLUUID, LLPointer<LLViewerTexture> > bump_image_map_t; + typedef std::unordered_map<LLUUID, LLPointer<LLViewerTexture> > bump_image_map_t; bump_image_map_t mBrightnessEntries; bump_image_map_t mDarknessEntries; + static LL::WorkQueue::weak_t sMainQueue; + static LL::WorkQueue::weak_t sTexUpdateQueue; + static LLRenderTarget sRenderTarget; }; extern LLBumpImageList gBumpImageList; -class LLDrawPoolInvisible : public LLDrawPoolBump +class LLDrawPoolInvisible : public LLRenderPass { public: - LLDrawPoolInvisible() : LLDrawPoolBump(LLDrawPool::POOL_INVISIBLE) { } + LLDrawPoolInvisible() : LLRenderPass(LLDrawPool::POOL_INVISIBLE) { } enum { @@ -186,11 +186,6 @@ public: virtual void beginRenderPass( S32 pass ) { } virtual void endRenderPass( S32 pass ) { } virtual S32 getNumPasses() {return 1;} - - virtual S32 getNumDeferredPasses() { return 1; } - /*virtual*/ void beginDeferredPass(S32 pass); - /*virtual*/ void endDeferredPass(S32 pass); - /*virtual*/ void renderDeferred(S32 pass); }; diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp index 05b0c1f1a9..2b05f4c453 100644 --- a/indra/newview/lldrawpoolmaterials.cpp +++ b/indra/newview/lldrawpoolmaterials.cpp @@ -31,6 +31,7 @@ #include "llviewershadermgr.h" #include "pipeline.h" #include "llglcommonfunc.h" +#include "llvoavatar.h" S32 diffuse_channel = -1; @@ -47,11 +48,20 @@ void LLDrawPoolMaterials::prerender() S32 LLDrawPoolMaterials::getNumDeferredPasses() { - return 12; + // 12 render passes times 2 (one for each rigged and non rigged) + return 12*2; } void LLDrawPoolMaterials::beginDeferredPass(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL; + + bool rigged = false; + if (pass >= 12) + { + rigged = true; + pass -= 12; + } U32 shader_idx[] = { 0, //LLRenderPass::PASS_MATERIAL, @@ -72,13 +82,22 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass) 15, //LLRenderPass::PASS_NORMSPEC_GLOW, }; - mShader = &(gDeferredMaterialProgram[shader_idx[pass]]); - - if (LLPipeline::sUnderWaterRender) - { - mShader = &(gDeferredMaterialWaterProgram[shader_idx[pass]]); - } - + U32 idx = shader_idx[pass]; + + if (LLPipeline::sUnderWaterRender) + { + mShader = &(gDeferredMaterialWaterProgram[idx]); + } + else + { + mShader = &(gDeferredMaterialProgram[idx]); + } + + if (rigged) + { + llassert(mShader->mRiggedVariant != nullptr); + mShader = mShader->mRiggedVariant; + } mShader->bind(); if (LLPipeline::sRenderingHUDs) @@ -91,13 +110,11 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass) } diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP); - - LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS); } void LLDrawPoolMaterials::endDeferredPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_MATERIALS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL; mShader->unbind(); @@ -106,6 +123,7 @@ void LLDrawPoolMaterials::endDeferredPass(S32 pass) void LLDrawPoolMaterials::renderDeferred(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL; static const U32 type_list[] = { LLRenderPass::PASS_MATERIAL, @@ -126,9 +144,20 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass) LLRenderPass::PASS_NORMSPEC_EMISSIVE, }; + bool rigged = false; + if (pass >= 12) + { + rigged = true; + pass -= 12; + } + llassert(pass < sizeof(type_list)/sizeof(U32)); U32 type = type_list[pass]; + if (rigged) + { + type += 1; + } U32 mask = mShader->mAttributeMask; @@ -157,7 +186,10 @@ void LLDrawPoolMaterials::renderDeferred(S32 pass) mShader->setMinimumAlpha(params.mAlphaMaskCutoff); mShader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, params.mFullbright ? 1.f : 0.f); - pushBatch(params, mask, TRUE); + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL; + pushMaterialsBatch(params, mask, rigged); + } } } @@ -171,49 +203,37 @@ void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex) mShader->bindTexture(LLShaderMgr::BUMP_MAP, tex); } -void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) +void LLDrawPoolMaterials::pushMaterialsBatch(LLDrawInfo& params, U32 mask, bool rigged) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MATERIAL; applyModelMatrix(params); bool tex_setup = false; - if (batch_textures && params.mTextureList.size() > 1) + //not batching textures or batch has only 1 texture -- might need a texture matrix + if (params.mTextureMatrix) { - for (U32 i = 0; i < params.mTextureList.size(); ++i) + //if (mShiny) { - if (params.mTextureList[i].notNull()) - { - gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE); - } + gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); } - } - else - { //not batching textures or batch has only 1 texture -- might need a texture matrix - if (params.mTextureMatrix) - { - //if (mShiny) - { - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - } - gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); - gPipeline.mTextureMatrixOps++; + gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix); + gPipeline.mTextureMatrixOps++; - tex_setup = true; - } + tex_setup = true; + } - if (mShaderLevel > 1 && texture) + if (mShaderLevel > 1) + { + if (params.mTexture.notNull()) { - if (params.mTexture.notNull()) - { - gGL.getTexUnit(diffuse_channel)->bind(params.mTexture); - params.mTexture->addTextureStats(params.mVSize); - } - else - { - gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE); - } + gGL.getTexUnit(diffuse_channel)->bindFast(params.mTexture); + } + else + { + gGL.getTexUnit(diffuse_channel)->unbindFast(LLTexUnit::TT_TEXTURE); } } @@ -222,11 +242,29 @@ void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, params.mGroup->rebuildMesh(); } + // upload matrix palette to shader + if (rigged && params.mAvatar.notNull()) + { + const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo); + U32 count = mpc.mMatrixPalette.size(); + + if (count == 0) + { + //skin info not loaded yet, don't render + return; + } + + mShader->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, + count, + FALSE, + (GLfloat*)&(mpc.mGLMp[0])); + } + LLGLEnableFunc stencil_test(GL_STENCIL_TEST, params.mSelected, &LLGLCommonFunc::selected_stencil_test); - params.mVertexBuffer->setBuffer(mask); - params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); - gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode); + params.mVertexBuffer->setBufferFast(mask); + params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset); + if (tex_setup) { gGL.getTexUnit(0)->activate(); diff --git a/indra/newview/lldrawpoolmaterials.h b/indra/newview/lldrawpoolmaterials.h index eae1aba87c..8a3ad923df 100644 --- a/indra/newview/lldrawpoolmaterials.h +++ b/indra/newview/lldrawpoolmaterials.h @@ -55,21 +55,21 @@ public: LLVertexBuffer::MAP_TANGENT }; - /*virtual*/ U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + U32 getVertexDataMask() override { return VERTEX_DATA_MASK; } - /*virtual*/ void render(S32 pass = 0) { } - /*virtual*/ S32 getNumPasses() {return 0;} - /*virtual*/ void prerender(); + void render(S32 pass = 0) override { } + S32 getNumPasses() override {return 0;} + void prerender() override; - /*virtual*/ S32 getNumDeferredPasses(); - /*virtual*/ void beginDeferredPass(S32 pass); - /*virtual*/ void endDeferredPass(S32 pass); - /*virtual*/ void renderDeferred(S32 pass); + S32 getNumDeferredPasses() override; + void beginDeferredPass(S32 pass) override; + void endDeferredPass(S32 pass) override; + void renderDeferred(S32 pass) override; void bindSpecularMap(LLViewerTexture* tex); void bindNormalMap(LLViewerTexture* tex); - /*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE); + void pushMaterialsBatch(LLDrawInfo& params, U32 mask, bool rigged); }; #endif //LL_LLDRAWPOOLMATERIALS_H diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index f211cf6e27..e324a663f4 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -38,71 +38,54 @@ #include "llrender.h" static LLGLSLShader* simple_shader = NULL; -static LLGLSLShader* fullbright_shader = NULL; static LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE_DEFERRED("Deferred Simple"); static LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS_DEFERRED("Deferred Grass"); -void LLDrawPoolGlow::beginPostDeferredPass(S32 pass) + +static void setup_simple_shader(LLGLSLShader* shader) { - gDeferredEmissiveProgram.bind(); - gDeferredEmissiveProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + shader->bind(); + if (LLPipeline::sRenderingHUDs) - { - gDeferredEmissiveProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - gDeferredEmissiveProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); - } + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 1); + } + else + { + shader->uniform1i(LLShaderMgr::NO_ATMO, 0); + } } -static LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW_PUSH("Glow Push"); - -void LLDrawPoolGlow::renderPostDeferred(S32 pass) +static void setup_glow_shader(LLGLSLShader* shader) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW); - LLGLEnable blend(GL_BLEND); - LLGLDisable test(GL_ALPHA_TEST); - gGL.flush(); - /// Get rid of z-fighting with non-glow pass. - LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL); - glPolygonOffset(-1.0f, -1.0f); - gGL.setSceneBlendType(LLRender::BT_ADD); - - LLGLDepthTest depth(GL_TRUE, GL_FALSE); - gGL.setColorMask(false, true); - - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW_PUSH); - pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - } - - gGL.setColorMask(true, false); - gGL.setSceneBlendType(LLRender::BT_ALPHA); + setup_simple_shader(shader); + if (LLPipeline::sRenderDeferred && !LLPipeline::sRenderingHUDs) + { + shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); + } + else + { + shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f); + } } -void LLDrawPoolGlow::endPostDeferredPass(S32 pass) +static void setup_fullbright_shader(LLGLSLShader* shader) { - gDeferredEmissiveProgram.unbind(); - LLRenderPass::endRenderPass(pass); + setup_glow_shader(shader); + shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f); } -S32 LLDrawPoolGlow::getNumPasses() + +void LLDrawPoolGlow::renderPostDeferred(S32 pass) { - if (LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0) - { - return 1; - } - else - { - return 0; - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW); + render(&gDeferredEmissiveProgram); } -void LLDrawPoolGlow::render(S32 pass) +void LLDrawPoolGlow::render(LLGLSLShader* shader) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GLOW); LLGLEnable blend(GL_BLEND); LLGLDisable test(GL_ALPHA_TEST); gGL.flush(); @@ -111,51 +94,33 @@ void LLDrawPoolGlow::render(S32 pass) glPolygonOffset(-1.0f, -1.0f); gGL.setSceneBlendType(LLRender::BT_ADD); - U32 shader_level = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); - - //should never get here without basic shaders enabled - llassert(shader_level > 0); - - LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; - shader->bind(); - if (LLPipeline::sRenderDeferred) - { - shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - } - else - { - shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f); - } - - if (LLPipeline::sRenderingHUDs) - { - shader->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - shader->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - LLGLDepthTest depth(GL_TRUE, GL_FALSE); gGL.setColorMask(false, true); - pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - - gGL.setColorMask(true, false); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - if (shader_level > 0 && fullbright_shader) - { - shader->unbind(); - } + //first pass -- static objects + setup_glow_shader(shader); + pushBatches(LLRenderPass::PASS_GLOW, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + + // second pass -- rigged objects + shader = shader->mRiggedVariant; + setup_glow_shader(shader); + pushRiggedBatches(LLRenderPass::PASS_GLOW_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + + gGL.setColorMask(true, false); + gGL.setSceneBlendType(LLRender::BT_ALPHA); } -void LLDrawPoolGlow::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures) +S32 LLDrawPoolGlow::getNumPasses() { - //gGL.diffuseColor4ubv(params.mGlowColor.mV); - LLRenderPass::pushBatch(params, mask, texture, batch_textures); + return 1; } +void LLDrawPoolGlow::render(S32 pass) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram; + render(shader); +} LLDrawPoolSimple::LLDrawPoolSimple() : LLRenderPass(POOL_SIMPLE) @@ -167,100 +132,73 @@ void LLDrawPoolSimple::prerender() mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } -void LLDrawPoolSimple::beginRenderPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); - - if (LLPipeline::sImpostorRender) - { - simple_shader = &gObjectSimpleImpostorProgram; - } - else if (LLPipeline::sUnderWaterRender) - { - simple_shader = &gObjectSimpleWaterProgram; - } - else - { - simple_shader = &gObjectSimpleProgram; - } - - if (mShaderLevel > 0) - { - simple_shader->bind(); - - if (LLPipeline::sRenderingHUDs) - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - } - else - { - // don't use shaders! - if (gGLManager.mHasShaderObjects) - { - LLGLSLShader::bindNoShader(); - } - } -} - -void LLDrawPoolSimple::endRenderPass(S32 pass) +S32 LLDrawPoolSimple::getNumPasses() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); - stop_glerror(); - LLRenderPass::endRenderPass(pass); - stop_glerror(); - if (mShaderLevel > 0) - { - simple_shader->unbind(); - } + return 1; } void LLDrawPoolSimple::render(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); + LLGLDisable blend(GL_BLEND); + LLGLSLShader* shader = nullptr; + if (LLPipeline::sImpostorRender) + { + shader = &gObjectSimpleImpostorProgram; + } + else if (LLPipeline::sUnderWaterRender) + { + shader = &gObjectSimpleWaterProgram; + } + else + { + shader = &gObjectSimpleProgram; + } + { //render simple - LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE); + gPipeline.enableLightsDynamic(); - if (mShaderLevel > 0) - { - U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX; - - pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE); - - if (LLPipeline::sRenderDeferred) - { //if deferred rendering is enabled, bump faces aren't registered as simple - //render bump faces here as simple so bump faces will appear under water - pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE); - pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE); - pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE); - pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE); - pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE); - } - } - else - { - LLGLDisable alpha_test(GL_ALPHA_TEST); - renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask()); - } - + U32 mask = getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX; + + // first pass -- static objects + { + setup_simple_shader(shader); + pushBatches(LLRenderPass::PASS_SIMPLE, mask, TRUE, TRUE); + + if (LLPipeline::sRenderDeferred) + { //if deferred rendering is enabled, bump faces aren't registered as simple + //render bump faces here as simple so bump faces will appear under water + pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE); + } + } + + //second pass, rigged + { + shader = shader->mRiggedVariant; + setup_simple_shader(shader); + pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, mask, TRUE, TRUE); + + if (LLPipeline::sRenderDeferred) + { //if deferred rendering is enabled, bump faces aren't registered as simple + //render bump faces here as simple so bump faces will appear under water + pushRiggedBatches(LLRenderPass::PASS_BUMP_RIGGED, mask, TRUE, TRUE); + pushRiggedBatches(LLRenderPass::PASS_MATERIAL_RIGGED, mask, TRUE, TRUE); + pushRiggedBatches(LLRenderPass::PASS_SPECMAP_RIGGED, mask, TRUE, TRUE); + pushRiggedBatches(LLRenderPass::PASS_NORMMAP_RIGGED, mask, TRUE, TRUE); + pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_RIGGED, mask, TRUE, TRUE); + } + } } } - - - - - - - - static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK("Alpha Mask"); LLDrawPoolAlphaMask::LLDrawPoolAlphaMask() : @@ -273,85 +211,36 @@ void LLDrawPoolAlphaMask::prerender() mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } -void LLDrawPoolAlphaMask::beginRenderPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); - - if (LLPipeline::sUnderWaterRender) - { - simple_shader = &gObjectSimpleWaterAlphaMaskProgram; - } - else - { - simple_shader = &gObjectSimpleAlphaMaskProgram; - } - - if (mShaderLevel > 0) - { - simple_shader->bind(); - - if (LLPipeline::sRenderingHUDs) - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - } - else - { - // don't use shaders! - if (gGLManager.mHasShaderObjects) - { - LLGLSLShader::bindNoShader(); - } - } -} - -void LLDrawPoolAlphaMask::endRenderPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); - stop_glerror(); - LLRenderPass::endRenderPass(pass); - stop_glerror(); - if (mShaderLevel > 0) - { - simple_shader->unbind(); - } -} - void LLDrawPoolAlphaMask::render(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLGLDisable blend(GL_BLEND); - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); - if (mShaderLevel > 0) - { - simple_shader->bind(); - simple_shader->setMinimumAlpha(0.33f); + LLGLSLShader* shader = nullptr; + if (LLPipeline::sUnderWaterRender) + { + shader = &gObjectSimpleWaterAlphaMaskProgram; + } + else + { + shader = &gObjectSimpleAlphaMaskProgram; + } - if (LLPipeline::sRenderingHUDs) - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); - } + // render static + setup_simple_shader(shader); + pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - } - else - { - LLGLEnable test(GL_ALPHA_TEST); - pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK - } + // render rigged + setup_simple_shader(shader->mRiggedVariant); + pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushRiggedMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushRiggedMaskBatches(LLRenderPass::PASS_SPECMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushRiggedMaskBatches(LLRenderPass::PASS_NORMMAP_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + pushRiggedMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } LLDrawPoolFullbrightAlphaMask::LLDrawPoolFullbrightAlphaMask() : @@ -364,166 +253,70 @@ void LLDrawPoolFullbrightAlphaMask::prerender() mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } -void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass) +void LLDrawPoolFullbrightAlphaMask::render(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); - - if (LLPipeline::sUnderWaterRender) - { - simple_shader = &gObjectFullbrightWaterAlphaMaskProgram; - } - else - { - simple_shader = &gObjectFullbrightAlphaMaskProgram; - } - - if (mShaderLevel > 0) - { - simple_shader->bind(); - - if (LLPipeline::sRenderingHUDs) - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - } - else - { - // don't use shaders! - if (gGLManager.mHasShaderObjects) - { - LLGLSLShader::bindNoShader(); - } - } -} + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); -void LLDrawPoolFullbrightAlphaMask::endRenderPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); - stop_glerror(); - LLRenderPass::endRenderPass(pass); - stop_glerror(); - if (mShaderLevel > 0) - { - simple_shader->unbind(); - } -} + LLGLSLShader* shader = nullptr; + if (LLPipeline::sUnderWaterRender) + { + shader = &gObjectFullbrightWaterAlphaMaskProgram; + } + else + { + shader = &gObjectFullbrightAlphaMaskProgram; + } -void LLDrawPoolFullbrightAlphaMask::render(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK); + // render static + setup_fullbright_shader(shader); + pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - if (mShaderLevel > 0) - { - if (simple_shader) - { - simple_shader->bind(); - simple_shader->setMinimumAlpha(0.33f); - - if (LLPipeline::sRenderingHUDs) - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); - simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - } - else - { - simple_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); - if (LLPipeline::sRenderDeferred) - { - simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - } - else - { - simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - } - } - } - pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - //LLGLSLShader::bindNoShader(); - } - else - { - LLGLEnable test(GL_ALPHA_TEST); - gPipeline.enableLightsFullbright(); - pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE); - gPipeline.enableLightsDynamic(); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK - } + // render rigged + setup_fullbright_shader(shader->mRiggedVariant); + pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } //=============================== //DEFERRED IMPLEMENTATION //=============================== -void LLDrawPoolSimple::beginDeferredPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED); - gDeferredDiffuseProgram.bind(); - - if (LLPipeline::sRenderingHUDs) - { - gDeferredDiffuseProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - gDeferredDiffuseProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); - } -} - -void LLDrawPoolSimple::endDeferredPass(S32 pass) +S32 LLDrawPoolSimple::getNumDeferredPasses() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED); - LLRenderPass::endRenderPass(pass); - - gDeferredDiffuseProgram.unbind(); + return 1; } void LLDrawPoolSimple::renderDeferred(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED); LLGLDisable blend(GL_BLEND); LLGLDisable alpha_test(GL_ALPHA_TEST); - { //render simple - LL_RECORD_BLOCK_TIME(FTM_RENDER_SIMPLE_DEFERRED); - pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - } + //render static + setup_simple_shader(&gDeferredDiffuseProgram); + pushBatches(LLRenderPass::PASS_SIMPLE, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); + + //render rigged + setup_simple_shader(gDeferredDiffuseProgram.mRiggedVariant); + pushRiggedBatches(LLRenderPass::PASS_SIMPLE_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } static LLTrace::BlockTimerStatHandle FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Alpha Mask"); -void LLDrawPoolAlphaMask::beginDeferredPass(S32 pass) -{ - -} - -void LLDrawPoolAlphaMask::endDeferredPass(S32 pass) -{ - -} void LLDrawPoolAlphaMask::renderDeferred(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED); - gDeferredDiffuseAlphaMaskProgram.bind(); - gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_ALPHA_MASK_DEFERRED); + LLGLSLShader* shader = &gDeferredDiffuseAlphaMaskProgram; - if (LLPipeline::sRenderingHUDs) - { - gDeferredDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - gDeferredDiffuseAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); - } + //render static + setup_simple_shader(shader); + pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); - gDeferredDiffuseAlphaMaskProgram.unbind(); + //render rigged + setup_simple_shader(shader->mRiggedVariant); + pushRiggedMaskBatches(LLRenderPass::PASS_ALPHA_MASK_RIGGED, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE); } - // grass drawpool LLDrawPoolGrass::LLDrawPoolGrass() : LLRenderPass(POOL_GRASS) @@ -539,7 +332,7 @@ void LLDrawPoolGrass::prerender() void LLDrawPoolGrass::beginRenderPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); stop_glerror(); if (LLPipeline::sUnderWaterRender) @@ -566,18 +359,14 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass) } else { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); - // don't use shaders! - if (gGLManager.mHasShaderObjects) - { - LLGLSLShader::bindNoShader(); - } + gGL.flush(); + LLGLSLShader::bindNoShader(); } } void LLDrawPoolGrass::endRenderPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); LLRenderPass::endRenderPass(pass); if (mShaderLevel > 0) @@ -586,20 +375,21 @@ void LLDrawPoolGrass::endRenderPass(S32 pass) } else { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.flush(); } } void LLDrawPoolGrass::render(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLGLDisable blend(GL_BLEND); { - LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); + //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS); LLGLEnable test(GL_ALPHA_TEST); gGL.setSceneBlendType(LLRender::BT_ALPHA); //render grass - LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask()); + LLRenderPass::pushBatches(LLRenderPass::PASS_GRASS, getVertexDataMask()); } } @@ -615,8 +405,9 @@ void LLDrawPoolGrass::endDeferredPass(S32 pass) void LLDrawPoolGrass::renderDeferred(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; { - LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED); + //LL_RECORD_BLOCK_TIME(FTM_RENDER_GRASS_DEFERRED); gDeferredNonIndexedDiffuseAlphaMaskProgram.bind(); gDeferredNonIndexedDiffuseAlphaMaskProgram.setMinimumAlpha(0.5f); @@ -630,7 +421,7 @@ void LLDrawPoolGrass::renderDeferred(S32 pass) } //render grass - LLRenderPass::renderTexture(LLRenderPass::PASS_GRASS, getVertexDataMask()); + LLRenderPass::pushBatches(LLRenderPass::PASS_GRASS, getVertexDataMask()); } } @@ -646,120 +437,67 @@ void LLDrawPoolFullbright::prerender() mShaderLevel = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); } -void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass) -{ - if (LLPipeline::sUnderWaterRender) - { - gDeferredFullbrightWaterProgram.bind(); - } - else - { - gDeferredFullbrightProgram.bind(); - - if (LLPipeline::sRenderingHUDs) - { - gDeferredFullbrightProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - gDeferredFullbrightProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); - } - } - -} void LLDrawPoolFullbright::renderPostDeferred(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; - pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE); -} - -void LLDrawPoolFullbright::endPostDeferredPass(S32 pass) -{ - if (LLPipeline::sUnderWaterRender) - { - gDeferredFullbrightWaterProgram.unbind(); - } - else - { - gDeferredFullbrightProgram.unbind(); - } - LLRenderPass::endRenderPass(pass); -} - -void LLDrawPoolFullbright::beginRenderPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); - - if (LLPipeline::sUnderWaterRender) - { - fullbright_shader = &gObjectFullbrightWaterProgram; - } - else - { - fullbright_shader = &gObjectFullbrightProgram; - } -} - -void LLDrawPoolFullbright::endRenderPass(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); - LLRenderPass::endRenderPass(pass); - - stop_glerror(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); - if (mShaderLevel > 0) - { - fullbright_shader->unbind(); - } + LLGLSLShader* shader = nullptr; + if (LLPipeline::sUnderWaterRender) + { + shader = &gDeferredFullbrightWaterProgram; + } + else + { + shader = &gDeferredFullbrightProgram; + } - stop_glerror(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; + + // render static + setup_fullbright_shader(shader); + pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE); + + // render rigged + setup_fullbright_shader(shader->mRiggedVariant); + pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, fullbright_mask, TRUE, TRUE); } void LLDrawPoolFullbright::render(S32 pass) { //render fullbright - LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); gGL.setSceneBlendType(LLRender::BT_ALPHA); stop_glerror(); + LLGLSLShader* shader = nullptr; + if (LLPipeline::sUnderWaterRender) + { + shader = &gObjectFullbrightWaterProgram; + } + else + { + shader = &gObjectFullbrightProgram; + } - if (mShaderLevel > 0) - { - fullbright_shader->bind(); - fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f); - fullbright_shader->uniform1f(LLViewerShaderMgr::TEXTURE_GAMMA, 1.f); - - if (LLPipeline::sRenderingHUDs) - { - fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - fullbright_shader->uniform1i(LLShaderMgr::NO_ATMO, 0); - } - U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; - pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE); - pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask, TRUE, TRUE); - pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask, TRUE, TRUE); - pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask, TRUE, TRUE); - pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask, TRUE, TRUE); - } - else - { - gPipeline.enableLightsFullbright(); - U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR; - renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask); - pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask); - pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask); - pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask); - pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask); - } + U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; - stop_glerror(); + // render static + setup_fullbright_shader(shader); + pushBatches(LLRenderPass::PASS_FULLBRIGHT, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, mask, TRUE, TRUE); + pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, mask, TRUE, TRUE); + + // render rigged + setup_fullbright_shader(shader->mRiggedVariant); + pushRiggedBatches(LLRenderPass::PASS_FULLBRIGHT_RIGGED, mask, TRUE, TRUE); + pushRiggedBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, mask, TRUE, TRUE); + pushRiggedBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED, mask, TRUE, TRUE); + pushRiggedBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED, mask, TRUE, TRUE); + pushRiggedBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, mask, TRUE, TRUE); } S32 LLDrawPoolFullbright::getNumPasses() @@ -767,65 +505,40 @@ S32 LLDrawPoolFullbright::getNumPasses() return 1; } - -void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass) +void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass) { - + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); + + LLGLSLShader* shader = nullptr; if (LLPipeline::sRenderingHUDs) { - gObjectFullbrightAlphaMaskProgram.bind(); - gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - gObjectFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); + shader = &gObjectFullbrightAlphaMaskProgram; } - else if (LLPipeline::sRenderDeferred) - { + else if (LLPipeline::sRenderDeferred) + { if (LLPipeline::sUnderWaterRender) - { - gDeferredFullbrightAlphaMaskWaterProgram.bind(); - gDeferredFullbrightAlphaMaskWaterProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - gDeferredFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 1); - } - else - { - gDeferredFullbrightAlphaMaskProgram.bind(); - gDeferredFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); - gDeferredFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); - } + { + shader = &gDeferredFullbrightAlphaMaskWaterProgram; + } + else + { + shader = &gDeferredFullbrightAlphaMaskProgram; + } } else { - gObjectFullbrightAlphaMaskProgram.bind(); - gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f); - gObjectFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::NO_ATMO, 0); - } -} + shader = &gObjectFullbrightAlphaMaskProgram; + } -void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass) -{ - LL_RECORD_BLOCK_TIME(FTM_RENDER_FULLBRIGHT); LLGLDisable blend(GL_BLEND); U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX; - pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE); + + // render static + setup_fullbright_shader(shader); + pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE); + + // render rigged + setup_fullbright_shader(shader->mRiggedVariant); + pushRiggedMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, fullbright_mask, TRUE, TRUE); } -void LLDrawPoolFullbrightAlphaMask::endPostDeferredPass(S32 pass) -{ - if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred) - { - gObjectFullbrightAlphaMaskProgram.unbind(); - } - else - { - if (LLPipeline::sUnderWaterRender) - { - gDeferredFullbrightAlphaMaskWaterProgram.unbind(); - } - else - { - gDeferredFullbrightAlphaMaskProgram.unbind(); - } - } - LLRenderPass::endRenderPass(pass); -} - - diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h index 608ad9e1eb..cccbe5e495 100644 --- a/indra/newview/lldrawpoolsimple.h +++ b/indra/newview/lldrawpoolsimple.h @@ -29,6 +29,8 @@ #include "lldrawpool.h" +class LLGLSLShader; + class LLDrawPoolSimple : public LLRenderPass { public: @@ -39,22 +41,17 @@ public: LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR }; - virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + virtual U32 getVertexDataMask() override { return VERTEX_DATA_MASK; } LLDrawPoolSimple(); - /*virtual*/ S32 getNumDeferredPasses() { return 1; } - /*virtual*/ void beginDeferredPass(S32 pass); - /*virtual*/ void endDeferredPass(S32 pass); - /*virtual*/ void renderDeferred(S32 pass); + S32 getNumDeferredPasses() override; + void renderDeferred(S32 pass) override; - /*virtual*/ void beginRenderPass(S32 pass); - /*virtual*/ void endRenderPass(S32 pass); /// We need two passes so we can handle emissive materials separately. - /*virtual*/ S32 getNumPasses() { return 1; } - /*virtual*/ void render(S32 pass = 0); - /*virtual*/ void prerender(); - + S32 getNumPasses() override; + void render(S32 pass = 0) override; + void prerender() override; }; class LLDrawPoolGrass : public LLRenderPass @@ -99,13 +96,9 @@ public: LLDrawPoolAlphaMask(); /*virtual*/ S32 getNumDeferredPasses() { return 1; } - /*virtual*/ void beginDeferredPass(S32 pass); - /*virtual*/ void endDeferredPass(S32 pass); /*virtual*/ void renderDeferred(S32 pass); /*virtual*/ S32 getNumPasses() { return 1; } - /*virtual*/ void beginRenderPass(S32 pass); - /*virtual*/ void endRenderPass(S32 pass); /*virtual*/ void render(S32 pass = 0); /*virtual*/ void prerender(); @@ -125,13 +118,9 @@ public: LLDrawPoolFullbrightAlphaMask(); /*virtual*/ S32 getNumPostDeferredPasses() { return 1; } - /*virtual*/ void beginPostDeferredPass(S32 pass); - /*virtual*/ void endPostDeferredPass(S32 pass); /*virtual*/ void renderPostDeferred(S32 pass); /*virtual*/ S32 getNumPasses() { return 1; } - /*virtual*/ void beginRenderPass(S32 pass); - /*virtual*/ void endRenderPass(S32 pass); /*virtual*/ void render(S32 pass = 0); /*virtual*/ void prerender(); }; @@ -151,12 +140,8 @@ public: LLDrawPoolFullbright(); /*virtual*/ S32 getNumPostDeferredPasses() { return 1; } - /*virtual*/ void beginPostDeferredPass(S32 pass); - /*virtual*/ void endPostDeferredPass(S32 pass); /*virtual*/ void renderPostDeferred(S32 pass); - /*virtual*/ void beginRenderPass(S32 pass); - /*virtual*/ void endRenderPass(S32 pass); /*virtual*/ S32 getNumPasses(); /*virtual*/ void render(S32 pass = 0); /*virtual*/ void prerender(); @@ -180,14 +165,13 @@ public: virtual void prerender() { } /*virtual*/ S32 getNumPostDeferredPasses() { return 1; } - /*virtual*/ void beginPostDeferredPass(S32 pass); - /*virtual*/ void endPostDeferredPass(S32 pass); /*virtual*/ void renderPostDeferred(S32 pass); + void render(LLGLSLShader* shader); + /*virtual*/ S32 getNumPasses(); void render(S32 pass = 0); - void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE); }; diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp index b6f55e800a..3a1efec91b 100644 --- a/indra/newview/lldrawpoolsky.cpp +++ b/indra/newview/lldrawpoolsky.cpp @@ -76,22 +76,8 @@ void LLDrawPoolSky::render(S32 pass) } - if (LLGLSLShader::sNoFixedFunction) - { //just use the UI shader (generic single texture no lighting) - gOneTextureNoColorProgram.bind(); - } - else - { - // don't use shaders! - if (gGLManager.mHasShaderObjects) - { - // Ironically, we must support shader objects to be - // able to use this call. - LLGLSLShader::bindNoShader(); - } - mShader = NULL; - } - + //just use the UI shader (generic single texture no lighting) + gOneTextureNoColorProgram.bind(); LLGLSPipelineDepthTestSkyBox gls_skybox(true, false); diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 37dc80e2b7..cc5cb667f0 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -111,7 +111,7 @@ void LLDrawPoolTerrain::prerender() void LLDrawPoolTerrain::beginRenderPass( S32 pass ) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); sShader = LLPipeline::sUnderWaterRender ? @@ -126,7 +126,7 @@ void LLDrawPoolTerrain::beginRenderPass( S32 pass ) void LLDrawPoolTerrain::endRenderPass( S32 pass ) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); //LLFacePool::endRenderPass(pass); if (mShaderLevel > 1 && sShader->mShaderLevel > 0) { @@ -154,7 +154,7 @@ void LLDrawPoolTerrain::boostTerrainDetailTextures() void LLDrawPoolTerrain::render(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); if (mDrawFace.empty()) { @@ -213,7 +213,7 @@ void LLDrawPoolTerrain::render(S32 pass) void LLDrawPoolTerrain::beginDeferredPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); sShader = LLPipeline::sUnderWaterRender ? &gDeferredTerrainWaterProgram : &gDeferredTerrainProgram; @@ -223,14 +223,14 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass) void LLDrawPoolTerrain::endDeferredPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); LLFacePool::endRenderPass(pass); sShader->unbind(); } void LLDrawPoolTerrain::renderDeferred(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_TERRAIN); if (mDrawFace.empty()) { return; @@ -250,7 +250,7 @@ void LLDrawPoolTerrain::renderDeferred(S32 pass) void LLDrawPoolTerrain::beginShadowPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); LLFacePool::beginRenderPass(pass); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gDeferredShadowProgram.bind(); @@ -261,14 +261,14 @@ void LLDrawPoolTerrain::beginShadowPass(S32 pass) void LLDrawPoolTerrain::endShadowPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); LLFacePool::endRenderPass(pass); gDeferredShadowProgram.unbind(); } void LLDrawPoolTerrain::renderShadow(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_TERRAIN); if (mDrawFace.empty()) { return; @@ -343,8 +343,6 @@ void LLDrawPoolTerrain::renderFullShader() LLSettingsWater::ptr_t pwater = LLEnvironment::instance().getCurrentWater(); - ((LLSettingsVOWater*)pwater.get())->updateShader(shader); - // // detail texture 1 // @@ -469,8 +467,6 @@ void LLDrawPoolTerrain::renderFull4TU() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); - // // Stage 1: Generate alpha ramp for detail0/detail1 transition // @@ -479,10 +475,6 @@ void LLDrawPoolTerrain::renderFull4TU() gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(1)->activate(); - // Care about alpha only - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); - // // Stage 2: Interpolate detail1 with existing based on ramp // @@ -497,8 +489,6 @@ void LLDrawPoolTerrain::renderFull4TU() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - gGL.getTexUnit(2)->setTextureColorBlend(LLTexUnit::TBO_LERP_PREV_ALPHA, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_TEX_COLOR); - // // Stage 3: Modulate with primary (vertex) color for lighting // @@ -506,9 +496,6 @@ void LLDrawPoolTerrain::renderFull4TU() gGL.getTexUnit(3)->enable(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(3)->activate(); - // Set alpha texture and do lighting modulation - gGL.getTexUnit(3)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_VERT_COLOR); - gGL.getTexUnit(0)->activate(); // GL_BLEND disabled by default @@ -529,8 +516,6 @@ void LLDrawPoolTerrain::renderFull4TU() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); - // // Stage 1: Generate alpha ramp for detail2/detail3 transition // @@ -543,10 +528,6 @@ void LLDrawPoolTerrain::renderFull4TU() gGL.loadIdentity(); gGL.translatef(-2.f, 0.f, 0.f); - // Care about alpha only - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); - // // Stage 2: Interpolate detail2 with existing based on ramp // @@ -561,8 +542,6 @@ void LLDrawPoolTerrain::renderFull4TU() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - gGL.getTexUnit(2)->setTextureColorBlend(LLTexUnit::TBO_LERP_PREV_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); - // // Stage 3: Generate alpha ramp for detail1/detail2 transition // @@ -576,10 +555,6 @@ void LLDrawPoolTerrain::renderFull4TU() gGL.translatef(-1.f, 0.f, 0.f); gGL.matrixMode(LLRender::MM_MODELVIEW); - // Set alpha texture and do lighting modulation - gGL.getTexUnit(3)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_PREV_COLOR, LLTexUnit::TBS_VERT_COLOR); - gGL.getTexUnit(3)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); - gGL.getTexUnit(0)->activate(); { LLGLEnable blend(GL_BLEND); @@ -629,8 +604,6 @@ void LLDrawPoolTerrain::renderFull4TU() gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); gGL.matrixMode(LLRender::MM_MODELVIEW); - - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } void LLDrawPoolTerrain::renderFull2TU() @@ -669,8 +642,6 @@ void LLDrawPoolTerrain::renderFull2TU() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR); - drawLoop(); //---------------------------------------------------------------------------- @@ -684,11 +655,6 @@ void LLDrawPoolTerrain::renderFull2TU() glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); - // Care about alpha only - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); - - // // Stage 1: Write detail1 // @@ -703,9 +669,6 @@ void LLDrawPoolTerrain::renderFull2TU() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR); - gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA); - gGL.getTexUnit(0)->activate(); { LLGLEnable blend(GL_BLEND); @@ -725,10 +688,6 @@ void LLDrawPoolTerrain::renderFull2TU() gGL.translatef(-1.f, 0.f, 0.f); gGL.matrixMode(LLRender::MM_MODELVIEW); - // Care about alpha only - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); - // // Stage 1: Write detail2 // @@ -743,9 +702,6 @@ void LLDrawPoolTerrain::renderFull2TU() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR); - gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA); - { LLGLEnable blend(GL_BLEND); drawLoop(); @@ -765,10 +721,6 @@ void LLDrawPoolTerrain::renderFull2TU() gGL.translatef(-2.f, 0.f, 0.f); gGL.matrixMode(LLRender::MM_MODELVIEW); - // Care about alpha only - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_ALPHA); - // Stage 1: Write detail3 gGL.getTexUnit(1)->bind(detail_texture3p); gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE); @@ -781,9 +733,6 @@ void LLDrawPoolTerrain::renderFull2TU() glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR); - gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA); - gGL.getTexUnit(0)->activate(); { LLGLEnable blend(GL_BLEND); @@ -816,7 +765,6 @@ void LLDrawPoolTerrain::renderFull2TU() gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } @@ -839,22 +787,8 @@ void LLDrawPoolTerrain::renderSimple() tp0.setVec(tscale, 0.f, 0.0f, -1.f*(origin_agent.mV[0]/256.f)); tp1.setVec(0.f, tscale, 0.0f, -1.f*(origin_agent.mV[1]/256.f)); - if (LLGLSLShader::sNoFixedFunction) - { - sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV); - sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV); - } - else - { - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR); - glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0.mV); - glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1.mV); - } - - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR); + sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_S, 1, tp0.mV); + sShader->uniform4fv(LLShaderMgr::OBJECT_PLANE_T, 1, tp1.mV); drawLoop(); @@ -863,15 +797,9 @@ void LLDrawPoolTerrain::renderSimple() gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - } gGL.matrixMode(LLRender::MM_TEXTURE); gGL.loadIdentity(); gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } //============================================================================ @@ -922,6 +850,7 @@ void LLDrawPoolTerrain::renderOwnership() void LLDrawPoolTerrain::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(mTexturep) ; if (tex && textures.find(tex) != textures.end()) { diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index 0d5195bdbf..facfb235c9 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -42,7 +42,6 @@ S32 LLDrawPoolTree::sDiffTex = 0; static LLGLSLShader* shader = NULL; -static LLTrace::BlockTimerStatHandle FTM_SHADOW_TREE("Tree Shadow"); LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) : LLFacePool(POOL_TREE), @@ -69,7 +68,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass) shader = &gTreeProgram; } - if (gPipeline.canUseVertexShaders()) + if (gPipeline.shadersLoaded()) { shader->bind(); shader->setMinimumAlpha(0.5f); @@ -78,23 +77,24 @@ void LLDrawPoolTree::beginRenderPass(S32 pass) else { gPipeline.enableLightsDynamic(); - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); + gGL.flush(); } } void LLDrawPoolTree::render(S32 pass) { - LL_RECORD_BLOCK_TIME(LLPipeline::sShadowRender ? FTM_SHADOW_TREE : FTM_RENDER_TREES); + LL_PROFILE_ZONE_SCOPED; if (mDrawFace.empty()) { return; } - LLGLState test(GL_ALPHA_TEST, LLGLSLShader::sNoFixedFunction ? 0 : 1); + LLGLState test(GL_ALPHA_TEST, 0); + + gGL.getTexUnit(sDiffTex)->bindFast(mTexturep); + gPipeline.touchTexture(mTexturep, 1024.f * 1024.f); // <=== keep Linden tree textures at full res - gGL.getTexUnit(sDiffTex)->bind(mTexturep); - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { @@ -117,9 +117,8 @@ void LLDrawPoolTree::render(S32 pass) gPipeline.mMatrixOpCount++; } - buff->setBuffer(LLDrawPoolTree::VERTEX_DATA_MASK); - buff->drawRange(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); - gPipeline.addTrianglesDrawn(buff->getNumIndices()); + buff->setBufferFast(LLDrawPoolTree::VERTEX_DATA_MASK); + buff->drawRangeFast(LLRender::TRIANGLES, 0, buff->getNumVerts()-1, buff->getNumIndices(), 0); } } } @@ -135,7 +134,7 @@ void LLDrawPoolTree::endRenderPass(S32 pass) if (mShaderLevel <= 0) { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.flush(); } } @@ -153,6 +152,7 @@ void LLDrawPoolTree::beginDeferredPass(S32 pass) void LLDrawPoolTree::renderDeferred(S32 pass) { + LL_PROFILE_ZONE_SCOPED; render(pass); } @@ -168,7 +168,7 @@ void LLDrawPoolTree::endDeferredPass(S32 pass) //============================================ void LLDrawPoolTree::beginShadowPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_TREE); + LL_PROFILE_ZONE_SCOPED; glPolygonOffset(gSavedSettings.getF32("RenderDeferredTreeShadowOffset"), gSavedSettings.getF32("RenderDeferredTreeShadowBias")); @@ -187,7 +187,7 @@ void LLDrawPoolTree::renderShadow(S32 pass) void LLDrawPoolTree::endShadowPass(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_TREE); + LL_PROFILE_ZONE_SCOPED; glPolygonOffset(gSavedSettings.getF32("RenderDeferredSpotShadowOffset"), gSavedSettings.getF32("RenderDeferredSpotShadowBias")); diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 3d1a292ba2..a84f62036e 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -50,8 +50,6 @@ #include "llsettingssky.h" #include "llsettingswater.h" -static float sTime; - BOOL deferred_render = FALSE; BOOL LLDrawPoolWater::sSkipScreenCopy = FALSE; @@ -136,9 +134,17 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass) //=============================== void LLDrawPoolWater::renderDeferred(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER); + + if (!LLPipeline::sRenderTransparentWater) + { + // Will render opaque water without use of ALM + render(pass); + return; + } + deferred_render = TRUE; - shade(); + renderWater(); deferred_render = FALSE; } @@ -146,7 +152,7 @@ void LLDrawPoolWater::renderDeferred(S32 pass) void LLDrawPoolWater::render(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WATER); if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1) { return; @@ -174,7 +180,7 @@ void LLDrawPoolWater::render(S32 pass) if ((mShaderLevel > 0) && !sSkipScreenCopy) { - shade(); + renderWater(); return; } @@ -233,9 +239,6 @@ void LLDrawPoolWater::render(S32 pass) glTexGenfv(GL_S, GL_OBJECT_PLANE, tp0); glTexGenfv(GL_T, GL_OBJECT_PLANE, tp1); - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); - gGL.getTexUnit(1)->setTextureAlphaBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_ALPHA); - gGL.getTexUnit(0)->activate(); glClearStencil(1); @@ -293,8 +296,6 @@ void LLDrawPoolWater::render(S32 pass) gGL.matrixMode(LLRender::MM_MODELVIEW); LLOverrideFaceColor overrid(this, 1.f, 1.f, 1.f, 0.5f*up_dot); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) { @@ -311,8 +312,6 @@ void LLDrawPoolWater::render(S32 pass) } } - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - gSky.mVOSkyp->getCubeMap()->disable(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -330,30 +329,31 @@ void LLDrawPoolWater::render(S32 pass) glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF); renderReflection(refl_face); } - - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } // for low end hardware void LLDrawPoolWater::renderOpaqueLegacyWater() { - LLVOSky *voskyp = gSky.mVOSkyp; + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLVOSky *voskyp = gSky.mVOSkyp; + + if (voskyp == NULL) + { + return; + } LLGLSLShader* shader = NULL; - if (LLGLSLShader::sNoFixedFunction) + if (LLPipeline::sUnderWaterRender) { - if (LLPipeline::sUnderWaterRender) - { - shader = &gObjectSimpleNonIndexedTexGenWaterProgram; - } - else - { - shader = &gObjectSimpleNonIndexedTexGenProgram; - } - - shader->bind(); + shader = &gObjectSimpleNonIndexedTexGenWaterProgram; + } + else + { + shader = &gObjectSimpleNonIndexedTexGenProgram; } + shader->bind(); + stop_glerror(); // Depth sorting and write to depth buffer @@ -438,12 +438,12 @@ void LLDrawPoolWater::renderOpaqueLegacyWater() } gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); } void LLDrawPoolWater::renderReflection(LLFace* face) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLVOSky *voskyp = gSky.mVOSkyp; if (!voskyp) @@ -470,320 +470,236 @@ void LLDrawPoolWater::renderReflection(LLFace* face) face->renderIndexed(); } -void LLDrawPoolWater::shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp) +void LLDrawPoolWater::renderWater() { - F32 water_height = LLEnvironment::instance().getWaterHeight(); - F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2]; - F32 eyedepth = camera_height - water_height; - bool underwater = eyedepth <= 0.0f; - - LLEnvironment& environment = LLEnvironment::instance(); - LLSettingsWater::ptr_t pwater = environment.getCurrentWater(); - LLSettingsSky::ptr_t psky = environment.getCurrentSky(); - - shader->bind(); - -// bind textures for water rendering - if (deferred_render) - { - if (shader->getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0) - { - glh::matrix4f norm_mat = get_current_modelview().inverse().transpose(); - shader->uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m); - } - } - - LLColor4 specular(psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor()); - shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV); - - sTime = (F32)LLFrameTimer::getElapsedSeconds() * 0.5f; - - S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX); - - if (reftex > -1) - { - gGL.getTexUnit(reftex)->activate(); - gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef); - gGL.getTexUnit(0)->activate(); - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + if (!deferred_render) + { + gGL.setColorMask(true, true); + } - //bind normal map - S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP); - S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2); + LLGLDisable blend(GL_BLEND); - LLViewerTexture* tex_a = mWaterNormp[0]; - LLViewerTexture* tex_b = mWaterNormp[1]; + LLColor3 light_diffuse(0, 0, 0); + F32 light_exp = 0.0f; - F32 blend_factor = LLEnvironment::instance().getCurrentWater()->getBlendFactor(); - - gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); + LLEnvironment & environment = LLEnvironment::instance(); + LLSettingsWater::ptr_t pwater = environment.getCurrentWater(); + LLSettingsSky::ptr_t psky = environment.getCurrentSky(); + LLVector3 light_dir = environment.getLightDirection(); + bool sun_up = environment.getIsSunUp(); + bool moon_up = environment.getIsMoonUp(); + bool has_normal_mips = gSavedSettings.getBOOL("RenderWaterMipNormal"); + bool underwater = LLViewerCamera::getInstance()->cameraUnderWater(); - if (tex_a && (!tex_b || (tex_a == tex_b))) + if (sun_up) { - gGL.getTexUnit(bumpTex)->bind(tex_a); - blend_factor = 0; // only one tex provided, no blending + light_diffuse += psky->getSunlightColor(); } - else if (tex_b && !tex_a) + // moonlight is several orders of magnitude less bright than sunlight, + // so only use this color when the moon alone is showing + else if (moon_up) { - gGL.getTexUnit(bumpTex)->bind(tex_b); - blend_factor = 0; // only one tex provided, no blending + light_diffuse += psky->getMoonlightColor(); } - else if (tex_b != tex_a) + + // Apply magic numbers translating light direction into intensities + light_dir.normalize(); + F32 ground_proj_sq = light_dir.mV[0] * light_dir.mV[0] + light_dir.mV[1] * light_dir.mV[1]; + light_exp = llmax(32.f, 256.f * powf(ground_proj_sq, 16.0f)); + if (0.f < light_diffuse.normalize()) // Normalizing a color? Puzzling... { - gGL.getTexUnit(bumpTex)->bind(tex_a); - gGL.getTexUnit(bumpTex2)->bind(tex_b); + light_diffuse *= (1.5f + (6.f * ground_proj_sq)); } - - // bind reflection texture from RenderTarget - S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); - F32 screenRes[] = - { - 1.f/gGLViewport[2], - 1.f/gGLViewport[3] - }; - - S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP); - stop_glerror(); -// set uniforms for water rendering - shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes); - shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + // set up normal maps filtering + for (auto norm_map : mWaterNormp) + { + if (norm_map) norm_map->setFilteringOption(has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT); + } - LLColor4 fog_color(pwater->getWaterFogColor(), 0.0f); - F32 fog_density = pwater->getModifiedWaterFogDensity(underwater); + LLColor4 specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor()); + F32 phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f; + LLGLSLShader *shader = nullptr; - if (screentex > -1) - { - shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density); - gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis); - } - - if (mShaderLevel == 1) + // two passes, first with standard water shader bound, second with edge water shader bound + for( int edge = 0 ; edge < 2; edge++ ) { - //F32 fog_density_slider_value = param_mgr->mDensitySliderValue; - //sWaterFogColor.mV[3] = fog_density_slider_value; - fog_color.mV[VW] = log(fog_density) / log(2); - } - - shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV); + // select shader + if (underwater && LLPipeline::sWaterReflections) + { + shader = deferred_render ? &gDeferredUnderWaterProgram : &gUnderWaterProgram; + } + else + { + if (edge && !deferred_render) + { + shader = &gWaterEdgeProgram; + } + else + { + shader = deferred_render ? &gDeferredWaterProgram : &gWaterProgram; + } + } + shader->bind(); - //shader->uniformMatrix4fv("inverse_ref", 1, GL_FALSE, (GLfloat*) gGLObliqueProjectionInverse.mMatrix); - shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, eyedepth); - shader->uniform1f(LLShaderMgr::WATER_TIME, sTime); - shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV); - shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV); - shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp); - shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV); - shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV); - shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV); + // bind textures for water rendering + S32 reftex = shader->enableTexture(LLShaderMgr::WATER_REFTEX); + if (reftex > -1) + { + gGL.getTexUnit(reftex)->activate(); + gGL.getTexUnit(reftex)->bind(&gPipeline.mWaterRef); + gGL.getTexUnit(0)->activate(); + } - shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV); - shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale()); - shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset()); - shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier()); + // bind normal map + S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP); + S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2); - F32 sunAngle = llmax(0.f, light_dir.mV[1]); - F32 scaledAngle = 1.f - sunAngle; + LLViewerTexture *tex_a = mWaterNormp[0]; + LLViewerTexture *tex_b = mWaterNormp[1]; - shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle); - shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle); - shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f*sunAngle); - shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0); + F32 blend_factor = pwater->getBlendFactor(); - LLVector4 rotated_light_direction = LLEnvironment::instance().getRotatedLightNorm(); - shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV); - shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); + gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); - if (LLViewerCamera::getInstance()->cameraUnderWater()) - { - shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow()); - } - else - { - shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove()); - } - - { - LLGLDisable cullface(GL_CULL_FACE); - - if (edge) + if (tex_a && (!tex_b || (tex_a == tex_b))) { - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) - { - LLFace *face = *iter; - if (face) - { - LLVOWater* water = (LLVOWater*) face->getViewerObject(); - gGL.getTexUnit(diffTex)->bind(face->getTexture()); - - if (water) - { - bool edge_patch = water->getIsEdgePatch(); - if (edge_patch) - { - //sNeedsReflectionUpdate = TRUE; - face->renderIndexed(); - } - } - } - } + gGL.getTexUnit(bumpTex)->bind(tex_a); + blend_factor = 0; // only one tex provided, no blending } - else + else if (tex_b && !tex_a) { - for (std::vector<LLFace*>::iterator iter = mDrawFace.begin(); iter != mDrawFace.end(); iter++) - { - LLFace *face = *iter; - if (face) - { - LLVOWater* water = (LLVOWater*) face->getViewerObject(); - gGL.getTexUnit(diffTex)->bind(face->getTexture()); - - if (water) - { - bool edge_patch = water->getIsEdgePatch(); - if (!edge_patch) - { - sNeedsReflectionUpdate = TRUE; - sNeedsDistortionUpdate = TRUE; - face->renderIndexed(); - } - } - } - } + gGL.getTexUnit(bumpTex)->bind(tex_b); + blend_factor = 0; // only one tex provided, no blending + } + else if (tex_b != tex_a) + { + gGL.getTexUnit(bumpTex)->bind(tex_a); + gGL.getTexUnit(bumpTex2)->bind(tex_b); } - } - - gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); - shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - shader->disableTexture(LLShaderMgr::WATER_SCREENTEX); - shader->disableTexture(LLShaderMgr::BUMP_MAP); - shader->disableTexture(LLShaderMgr::DIFFUSE_MAP); - shader->disableTexture(LLShaderMgr::WATER_REFTEX); - shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH); + // bind reflection texture from RenderTarget + S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); + F32 screenRes[] = {1.f / gGLViewport[2], 1.f / gGLViewport[3]}; - shader->unbind(); -} + S32 diffTex = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP); -void LLDrawPoolWater::shade() -{ - if (!deferred_render) - { - gGL.setColorMask(true, true); - } + // set uniforms for shader + if (deferred_render) + { + if (shader->getUniformLocation(LLShaderMgr::DEFERRED_NORM_MATRIX) >= 0) + { + glh::matrix4f norm_mat = get_current_modelview().inverse().transpose(); + shader->uniformMatrix4fv(LLShaderMgr::DEFERRED_NORM_MATRIX, 1, FALSE, norm_mat.m); + } + } - LLVOSky *voskyp = gSky.mVOSkyp; + shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes); + shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); - if(voskyp == NULL) - { - return; - } + LLColor4 fog_color(pwater->getWaterFogColor(), 0.0f); + F32 fog_density = pwater->getModifiedWaterFogDensity(underwater); - LLGLDisable blend(GL_BLEND); + if (screentex > -1) + { + shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density); + gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis); + } - LLColor3 light_diffuse(0,0,0); - F32 light_exp = 0.0f; - LLVector3 light_dir; + if (mShaderLevel == 1) + { + fog_color.mV[VW] = log(fog_density) / log(2); + } - LLEnvironment& environment = LLEnvironment::instance(); - LLSettingsWater::ptr_t pwater = environment.getCurrentWater(); - LLSettingsSky::ptr_t psky = environment.getCurrentSky(); + F32 water_height = environment.getWaterHeight(); + F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2]; + shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height); + shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time); + shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV); - light_dir = environment.getLightDirection(); - light_dir.normalize(); + shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV); + shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV); - bool sun_up = environment.getIsSunUp(); - bool moon_up = environment.getIsMoonUp(); + shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV); + shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp); - if (sun_up) - { - light_diffuse += voskyp->getSun().getColorCached(); - } - // moonlight is several orders of magnitude less bright than sunlight, - // so only use this color when the moon alone is showing - else if (moon_up) - { - light_diffuse += psky->getMoonDiffuse(); - } + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV); + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV); - light_exp = light_dir * LLVector3(light_dir.mV[0], light_dir.mV[1], 0.f); + shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV); - light_diffuse.normalize(); - light_diffuse *= (light_exp + 0.25f); + shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale()); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset()); + shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier()); - light_exp *= light_exp; - light_exp *= light_exp; - light_exp *= light_exp; - light_exp *= light_exp; - light_exp *= 256.f; - light_exp = light_exp > 32.f ? light_exp : 32.f; + F32 sunAngle = llmax(0.f, light_dir.mV[1]); + F32 scaledAngle = 1.f - sunAngle; - light_diffuse *= 6.f; + shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0); + shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle); + shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle); + shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f * sunAngle); + shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0); - LLGLSLShader* shader = nullptr; - LLGLSLShader* edge_shader = nullptr; + LLVector4 rotated_light_direction = LLEnvironment::instance().getRotatedLightNorm(); + shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV); + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); - F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - LLEnvironment::instance().getWaterHeight(); - - if (eyedepth < 0.f && LLPipeline::sWaterReflections) - { - if (deferred_render) - { - shader = &gDeferredUnderWaterProgram; - } - else + if (LLViewerCamera::getInstance()->cameraUnderWater()) { - shader = &gUnderWaterProgram; + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow()); + } + else + { + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove()); } - } - else if (deferred_render) - { - shader = &gDeferredWaterProgram; - edge_shader = nullptr; - } - else - { - shader = &gWaterProgram; - edge_shader = &gWaterEdgeProgram; - } - if (mWaterNormp[0]) - { - if (gSavedSettings.getBOOL("RenderWaterMipNormal")) - { - mWaterNormp[0]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); - } - else - { - mWaterNormp[0]->setFilteringOption(LLTexUnit::TFO_POINT); - } - } + LLGLDisable cullface(GL_CULL_FACE); - if (mWaterNormp[1]) - { - if (gSavedSettings.getBOOL("RenderWaterMipNormal")) - { - mWaterNormp[1]->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); - } - else - { - mWaterNormp[1]->setFilteringOption(LLTexUnit::TFO_POINT); - } - } + LLVOWater *water = nullptr; + for (LLFace *const &face : mDrawFace) + { + if (!face) continue; + water = static_cast<LLVOWater *>(face->getViewerObject()); + if (!water) continue; - shade2(false, shader, light_diffuse, light_dir, light_exp); - shade2(true, edge_shader ? edge_shader : shader, light_diffuse, light_dir, light_exp); + gGL.getTexUnit(diffTex)->bind(face->getTexture()); - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - if (!deferred_render) - { - gGL.setColorMask(true, false); - } + if ((bool)edge == (bool) water->getIsEdgePatch()) + { + face->renderIndexed(); + // Note non-void water being drawn, updates required + if (!edge) // SL-16461 remove !LLPipeline::sUseOcclusion check + { + sNeedsReflectionUpdate = TRUE; + sNeedsDistortionUpdate = TRUE; + } + } + } + + shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); + shader->disableTexture(LLShaderMgr::WATER_SCREENTEX); + shader->disableTexture(LLShaderMgr::BUMP_MAP); + shader->disableTexture(LLShaderMgr::DIFFUSE_MAP); + shader->disableTexture(LLShaderMgr::WATER_REFTEX); + shader->disableTexture(LLShaderMgr::WATER_SCREENDEPTH); + + // clean up + shader->unbind(); + gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); + } + + gGL.getTexUnit(0)->activate(); + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + if (!deferred_render) + { + gGL.setColorMask(true, false); + } } LLViewerTexture *LLDrawPoolWater::getDebugTexture() diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index a5d163e0d7..6f2fc3271d 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -78,8 +78,7 @@ public: /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display void renderReflection(LLFace* face); - void shade(); - void shade2(bool edge, LLGLSLShader* shader, const LLColor3& light_diffuse, const LLVector3& light_dir, F32 light_exp); + void renderWater(); void setTransparentTextures(const LLUUID& transparentTextureId, const LLUUID& nextTransparentTextureId); void setOpaqueTexture(const LLUUID& opaqueTextureId); diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index 0c3d8f3098..9873846669 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -182,8 +182,6 @@ void LLDrawPoolWLSky::renderSkyHazeDeferred(const LLVector3& camPosLocal, F32 ca sky_shader->bindTexture(LLShaderMgr::RAINBOW_MAP, rainbow_tex); sky_shader->bindTexture(LLShaderMgr::HALO_MAP, halo_tex); - ((LLSettingsVOSky*)psky.get())->updateShader(sky_shader); - F32 moisture_level = (float)psky->getSkyMoistureLevel(); F32 droplet_radius = (float)psky->getSkyDropletRadius(); F32 ice_level = (float)psky->getSkyIceLevel(); @@ -268,33 +266,14 @@ void LLDrawPoolWLSky::renderStars(const LLVector3& camPosLocal) const gGL.pushMatrix(); gGL.translatef(camPosLocal.mV[0], camPosLocal.mV[1], camPosLocal.mV[2]); gGL.rotatef(gFrameTimeSeconds*0.01f, 0.f, 0.f, 1.f); - if (LLGLSLShader::sNoFixedFunction) - { - gCustomAlphaProgram.bind(); - gCustomAlphaProgram.uniform1f(sCustomAlpha, star_alpha.mV[3]); - } - else - { - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_VERT_COLOR); - gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT_X2, LLTexUnit::TBS_CONST_ALPHA, LLTexUnit::TBS_TEX_ALPHA); - glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, star_alpha.mV); - } + gCustomAlphaProgram.bind(); + gCustomAlphaProgram.uniform1f(sCustomAlpha, star_alpha.mV[3]); gSky.mVOWLSkyp->drawStars(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.popMatrix(); - - if (LLGLSLShader::sNoFixedFunction) - { - gCustomAlphaProgram.unbind(); - } - else - { - // and disable the combiner states - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } + gCustomAlphaProgram.unbind(); } void LLDrawPoolWLSky::renderStarsDeferred(const LLVector3& camPosLocal) const @@ -406,8 +385,6 @@ void LLDrawPoolWLSky::renderSkyCloudsDeferred(const LLVector3& camPosLocal, F32 cloudshader->uniform1f(LLShaderMgr::CLOUD_VARIANCE, cloud_variance); cloudshader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, psky->getSunMoonGlowFactor()); - ((LLSettingsVOSky*)psky.get())->updateShader(cloudshader); - /// Render the skydome renderDome(camPosLocal, camHeightLocal, cloudshader); @@ -462,8 +439,6 @@ void LLDrawPoolWLSky::renderSkyClouds(const LLVector3& camPosLocal, F32 camHeigh cloudshader->uniform1f(LLShaderMgr::CLOUD_VARIANCE, cloud_variance); cloudshader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, psky->getSunMoonGlowFactor()); - ((LLSettingsVOSky*)psky.get())->updateShader(cloudshader); - /// Render the skydome renderDome(camPosLocal, camHeightLocal, cloudshader); @@ -485,7 +460,7 @@ void LLDrawPoolWLSky::renderHeavenlyBodies() LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN]; F32 blend_factor = LLEnvironment::instance().getCurrentSky()->getBlendFactor(); - bool can_use_vertex_shaders = gPipeline.canUseVertexShaders(); + bool can_use_vertex_shaders = gPipeline.shadersLoaded(); bool can_use_windlight_shaders = gPipeline.canUseWindLightShaders(); @@ -591,11 +566,11 @@ void LLDrawPoolWLSky::renderHeavenlyBodies() void LLDrawPoolWLSky::renderDeferred(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY); if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) { return; } - LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY); const F32 camHeightLocal = LLEnvironment::instance().getCamHeight(); @@ -615,11 +590,11 @@ void LLDrawPoolWLSky::renderDeferred(S32 pass) void LLDrawPoolWLSky::render(S32 pass) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY); if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY)) { return; } - LL_RECORD_BLOCK_TIME(FTM_RENDER_WL_SKY); const F32 camHeightLocal = LLEnvironment::instance().getCamHeight(); LLVector3 const & origin = LLViewerCamera::getInstance()->getOrigin(); diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 8b8273d183..63e7887d81 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -119,10 +119,13 @@ BOOL LLViewerDynamicTexture::render() void LLViewerDynamicTexture::preRender(BOOL clear_depth) { gPipeline.allocatePhysicsBuffer(); - llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth())); - llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight())); + if (!gNonInteractive) + { + llassert(mFullWidth <= static_cast<S32>(gPipeline.mPhysicsDisplay.getWidth())); + llassert(mFullHeight <= static_cast<S32>(gPipeline.mPhysicsDisplay.getHeight())); + } - if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsATI) + if (gGLManager.mHasFramebufferObject && gPipeline.mPhysicsDisplay.isComplete() && !gGLManager.mIsAMD) { //using offscreen render target, just use the bottom left corner mOrigin.set(0, 0); } @@ -209,7 +212,7 @@ BOOL LLViewerDynamicTexture::updateAllInstances() return TRUE; } - bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete() && !gGLManager.mIsATI; + bool use_fbo = gGLManager.mHasFramebufferObject && gPipeline.mBake.isComplete() && !gGLManager.mIsAMD; if (use_fbo) { diff --git a/indra/newview/lldynamictexture.h b/indra/newview/lldynamictexture.h index 4bd74a8425..caedf928c3 100644 --- a/indra/newview/lldynamictexture.h +++ b/indra/newview/lldynamictexture.h @@ -35,16 +35,8 @@ class LLViewerDynamicTexture : public LLViewerTexture { + LL_ALIGN_NEW public: - void* operator new(size_t size) - { - return LLTrace::MemTrackable<LLTexture>::aligned_new<16>(size); - } - - void operator delete(void* ptr, size_t size) - { - LLTrace::MemTrackable<LLTexture>::aligned_delete<16>(ptr, size); - } enum { diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index cc2b1cc42c..b76dc6a961 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -105,7 +105,6 @@ namespace //--------------------------------------------------------------------- LLTrace::BlockTimerStatHandle FTM_ENVIRONMENT_UPDATE("Update Environment Tick"); - LLTrace::BlockTimerStatHandle FTM_SHADER_PARAM_UPDATE("Update Shader Parameters"); LLSettingsBase::Seconds DEFAULT_UPDATE_THRESHOLD(10.0); const LLSettingsBase::Seconds MINIMUM_SPANLENGTH(0.01f); @@ -612,6 +611,7 @@ namespace specialSet.insert(SETTING_CLOUD_TEXTUREID); specialSet.insert(SETTING_MOON_TEXTUREID); specialSet.insert(SETTING_SUN_TEXTUREID); + specialSet.insert(SETTING_CLOUD_SHADOW); // due to being part of skips } return specialSet; } @@ -652,6 +652,7 @@ namespace template<> void LLSettingsInjected<LLSettingsVOSky>::updateSpecial(const typename LLSettingsInjected<LLSettingsVOSky>::Injection::ptr_t &injection, typename LLSettingsBase::BlendFactor mix) { + bool is_texture = true; if (injection->mKeyName == SETTING_SUN_TEXTUREID) { mNextSunTextureId = injection->mValue.asUUID(); @@ -676,9 +677,29 @@ namespace { mNextHaloTextureId = injection->mValue.asUUID(); } + else if (injection->mKeyName == LLSettingsSky::SETTING_CLOUD_SHADOW) + { + // Special case due to being texture dependent and part of skips + is_texture = false; + if (!injection->mBlendIn) + mix = 1.0 - mix; + stringset_t dummy; + LLUUID cloud_noise_id = getCloudNoiseTextureId(); + F64 value = this->mSettings[injection->mKeyName].asReal(); + if (this->getCloudNoiseTextureId().isNull()) + { + value = 0; // there was no texture so start from zero coverage + } + // Ideally we need to check for texture in injection, but + // in this case user is setting value explicitly, potentially + // with different transitions, don't ignore it + F64 result = lerp(value, injection->mValue.asReal(), mix); + injection->mLastValue = LLSD::Real(result); + this->mSettings[injection->mKeyName] = injection->mLastValue; + } // Unfortunately I don't have a per texture blend factor. We'll just pick the one that is furthest along. - if (getBlendFactor() < mix) + if (is_texture && getBlendFactor() < mix) { setBlendFactor(mix); } @@ -825,7 +846,6 @@ std::string env_selection_to_string(LLEnvironment::EnvSelection_t sel) #undef RTNENUM } - //------------------------------------------------------------------------- LLEnvironment::LLEnvironment(): mCloudScrollDelta(), @@ -879,6 +899,7 @@ void LLEnvironment::cleanupSingleton() LLEnvironment::~LLEnvironment() { + cleanupSingleton(); } bool LLEnvironment::canEdit() const @@ -1134,6 +1155,10 @@ void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, const LLSe mSignalEnvChanged(env, env_version); } +void LLEnvironment::setCurrentEnvironmentSelection(LLEnvironment::EnvSelection_t env) +{ + mCurrentEnvironment->setEnvironmentSelection(env); +} void LLEnvironment::setEnvironment(LLEnvironment::EnvSelection_t env, LLEnvironment::fixedEnvironment_t fixed, S32 env_version) { @@ -1471,6 +1496,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::getSharedEnvironmentInstance() void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance(); if ((mCurrentEnvironment != pinstance) || forced) @@ -1488,6 +1514,8 @@ void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool f { mCurrentEnvironment = pinstance; } + + updateSettingsUniforms(); } } @@ -1594,7 +1622,7 @@ LLVector4 LLEnvironment::getRotatedLightNorm() const //------------------------------------------------------------------------- void LLEnvironment::update(const LLViewerCamera * cam) { - LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; //LL_RECORD_BLOCK_TIME(FTM_ENVIRONMENT_UPDATE); //F32Seconds now(LLDate::now().secondsSinceEpoch()); static LLFrameTimer timer; @@ -1614,6 +1642,8 @@ void LLEnvironment::update(const LLViewerCamera * cam) stop_glerror(); + updateSettingsUniforms(); + // *TODO: potential optimization - this block may only need to be // executed some of the time. For example for water shaders only. { @@ -1648,10 +1678,16 @@ void LLEnvironment::updateCloudScroll() } // static -void LLEnvironment::updateGLVariablesForSettings(LLGLSLShader *shader, const LLSettingsBase::ptr_t &psetting) +void LLEnvironment::updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting) { - LL_RECORD_BLOCK_TIME(FTM_SHADER_PARAM_UPDATE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + for (int i = 0; i < LLGLSLShader::SG_COUNT; ++i) + { + uniforms[i].clear(); + } + + LLShaderUniforms* shader = &uniforms[LLGLSLShader::SG_ANY]; //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; LLSettingsBase::parammapping_t params = psetting->getParameterMap(); for (auto &it: params) @@ -1694,7 +1730,7 @@ void LLEnvironment::updateGLVariablesForSettings(LLGLSLShader *shader, const LLS { LLVector4 vect4(value); //_WARNS("RIDER") << "pushing '" << (*it).first << "' as " << vect4 << LL_ENDL; - shader->uniform4fv(it.second.getShaderKey(), 1, vect4.mV); + shader->uniform4fv(it.second.getShaderKey(), vect4 ); break; } @@ -1707,17 +1743,44 @@ void LLEnvironment::updateGLVariablesForSettings(LLGLSLShader *shader, const LLS default: break; } - stop_glerror(); } //_WARNS("RIDER") << "----------------------------------------------------------------" << LL_ENDL; - psetting->applySpecial(shader); + psetting->applySpecial(uniforms); } -void LLEnvironment::updateShaderUniforms(LLGLSLShader *shader) +void LLEnvironment::updateShaderUniforms(LLGLSLShader* shader) { - updateGLVariablesForSettings(shader, mCurrentEnvironment->getWater()); - updateGLVariablesForSettings(shader, mCurrentEnvironment->getSky()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; + + // apply uniforms that should be applied to all shaders + mSkyUniforms[LLGLSLShader::SG_ANY].apply(shader); + mWaterUniforms[LLGLSLShader::SG_ANY].apply(shader); + + // apply uniforms specific to the given shader's shader group + auto group = shader->mShaderGroup; + mSkyUniforms[group].apply(shader); + mWaterUniforms[group].apply(shader); +} + +void LLEnvironment::updateSettingsUniforms() +{ + if (mCurrentEnvironment->getWater()) + { + updateGLVariablesForSettings(mWaterUniforms, mCurrentEnvironment->getWater()); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to update GL variable for water settings, environment is not properly set" << LL_ENDL; + } + if (mCurrentEnvironment->getSky()) + { + updateGLVariablesForSettings(mSkyUniforms, mCurrentEnvironment->getSky()); + } + else + { + LL_WARNS("ENVIRONMENT") << "Failed to update GL variable for sky settings, environment is not properly set" << LL_ENDL; + } } void LLEnvironment::recordEnvironment(S32 parcel_id, LLEnvironment::EnvironmentInfo::ptr_t envinfo, LLSettingsBase::Seconds transition) @@ -2634,6 +2697,7 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::DayInstance::clone() const bool LLEnvironment::DayInstance::applyTimeDelta(const LLSettingsBase::Seconds& delta) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; ptr_t keeper(shared_from_this()); // makes sure that this does not go away while it is being worked on. bool changed(false); diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h index 7cbf2d25bb..330de2bea8 100644 --- a/indra/newview/llenvironment.h +++ b/indra/newview/llenvironment.h @@ -38,20 +38,21 @@ #include "llatmosphere.h" +#include "llglslshader.h" + #include <boost/signals2.hpp> //------------------------------------------------------------------------- class LLViewerCamera; -class LLGLSLShader; class LLParcel; //------------------------------------------------------------------------- -class LLEnvironment : public LLSingleton<LLEnvironment> +class LLEnvironment : public LLSimpleton<LLEnvironment> { - LLSINGLETON_C11(LLEnvironment); LOG_CLASS(LLEnvironment); - public: + LLEnvironment(); + static const F64Seconds TRANSITION_INSTANT; static const F64Seconds TRANSITION_FAST; static const F64Seconds TRANSITION_DEFAULT; @@ -114,7 +115,7 @@ public: typedef std::array<F32, 4> altitude_list_t; typedef std::vector<F32> altitudes_vect_t; - virtual ~LLEnvironment(); + ~LLEnvironment(); bool canEdit() const; bool isExtendedEnvironmentEnabled() const; @@ -131,9 +132,14 @@ public: void update(const LLViewerCamera * cam); - static void updateGLVariablesForSettings(LLGLSLShader *shader, const LLSettingsBase::ptr_t &psetting); + static void updateGLVariablesForSettings(LLShaderUniforms* uniforms, const LLSettingsBase::ptr_t &psetting); + + // apply current sky settings to given shader void updateShaderUniforms(LLGLSLShader *shader); + // prepare settings to be applied to shaders (call whenever settings are updated) + void updateSettingsUniforms(); + void setSelectedEnvironment(EnvSelection_t env, LLSettingsBase::Seconds transition = TRANSITION_DEFAULT, bool forced = false); EnvSelection_t getSelectedEnvironment() const { return mSelectedEnvironment; } @@ -152,6 +158,8 @@ public: static void logEnvironment(EnvSelection_t env, const LLSettingsBase::ptr_t &settings, S32 env_version = NO_VERSION); + void setCurrentEnvironmentSelection(LLEnvironment::EnvSelection_t env); + LLSettingsDay::ptr_t getEnvironmentDay(EnvSelection_t env); LLSettingsDay::Seconds getEnvironmentDayLength(EnvSelection_t env); @@ -234,6 +242,11 @@ public: void handleEnvironmentPush(LLSD &message); + //cached uniform values from LLSD values + LLShaderUniforms mWaterUniforms[LLGLSLShader::SG_COUNT]; + LLShaderUniforms mSkyUniforms[LLGLSLShader::SG_COUNT]; + // ======================================================================================= + class DayInstance: public std::enable_shared_from_this<DayInstance> { public: @@ -288,6 +301,7 @@ public: LLSettingsDay::ptr_t mDayCycle; LLSettingsSky::ptr_t mSky; LLSettingsWater::ptr_t mWater; + S32 mSkyTrack; bool mInitialized; @@ -325,9 +339,10 @@ public: DayInstance::ptr_t getSelectedEnvironmentInstance(); DayInstance::ptr_t getSharedEnvironmentInstance(); + void initSingleton(); + protected: - virtual void initSingleton() override; - virtual void cleanupSingleton() override; + void cleanupSingleton(); private: diff --git a/indra/newview/llexperiencelog.cpp b/indra/newview/llexperiencelog.cpp index ee5d561927..c441fbc09f 100644 --- a/indra/newview/llexperiencelog.cpp +++ b/indra/newview/llexperiencelog.cpp @@ -149,10 +149,6 @@ std::string LLExperienceLog::getPermissionString( const LLSD& message, const std { buf.str(entry); } - else - { - buf.str(); - } } if(buf.str().empty()) diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index f1b64a5899..d1e2b8b93d 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -56,6 +56,7 @@ #include "llviewertexture.h" #include "llvoavatar.h" #include "llsculptidsize.h" +#include "llmeshrepository.h" #if LL_LINUX // Work-around spurious used before init warning on Vector4a @@ -71,6 +72,7 @@ static LLStaticHashedString sColorIn("color_in"); BOOL LLFace::sSafeRenderSelect = TRUE; // FALSE + #define DOTVEC(a,b) (a.mV[0]*b.mV[0] + a.mV[1]*b.mV[1] + a.mV[2]*b.mV[2]) /* @@ -127,6 +129,7 @@ void planarProjection(LLVector2 &tc, const LLVector4a& normal, void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE; mLastUpdateTime = gFrameTimeSeconds; mLastMoveTime = 0.f; mLastSkinTime = gFrameTimeSeconds; @@ -196,14 +199,7 @@ void LLFace::destroy() if (mDrawPoolp) { - if (this->isState(LLFace::RIGGED) && (mDrawPoolp->getType() == LLDrawPool::POOL_CONTROL_AV || mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR)) - { - ((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this); - } - else - { - mDrawPoolp->removeFace(this); - } + mDrawPoolp->removeFace(this); mDrawPoolp = NULL; } @@ -241,6 +237,8 @@ void LLFace::setPool(LLFacePool* pool) void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE + if (!new_pool) { LL_ERRS() << "Setting pool to null!" << LL_ENDL; @@ -320,6 +318,8 @@ void LLFace::setSpecularMap(LLViewerTexture* tex) void LLFace::dirtyTexture() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE + LLDrawable* drawablep = getDrawable(); if (mVObjp.notNull() && mVObjp->getVolume()) @@ -535,6 +535,8 @@ void LLFace::updateCenterAgent() void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE + if (mDrawablep == NULL || mDrawablep->getSpatialGroup() == NULL) { return; @@ -585,6 +587,7 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) glTexCoordPointer(2, GL_FLOAT, 8, vol_face.mTexCoords); } gGL.syncMatrices(); + LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x00FF00 ); glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } @@ -605,6 +608,8 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) void renderFace(LLDrawable* drawable, LLFace *face) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE + LLVOVolume* vobj = drawable->getVOVolume(); if (vobj) { @@ -648,7 +653,7 @@ void LLFace::renderOneWireframe(const LLColor4 &color, F32 fogCfx, bool wirefram glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV()))); glFogfv(GL_FOG_COLOR, fogCol.mV); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.flush(); { gGL.diffuseColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); renderFace(mDrawablep, this); @@ -891,6 +896,8 @@ bool less_than_max_mag(const LLVector4a& vec) BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f, const LLMatrix4& mat_vert_in, BOOL global_volume) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE + //get bounding box if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED)) { @@ -1165,6 +1172,11 @@ bool LLFace::canRenderAsMask() return true; } + if (isState(LLFace::RIGGED)) + { // never auto alpha-mask rigged faces + return false; + } + const LLTextureEntry* te = getTextureEntry(); if( !te || !getViewerObject() || !getTexture() ) { @@ -1202,12 +1214,10 @@ bool LLFace::canRenderAsMask() } -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_VOLUME("Volume VB Cache"); - //static void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_VOLUME); + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE; U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL; @@ -1269,41 +1279,13 @@ void push_for_transform(LLVertexBuffer* buff, U32 source_count, U32 dest_count) } } -static LLTrace::BlockTimerStatHandle FTM_FACE_GET_GEOM("Face Geom"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_POSITION("Position"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_NORMAL("Normal"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TEXTURE("Texture"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_COLOR("Color"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_EMISSIVE("Emissive"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_WEIGHTS("Weights"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_TANGENT("Binormal"); - -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK("Face Feedback"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_POSITION("Feedback Position"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_NORMAL("Feedback Normal"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_TEXTURE("Feedback Texture"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_COLOR("Feedback Color"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_EMISSIVE("Feedback Emissive"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_FEEDBACK_BINORMAL("Feedback Binormal"); - -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX("Index"); -static LLTrace::BlockTimerStatHandle FTM_FACE_GEOM_INDEX_TAIL("Tail"); -static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_STORE("Pos"); -static LLTrace::BlockTimerStatHandle FTM_FACE_TEXTURE_INDEX_STORE("TexIdx"); -static LLTrace::BlockTimerStatHandle FTM_FACE_POSITION_PAD("Pad"); -static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_DEFAULT("Default"); -static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK("Quick"); -static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_NO_XFORM("No Xform"); -static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_XFORM("Xform"); -static LLTrace::BlockTimerStatHandle FTM_FACE_TEX_QUICK_PLANAR("Quick Planar"); - BOOL LLFace::getGeometryVolume(const LLVolume& volume, const S32 &f, const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in, const U16 &index_offset, bool force_rebuild) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GET_GEOM); + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE; llassert(verify()); if (volume.getNumVolumeFaces() <= f) { @@ -1311,7 +1293,9 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, return FALSE; } - const LLVolumeFace &vf = volume.getVolumeFace(f); + bool rigged = isState(RIGGED); + + const LLVolumeFace &vf = volume.getVolumeFace(f); S32 num_vertices = (S32)vf.mNumVertices; S32 num_indices = (S32) vf.mNumIndices; @@ -1444,7 +1428,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, // INDICES if (full_rebuild) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices"); mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex, mIndicesCount, map_range); volatile __m128i* dst = (__m128i*) indicesp.get(); @@ -1460,7 +1444,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_INDEX_TAIL); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - indices tail"); U16* idx = (U16*) dst; for (S32 i = end*8; i < num_indices; ++i) @@ -1475,9 +1459,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } - LLMatrix4a mat_normal; - mat_normal.loadu(mat_norm_in); - F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0; bool do_xform = false; if (rebuild_tcoord) @@ -1512,6 +1493,45 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } + const LLMeshSkinInfo* skin = nullptr; + LLMatrix4a mat_vert; + LLMatrix4a mat_normal; + + // prepare mat_vert + if (rebuild_pos) + { + if (rigged) + { //override with bind shape matrix if rigged + skin = mSkinInfo; + mat_vert = skin->mBindShapeMatrix; + } + else + { + mat_vert.loadu(mat_vert_in); + } + } + + if (rebuild_normal || rebuild_tangent) + { //override mat_normal with inverse of skin->mBindShapeMatrix + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - norm mat override"); + if (rigged) + { + if (skin == nullptr) + { + skin = mSkinInfo; + } + + //TODO -- cache this (check profile marker above)? + glh::matrix4f m((F32*) skin->mBindShapeMatrix.getF32ptr()); + m = m.inverse().transpose(); + mat_normal.loadu(m.m); + } + else + { + mat_normal.loadu(mat_norm_in); + } + } + static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback", false); #ifdef GL_TRANSFORM_FEEDBACK_BUFFER @@ -1523,7 +1543,8 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, !volume.isUnique()) //source volume is NOT flexi { //use transform feedback to pack vertex buffer //gGLDebugLoggingEnabled = TRUE; - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK); + + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - transform feedback"); LLGLEnable discard(GL_RASTERIZER_DISCARD); LLVertexBuffer* buff = (LLVertexBuffer*) vf.mVertexBuffer.get(); @@ -1541,7 +1562,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_pos) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_POSITION); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf position"); gTransformPositionProgram.bind(); mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_VERTEX, mGeomIndex, mGeomCount); @@ -1566,7 +1587,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_color) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_COLOR); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf color"); gTransformColorProgram.bind(); mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_COLOR, mGeomIndex, mGeomCount); @@ -1582,7 +1603,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_emissive) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_EMISSIVE); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf emissive"); gTransformColorProgram.bind(); mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_EMISSIVE, mGeomIndex, mGeomCount); @@ -1603,7 +1624,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_normal) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_NORMAL); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf normal"); gTransformNormalProgram.bind(); mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_NORMAL, mGeomIndex, mGeomCount); @@ -1616,7 +1637,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tangent) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf tangent"); gTransformTangentProgram.bind(); mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TANGENT, mGeomIndex, mGeomCount); @@ -1629,7 +1650,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tcoord) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_FEEDBACK_TEXTURE); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tf tcoord"); gTransformTexCoordProgram.bind(); mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TEXCOORD0, mGeomIndex, mGeomCount); @@ -1668,7 +1689,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tcoord) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TEXTURE); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tcoord"); //bump setup LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f ); @@ -1764,7 +1785,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, do_xform = false; } - if (getVirtualSize() >= MIN_TEX_ANIM_SIZE || isState(LLFace::RIGGED)) + if (getVirtualSize() >= MIN_TEX_ANIM_SIZE) // || isState(LLFace::RIGGED)) { //don't override texture transform during tc bake tex_mode = 0; } @@ -1791,18 +1812,18 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (texgen != LLTextureEntry::TEX_GEN_PLANAR) { - LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen"); if (!do_tex_mat) { if (!do_xform) { - LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_NO_XFORM); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 1"); S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF; LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size); } else { - LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_XFORM); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("ggv - texgen 2"); F32* dst = (F32*) tex_coords0.get(); LLVector4a* src = (LLVector4a*) vf.mTexCoords; @@ -1842,9 +1863,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, for (S32 i = 0; i < num_vertices; i++) { LLVector2 tc(vf.mTexCoords[i]); - //LLVector4a& norm = vf.mNormals[i]; - //LLVector4a& center = *(vf.mCenter); - + LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f); tmp = tmp * *mTextureMatrix; tc.mV[0] = tmp.mV[0]; @@ -1855,7 +1874,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } else { //no bump, tex gen planar - LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_QUICK_PLANAR); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen planar"); if (do_tex_mat) { for (S32 i = 0; i < num_vertices; i++) @@ -1900,7 +1919,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } else { //bump mapped or has material, just do the whole expensive loop - LL_RECORD_BLOCK_TIME(FTM_FACE_TEX_DEFAULT); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - texgen default"); std::vector<LLVector2> bump_tc; @@ -2058,14 +2077,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a* end = src+num_vertices; //LLVector4a* end_64 = end-4; - //LL_RECORD_TIME_BLOCK(FTM_FACE_GEOM_POSITION); llassert(num_vertices > 0); mVertexBuffer->getVertexStrider(vert, mGeomIndex, mGeomCount, map_range); - LLMatrix4a mat_vert; - mat_vert.loadu(mat_vert_in); - + F32* dst = (F32*) vert.get(); F32* end_f32 = dst+mGeomCount*4; @@ -2095,53 +2111,19 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, LLVector4a tmp; - { - //LL_RECORD_TIME_BLOCK(FTM_FACE_POSITION_STORE); - - /*if (num_vertices > 4) - { //more than 64 bytes - while (src < end_64) - { - _mm_prefetch((char*)src + 64, _MM_HINT_T0); - _mm_prefetch((char*)dst + 64, _MM_HINT_T0); - - mat_vert.affineTransform(*src, res0); - tmp.setSelectWithMask(mask, texIdx, res0); - tmp.store4a((F32*) dst); - - mat_vert.affineTransform(*(src+1), res1); - tmp.setSelectWithMask(mask, texIdx, res1); - tmp.store4a((F32*) dst+4); - - mat_vert.affineTransform(*(src+2), res2); - tmp.setSelectWithMask(mask, texIdx, res2); - tmp.store4a((F32*) dst+8); - - mat_vert.affineTransform(*(src+3), res3); - tmp.setSelectWithMask(mask, texIdx, res3); - tmp.store4a((F32*) dst+12); - - dst += 16; - src += 4; - } - }*/ - - while (src < end) - { - mat_vert.affineTransform(*src++, res0); - tmp.setSelectWithMask(mask, texIdx, res0); - tmp.store4a((F32*) dst); - dst += 4; - } + + while (src < end) + { + mat_vert.affineTransform(*src++, res0); + tmp.setSelectWithMask(mask, texIdx, res0); + tmp.store4a((F32*) dst); + dst += 4; } - + + while (dst < end_f32) { - //LL_RECORD_TIME_BLOCK(FTM_FACE_POSITION_PAD); - while (dst < end_f32) - { - res0.store4a((F32*) dst); - dst += 4; - } + res0.store4a((F32*) dst); + dst += 4; } if (map_range) @@ -2150,10 +2132,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, } } - if (rebuild_normal) { - //LL_RECORD_TIME_BLOCK(FTM_FACE_GEOM_NORMAL); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - normal"); + mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range); F32* normals = (F32*) norm.get(); LLVector4a* src = vf.mNormals; @@ -2175,7 +2157,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_tangent) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_TANGENT); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - tangent"); mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range); F32* tangents = (F32*) tangent.get(); @@ -2208,7 +2190,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_weights && vf.mWeights) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_WEIGHTS); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - weight"); mVertexBuffer->getWeight4Strider(wght, mGeomIndex, mGeomCount, map_range); F32* weights = (F32*) wght.get(); LLVector4a::memcpyNonAliased16(weights, (F32*) vf.mWeights, num_vertices*4*sizeof(F32)); @@ -2220,7 +2202,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_COLOR) ) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_COLOR); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - color"); mVertexBuffer->getColorStrider(colors, mGeomIndex, mGeomCount, map_range); LLVector4a src; @@ -2251,7 +2233,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, if (rebuild_emissive) { - LL_RECORD_BLOCK_TIME(FTM_FACE_GEOM_EMISSIVE); + LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("getGeometryVolume - emissive"); LLStrider<LLColor4U> emissive; mVertexBuffer->getEmissiveStrider(emissive, mGeomIndex, mGeomCount, map_range); @@ -2382,12 +2364,35 @@ F32 LLFace::getTextureVirtualSize() BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE; + //VECTORIZE THIS //get area of circle around face - LLVector4a center; - center.load3(getPositionAgent().mV); - LLVector4a size; - size.setSub(mExtents[1], mExtents[0]); + + LLVector4a center; + LLVector4a size; + + + if (isState(LLFace::RIGGED)) + { + //override with avatar bounding box + LLVOAvatar* avatar = mVObjp->getAvatar(); + if (avatar) + { + center.load3(avatar->getPositionAgent().mV); + const LLVector4a* exts = avatar->mDrawable->getSpatialExtents(); + size.setSub(exts[1], exts[0]); + } + else + { + return false; + } + } + else + { + center.load3(getPositionAgent().mV); + size.setSub(mExtents[1], mExtents[0]); + } size.mul(0.5f); LLViewerCamera* camera = LLViewerCamera::getInstance(); @@ -2661,6 +2666,8 @@ const LLMatrix4& LLFace::getRenderMatrix() const S32 LLFace::renderElements(const U16 *index_array) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE + S32 ret = 0; if (isState(GLOBAL)) @@ -2680,6 +2687,8 @@ S32 LLFace::renderElements(const U16 *index_array) const S32 LLFace::renderIndexed() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE + if(mDrawablep == NULL || mDrawPoolp == NULL) { return 0; @@ -2690,6 +2699,8 @@ S32 LLFace::renderIndexed() S32 LLFace::renderIndexed(U32 mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_FACE + if (mVertexBuffer.isNull()) { return 0; @@ -2767,56 +2778,6 @@ void LLFace::clearVertexBuffer() mVertexBuffer = NULL; } -//static -U32 LLFace::getRiggedDataMask(U32 type) -{ - static const U32 rigged_data_mask[] = { - LLDrawPoolAvatar::RIGGED_MATERIAL_MASK, - LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_VMASK, - LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_MASK_MASK, - LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK, - LLDrawPoolAvatar::RIGGED_SPECMAP_VMASK, - LLDrawPoolAvatar::RIGGED_SPECMAP_BLEND_MASK, - LLDrawPoolAvatar::RIGGED_SPECMAP_MASK_MASK, - LLDrawPoolAvatar::RIGGED_SPECMAP_EMISSIVE_MASK, - LLDrawPoolAvatar::RIGGED_NORMMAP_VMASK, - LLDrawPoolAvatar::RIGGED_NORMMAP_BLEND_MASK, - LLDrawPoolAvatar::RIGGED_NORMMAP_MASK_MASK, - LLDrawPoolAvatar::RIGGED_NORMMAP_EMISSIVE_MASK, - LLDrawPoolAvatar::RIGGED_NORMSPEC_VMASK, - LLDrawPoolAvatar::RIGGED_NORMSPEC_BLEND_MASK, - LLDrawPoolAvatar::RIGGED_NORMSPEC_MASK_MASK, - LLDrawPoolAvatar::RIGGED_NORMSPEC_EMISSIVE_MASK, - LLDrawPoolAvatar::RIGGED_SIMPLE_MASK, - LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK, - LLDrawPoolAvatar::RIGGED_SHINY_MASK, - LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK, - LLDrawPoolAvatar::RIGGED_GLOW_MASK, - LLDrawPoolAvatar::RIGGED_ALPHA_MASK, - LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK, - LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK, - LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK, - }; - - llassert(type < sizeof(rigged_data_mask)/sizeof(U32)); - - return rigged_data_mask[type]; -} - -U32 LLFace::getRiggedVertexBufferDataMask() const -{ - U32 data_mask = 0; - for (U32 i = 0; i < mRiggedIndex.size(); ++i) - { - if (mRiggedIndex[i] > -1) - { - data_mask |= LLFace::getRiggedDataMask(i); - } - } - - return data_mask; -} - S32 LLFace::getRiggedIndex(U32 type) const { if (mRiggedIndex.empty()) @@ -2829,19 +2790,7 @@ S32 LLFace::getRiggedIndex(U32 type) const return mRiggedIndex[type]; } -void LLFace::setRiggedIndex(U32 type, S32 index) +U64 LLFace::getSkinHash() { - if (mRiggedIndex.empty()) - { - mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES); - for (U32 i = 0; i < mRiggedIndex.size(); ++i) - { - mRiggedIndex[i] = -1; - } - } - - llassert(type < mRiggedIndex.size()); - - mRiggedIndex[type] = index; + return mSkinInfo ? mSkinInfo->mHash : 0; } - diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 3611539ff8..aa00c9d052 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -47,18 +47,18 @@ class LLTextureEntry; class LLVertexProgram; class LLViewerTexture; class LLGeometryManager; -class LLTextureAtlasSlot; class LLDrawInfo; +class LLMeshSkinInfo; const F32 MIN_ALPHA_SIZE = 1024.f; const F32 MIN_TEX_ANIM_SIZE = 512.f; const U8 FACE_DO_NOT_BATCH_TEXTURES = 255; -class LLFace : public LLTrace::MemTrackableNonVirtual<LLFace, 16> +class alignas(16) LLFace { + LL_ALIGN_NEW public: LLFace(const LLFace& rhs) - : LLTrace::MemTrackableNonVirtual<LLFace, 16>("LLFace") { *this = rhs; } @@ -85,8 +85,8 @@ public: public: LLFace(LLDrawable* drawablep, LLViewerObject* objp) - : LLTrace::MemTrackableNonVirtual<LLFace, 16>("LLFace") { + LL_PROFILE_ZONE_SCOPED; init(drawablep, objp); } ~LLFace() { destroy(); } @@ -143,7 +143,7 @@ public: LLViewerObject* getViewerObject() const { return mVObjp; } S32 getLOD() const { return mVObjp.notNull() ? mVObjp->getLOD() : 0; } void setPoolType(U32 type) { mPoolType = type; } - S32 getTEOffset() { return mTEOffset; } + S32 getTEOffset() const { return mTEOffset; } LLViewerTexture* getTexture(U32 ch = LLRender::DIFFUSE_MAP) const; void setViewerObject(LLViewerObject* object); @@ -228,15 +228,17 @@ public: void setVertexBuffer(LLVertexBuffer* buffer); void clearVertexBuffer(); //sets mVertexBuffer to NULL LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; } - U32 getRiggedVertexBufferDataMask() const; S32 getRiggedIndex(U32 type) const; - void setRiggedIndex(U32 type, S32 index); - - static U32 getRiggedDataMask(U32 type); void notifyAboutCreatingTexture(LLViewerTexture *texture); void notifyAboutMissingAsset(LLViewerTexture *texture); + // used to preserve draw order of faces that are batched together. + // Allows content creators to manipulate linked sets and face ordering + // for consistent alpha sorting results, particularly for rigged attachments + void setDrawOrderIndex(U32 index) { mDrawOrderIndex = index; } + U32 getDrawOrderIndex() const { return mDrawOrderIndex; } + public: //aligned members LLVector4a mExtents[2]; @@ -261,6 +263,11 @@ public: LLMatrix4* mSpecMapMatrix; LLMatrix4* mNormalMapMatrix; LLDrawInfo* mDrawInfo; + LLVOAvatar* mAvatar = nullptr; + LLMeshSkinInfo* mSkinInfo = nullptr; + + // return mSkinInfo->mHash or 0 if mSkinInfo is null + U64 getSkinHash(); private: LLPointer<LLVertexBuffer> mVertexBuffer; @@ -271,10 +278,10 @@ private: LLColor4 mFaceColor; // overrides material color if state |= USE_FACE_COLOR U16 mGeomCount; // vertex count for this face - U16 mGeomIndex; // index into draw pool + U16 mGeomIndex; // starting index into mVertexBuffer's vertex array U8 mTextureIndex; // index of texture channel to use for pseudo-atlasing U32 mIndicesCount; - U32 mIndicesIndex; // index into draw pool for indices (yeah, I know!) + U32 mIndicesIndex; // index into mVertexBuffer's index array S32 mIndexInTex[LLRender::NUM_TEXTURE_CHANNELS]; LLXformMatrix* mXform; @@ -304,6 +311,7 @@ private: bool mHasMedia ; bool mIsMediaAllowed; + U32 mDrawOrderIndex = 0; // see setDrawOrderIndex protected: static BOOL sSafeRenderSelect; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index 239d162101..1605e4133d 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -716,7 +716,6 @@ void LLFastTimerView::exportCharts(const std::string& base, const std::string& t //====================================== buffer.clear(); - gGL.color3fv(base_col.mV); U32 count = 0; U32 total_count = base_execution.size(); @@ -1019,11 +1018,9 @@ void LLFastTimerView::printLineStats() } } -static LLTrace::BlockTimerStatHandle FTM_DRAW_LINE_GRAPH("Draw line graph"); - void LLFastTimerView::drawLineGraph() { - LL_RECORD_BLOCK_TIME(FTM_DRAW_LINE_GRAPH); + LL_PROFILE_ZONE_SCOPED; //draw line graph history gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLLocalClipRect clip(mGraphRect); @@ -1062,6 +1059,7 @@ void LLFastTimerView::drawLineGraph() F32Seconds cur_max(0); U32 cur_max_calls = 0; + for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME); it != LLTrace::end_block_timer_tree_df(); ++it) @@ -1096,6 +1094,7 @@ void LLFastTimerView::drawLineGraph() F32 call_scale_factor = (F32)mGraphRect.getHeight() / (F32)max_calls; F32 time_scale_factor = (F32)mGraphRect.getHeight() / max_time.value(); F32 hz_scale_factor = (F32) mGraphRect.getHeight() / (1.f / max_time.value()); + for (U32 j = mRecording.getNumRecordedPeriods(); j > 0; j--) @@ -1103,7 +1102,7 @@ void LLFastTimerView::drawLineGraph() LLTrace::Recording& recording = mRecording.getPrevRecording(j); F32Seconds time = llmax(recording.getSum(*idp), F64Seconds(0.000001)); U32 calls = recording.getSum(idp->callCount()); - + if (is_hover_timer) { //normalize to highlighted timer @@ -1450,6 +1449,7 @@ void LLFastTimerView::updateTotalTime() void LLFastTimerView::drawBars() { + LL_PROFILE_ZONE_SCOPED; LLLocalClipRect clip(mBarRect); S32 bar_height = mBarRect.getHeight() / (MAX_VISIBLE_HISTORY + 2); @@ -1527,11 +1527,9 @@ void LLFastTimerView::drawBars() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_TIMER_BAR_WIDTHS("Update timer bar widths"); - F32Seconds LLFastTimerView::updateTimerBarWidths(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 history_index, U32& bar_index) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_TIMER_BAR_WIDTHS); + LL_PROFILE_ZONE_SCOPED; const F32Seconds self_time = history_index == -1 ? mRecording.getPeriodMean(time_block->selfTime(), RUNNING_AVERAGE_WIDTH) : mRecording.getPrevRecording(history_index).getSum(time_block->selfTime()); @@ -1555,11 +1553,9 @@ F32Seconds LLFastTimerView::updateTimerBarWidths(LLTrace::BlockTimerStatHandle* return full_time; } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_TIMER_BAR_FRACTIONS("Update timer bar fractions"); - S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::BlockTimerStatHandle* time_block, TimerBarRow& row, S32 timer_bar_index) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_TIMER_BAR_FRACTIONS); + LL_PROFILE_ZONE_SCOPED; TimerBar& timer_bar = row.mBars[timer_bar_index]; const F32Seconds bar_time = timer_bar.mTotalTime - timer_bar.mSelfTime; @@ -1620,6 +1616,7 @@ S32 LLFastTimerView::updateTimerBarOffsets(LLTrace::BlockTimerStatHandle* time_b S32 LLFastTimerView::drawBar(LLRect bar_rect, TimerBarRow& row, S32 image_width, S32 image_height, bool hovered, bool visible, S32 bar_index) { + LL_PROFILE_ZONE_SCOPED; TimerBar& timer_bar = row.mBars[bar_index]; LLTrace::BlockTimerStatHandle* time_block = timer_bar.mTimeBlock; diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index e6bbe234b3..e934041e2e 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -381,7 +381,10 @@ F32 gpu_benchmark(); F32 logExceptionBenchmark() { - // Todo: make a wrapper/class for SEH exceptions + // FIXME: gpu_benchmark uses many C++ classes on the stack to control state. + // SEH exceptions with our current exception handling options do not call + // destructors for these classes, resulting in an undefined state should + // this handler be invoked. F32 gbps = -1; __try { @@ -389,6 +392,9 @@ F32 logExceptionBenchmark() } __except (msc_exception_filter(GetExceptionCode(), GetExceptionInformation())) { + // HACK - ensure that profiling is disabled + LLGLSLShader::finishProfile(false); + // convert to C++ styled exception char integer_string[32]; sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode()); @@ -520,7 +526,6 @@ void LLFeatureManager::initSingleton() void LLFeatureManager::applyRecommendedSettings() { - loadGPUClass(); // apply saved settings // cap the level at 2 (high) U32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_5)); @@ -607,22 +612,6 @@ void LLFeatureManager::setGraphicsLevel(U32 level, bool skipFeatures) // if we're passed an invalid level, default to "Low" std::string features(isValidGraphicsLevel(level)? getNameForGraphicsLevel(level) : "Low"); - if (features == "Low") - { -#if LL_DARWIN - // This Mac-specific change is to insure that we force 'Basic Shaders' for all Mac - // systems which support them instead of falling back to fixed-function unnecessarily - // MAINT-2157 - if (gGLManager.mGLVersion < 2.1f) -#else - // only use fixed function by default if GL version < 3.0 or this is an intel graphics chip - if (gGLManager.mGLVersion < 3.f || gGLManager.mIsIntel) -#endif - { - // same as Low, but with "Basic Shaders" disabled - features = "LowFixedFunction"; - } - } maskFeatures(features); @@ -670,46 +659,18 @@ void LLFeatureManager::applyBaseMasks() } // now all those wacky ones - if (!gGLManager.mHasFragmentShader) - { - maskFeatures("NoPixelShaders"); - } - if (!gGLManager.mHasVertexShader || !mGPUSupported) - { - maskFeatures("NoVertexShaders"); - } if (gGLManager.mIsNVIDIA) { maskFeatures("NVIDIA"); } - if (gGLManager.mIsGF2or4MX) - { - maskFeatures("GeForce2"); - } - if (gGLManager.mIsATI) - { - maskFeatures("ATI"); - } - if (gGLManager.mHasATIMemInfo && gGLManager.mVRAM < 256) + if (gGLManager.mIsAMD) { - maskFeatures("ATIVramLT256"); - } - if (gGLManager.mATIOldDriver) - { - maskFeatures("ATIOldDriver"); - } - if (gGLManager.mIsGFFX) - { - maskFeatures("GeForceFX"); + maskFeatures("AMD"); } if (gGLManager.mIsIntel) { maskFeatures("Intel"); } - if (gGLManager.mGLVersion < 1.5f) - { - maskFeatures("OpenGLPre15"); - } if (gGLManager.mGLVersion < 3.f) { maskFeatures("OpenGLPre30"); @@ -749,17 +710,6 @@ void LLFeatureManager::applyBaseMasks() //LL_INFOS() << "Masking features from gpu table match: " << gpustr << LL_ENDL; maskFeatures(gpustr); - // now mask cpu type ones - if (gSysMemory.getPhysicalMemoryKB() <= U32Megabytes(256)) - { - maskFeatures("RAM256MB"); - } - - if (gSysCPU.getMHz() < 1100) - { - maskFeatures("CPUSlow"); - } - if (isSafe()) { maskFeatures("safe"); @@ -774,11 +724,9 @@ LLSD LLFeatureManager::getRecommendedSettingsMap() LLSD map(LLSD::emptyMap()); - loadGPUClass(); U32 level = llmax(GPU_CLASS_0, llmin(mGPUClass, GPU_CLASS_5)); LL_INFOS("RenderInit") << "Getting the map of recommended settings for level " << level << LL_ENDL; - applyBaseMasks(); std::string features(isValidGraphicsLevel(level) ? getNameForGraphicsLevel(level) : "Low"); maskFeatures(features); diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index a24d1d1436..4f3c2d8d34 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -47,9 +47,6 @@ static const F32 SEC_PER_FLEXI_FRAME = 1.f / 60.f; // 60 flexi updates per secon /*static*/ F32 LLVolumeImplFlexible::sUpdateFactor = 1.0f; std::vector<LLVolumeImplFlexible*> LLVolumeImplFlexible::sInstanceList; -static LLTrace::BlockTimerStatHandle FTM_FLEXIBLE_REBUILD("Rebuild"); -static LLTrace::BlockTimerStatHandle FTM_DO_FLEXIBLE_UPDATE("Flexible Update"); - // LLFlexibleObjectData::pack/unpack now in llprimitive.cpp //----------------------------------------------- @@ -95,7 +92,7 @@ LLVolumeImplFlexible::~LLVolumeImplFlexible() //static void LLVolumeImplFlexible::updateClass() { - LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE); + LL_PROFILE_ZONE_SCOPED; U64 virtual_frame_num = LLTimer::getElapsedSeconds() / SEC_PER_FLEXI_FRAME; for (std::vector<LLVolumeImplFlexible*>::iterator iter = sInstanceList.begin(); @@ -429,7 +426,7 @@ inline S32 log2(S32 x) void LLVolumeImplFlexible::doFlexibleUpdate() { - LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE); + LL_PROFILE_ZONE_SCOPED; LLVolume* volume = mVO->getVolume(); LLPath *path = &volume->getPath(); if ((mSimulateRes == 0 || !mInitialized) && mVO->mDrawable->isVisible()) @@ -720,13 +717,12 @@ void LLVolumeImplFlexible::doFlexibleUpdate() mLastSegmentRotation = parentSegmentRotation; } -static LLTrace::BlockTimerStatHandle FTM_FLEXI_PREBUILD("Flexi Prebuild"); void LLVolumeImplFlexible::preRebuild() { if (!mUpdated) { - LL_RECORD_BLOCK_TIME(FTM_FLEXI_PREBUILD); + LL_PROFILE_ZONE_SCOPED; doFlexibleRebuild(false); } } @@ -755,6 +751,7 @@ void LLVolumeImplFlexible::onSetScale(const LLVector3& scale, BOOL damped) BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) { + LL_PROFILE_ZONE_SCOPED; LLVOVolume *volume = (LLVOVolume*)mVO; if (mVO->isAttachment()) @@ -792,7 +789,6 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) if (mRenderRes > -1) { - LL_RECORD_BLOCK_TIME(FTM_DO_FLEXIBLE_UPDATE); doFlexibleUpdate(); } @@ -812,7 +808,6 @@ BOOL LLVolumeImplFlexible::doUpdateGeometry(LLDrawable *drawable) volume->mDrawable->setState(LLDrawable::REBUILD_VOLUME); volume->dirtySpatialGroup(); { - LL_RECORD_BLOCK_TIME(FTM_FLEXIBLE_REBUILD); doFlexibleRebuild(volume->mVolumeChanged); } volume->genBBoxes(isVolumeGlobal()); diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp index 687d820a18..a3037ed651 100644 --- a/indra/newview/llfloaterbvhpreview.cpp +++ b/indra/newview/llfloaterbvhpreview.cpp @@ -1087,10 +1087,7 @@ BOOL LLPreviewAnimation::render() gGL.pushMatrix(); gGL.loadIdentity(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); LLGLSUIDefault def; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); diff --git a/indra/newview/llfloaterfixedenvironment.cpp b/indra/newview/llfloaterfixedenvironment.cpp index 4f2c36f45b..fec218ca3b 100644 --- a/indra/newview/llfloaterfixedenvironment.cpp +++ b/indra/newview/llfloaterfixedenvironment.cpp @@ -137,6 +137,7 @@ void LLFloaterFixedEnvironment::onClose(bool app_quitting) doCloseInventoryFloater(app_quitting); LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL); + LLEnvironment::instance().setCurrentEnvironmentSelection(LLEnvironment::ENV_LOCAL); LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_EDIT); mSettings.reset(); diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 028c922a4d..89ba687d25 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -664,10 +664,7 @@ BOOL LLImagePreviewAvatar::render() LLGLSUIDefault def; gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); gl_rect_2d_simple( mFullWidth, mFullHeight ); @@ -866,10 +863,7 @@ BOOL LLImagePreviewSculpted::render() gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); gl_rect_2d_simple( mFullWidth, mFullHeight ); @@ -903,10 +897,7 @@ BOOL LLImagePreviewSculpted::render() gPipeline.enableLightsAvatar(); - if (LLGLSLShader::sNoFixedFunction) - { - gObjectPreviewProgram.bind(); - } + gObjectPreviewProgram.bind(); gPipeline.enableLightsPreview(); gGL.pushMatrix(); @@ -920,10 +911,7 @@ BOOL LLImagePreviewSculpted::render() gGL.popMatrix(); - if (LLGLSLShader::sNoFixedFunction) - { - gObjectPreviewProgram.unbind(); - } + gObjectPreviewProgram.unbind(); return TRUE; } diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp index 6cd1648182..1525bb9952 100644 --- a/indra/newview/llfloaterimcontainer.cpp +++ b/indra/newview/llfloaterimcontainer.cpp @@ -723,7 +723,8 @@ void LLFloaterIMContainer::setMinimized(BOOL b) } void LLFloaterIMContainer::setVisible(BOOL visible) -{ LLFloaterIMNearbyChat* nearby_chat; +{ + LLFloaterIMNearbyChat* nearby_chat; if (visible) { // Make sure we have the Nearby Chat present when showing the conversation container @@ -758,22 +759,25 @@ void LLFloaterIMContainer::setVisible(BOOL visible) LLFloaterIMSessionTab::addToHost(LLUUID()); } - // We need to show/hide all the associated conversations that have been torn off - // (and therefore, are not longer managed by the multifloater), - // so that they show/hide with the conversations manager. - conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); - for (;widget_it != mConversationsWidgets.end(); ++widget_it) - { - LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second); - if (widget) - { - LLFloater* session_floater = widget->getSessionFloater(); - if (session_floater != nearby_chat) - { - widget->setVisibleIfDetached(visible); - } - } - } + if (!LLFloater::isQuitRequested()) + { + // We need to show/hide all the associated conversations that have been torn off + // (and therefore, are not longer managed by the multifloater), + // so that they show/hide with the conversations manager. + conversations_widgets_map::iterator widget_it = mConversationsWidgets.begin(); + for (; widget_it != mConversationsWidgets.end(); ++widget_it) + { + LLConversationViewSession* widget = dynamic_cast<LLConversationViewSession*>(widget_it->second); + if (widget) + { + LLFloater* session_floater = widget->getSessionFloater(); + if (session_floater != nearby_chat) + { + widget->setVisibleIfDetached(visible); + } + } + } + } // Now, do the normal multifloater show/hide LLMultiFloater::setVisible(visible); diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 0fefb0d432..fe5120376c 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -138,10 +138,10 @@ mAvatarTabIndex(0) mStatusLock = new LLMutex(); mModelPreview = NULL; - mLODMode[LLModel::LOD_HIGH] = 0; + mLODMode[LLModel::LOD_HIGH] = LLModelPreview::LOD_FROM_FILE; for (U32 i = 0; i < LLModel::LOD_HIGH; i++) { - mLODMode[i] = 1; + mLODMode[i] = LLModelPreview::MESH_OPTIMIZER_AUTO; } } @@ -351,15 +351,6 @@ void LLFloaterModelPreview::initModelPreview() //static bool LLFloaterModelPreview::showModelPreview() { -#ifdef LL_GLOD - if (LLRender::sGLCoreProfile) - { - // GLOD is incompatible with RenderGLCoreProfile, will crash on init - LLNotificationsUtil::add("MeshUploadProfilerError"); - return false; - } -#endif - LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)LLFloaterReg::getInstance("upload_model"); if (fmp && !fmp->isModelLoading()) { @@ -744,7 +735,19 @@ void LLFloaterModelPreview::onAutoFillCommit(LLUICtrl* ctrl, void* userdata) void LLFloaterModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) { - mModelPreview->onLODParamCommit(lod, enforce_tri_limit); + LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]); + S32 mode = lod_source_combo->getCurrentIndex(); + switch (mode) + { + case LLModelPreview::MESH_OPTIMIZER_AUTO: + case LLModelPreview::MESH_OPTIMIZER_SLOPPY: + case LLModelPreview::MESH_OPTIMIZER_COMBINE: + mModelPreview->onLODMeshOptimizerParamCommit(lod, enforce_tri_limit, mode); + break; + default: + LL_ERRS() << "Only supposed to be called to generate models" << LL_ENDL; + break; + } //refresh LoDs that reference this one for (S32 i = lod - 1; i >= 0; --i) @@ -1376,31 +1379,31 @@ void LLFloaterModelPreview::clearAvatarTab() } void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) - { +{ S32 display_lod = mModelPreview->mPreviewLOD; if (mModelPreview->mModel[display_lod].empty()) - { + { mSelectedJointName.clear(); return; - } + } // Joints will be listed as long as they are listed in mAlternateBindMatrix // even if they are for some reason identical to defaults. // Todo: Are overrides always identical for all lods? They normally are, but there might be situations where they aren't. if (mJointOverrides[display_lod].empty()) - { + { // populate map for (LLModelLoader::scene::iterator iter = mModelPreview->mScene[display_lod].begin(); iter != mModelPreview->mScene[display_lod].end(); ++iter) - { + { for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) - { + { LLModelInstance& instance = *model_iter; LLModel* model = instance.mModel; const LLMeshSkinInfo *skin = &model->mSkinInfo; U32 joint_count = LLSkinningUtil::getMeshJointCount(skin); U32 bind_count = highlight_overrides ? skin->mAlternateBindMatrix.size() : 0; // simply do not include overrides if data is not needed if (bind_count > 0 && bind_count != joint_count) - { + { std::ostringstream out; out << "Invalid joint overrides for model " << model->getName(); out << ". Amount of joints " << joint_count; @@ -1409,68 +1412,68 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) addStringToLog(out.str(), true); // Disable overrides for this model bind_count = 0; - } + } if (bind_count > 0) - { + { for (U32 j = 0; j < joint_count; ++j) - { - const LLVector3& joint_pos = skin->mAlternateBindMatrix[j].getTranslation(); + { + const LLVector3& joint_pos = LLVector3(skin->mAlternateBindMatrix[j].getTranslation()); LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; LLJoint* pJoint = LLModelPreview::lookupJointByName(skin->mJointNames[j], mModelPreview); if (pJoint) - { + { // see how voavatar uses aboveJointPosThreshold if (pJoint->aboveJointPosThreshold(joint_pos)) - { + { // valid override if (data.mPosOverrides.size() > 0 && (data.mPosOverrides.begin()->second - joint_pos).lengthSquared() > (LL_JOINT_TRESHOLD_POS_OFFSET * LL_JOINT_TRESHOLD_POS_OFFSET)) - { + { // File contains multiple meshes with conflicting joint offsets // preview may be incorrect, upload result might wary (depends onto // mesh_id that hasn't been generated yet). data.mHasConflicts = true; - } + } data.mPosOverrides[model->getName()] = joint_pos; - } - else - { + } + else + { // default value, it won't be accounted for by avatar data.mModelsNoOverrides.insert(model->getName()); - } - } - } - } - else - { + } + } + } + } + else + { for (U32 j = 0; j < joint_count; ++j) - { + { LLJointOverrideData &data = mJointOverrides[display_lod][skin->mJointNames[j]]; data.mModelsNoOverrides.insert(model->getName()); } } - } - } - } + } + } + } LLPanel *panel = mTabContainer->getPanelByName("rigging_panel"); LLScrollListCtrl *joints_list = panel->getChild<LLScrollListCtrl>("joints_list"); if (joints_list->isEmpty()) - { + { // Populate table - std::map<std::string, std::string> joint_alias_map; + std::map<std::string, std::string> joint_alias_map; mModelPreview->getJointAliases(joint_alias_map); - + S32 conflicts = 0; joint_override_data_map_t::iterator joint_iter = mJointOverrides[display_lod].begin(); joint_override_data_map_t::iterator joint_end = mJointOverrides[display_lod].end(); while (joint_iter != joint_end) - { + { const std::string& listName = joint_iter->first; - + LLScrollListItem::Params item_params; item_params.value(listName); @@ -1478,38 +1481,38 @@ void LLFloaterModelPreview::updateAvatarTab(bool highlight_overrides) cell_params.font = LLFontGL::getFontSansSerif(); cell_params.value = listName; if (joint_alias_map.find(listName) == joint_alias_map.end()) - { + { // Missing names cell_params.color = LLColor4::red; - } + } if (joint_iter->second.mHasConflicts) - { + { // Conflicts cell_params.color = LLColor4::orange; conflicts++; - } + } if (highlight_overrides && joint_iter->second.mPosOverrides.size() > 0) - { + { cell_params.font.style = "BOLD"; - } + } item_params.columns.add(cell_params); joints_list->addRow(item_params, ADD_BOTTOM); joint_iter++; - } + } joints_list->selectFirstItem(); LLScrollListItem *selected = joints_list->getFirstSelected(); if (selected) -{ + { mSelectedJointName = selected->getValue().asString(); - } + } LLTextBox *joint_conf_descr = panel->getChild<LLTextBox>("conflicts_description"); joint_conf_descr->setTextArg("[CONFLICTS]", llformat("%d", conflicts)); joint_conf_descr->setTextArg("[JOINTS_COUNT]", llformat("%d", mJointOverrides[display_lod].size())); - } - } + } +} //----------------------------------------------------------------------------- // addStringToLogTab() @@ -1739,19 +1742,10 @@ void LLFloaterModelPreview::onLoDSourceCommit(S32 lod) mModelPreview->updateLodControls(lod); LLComboBox* lod_source_combo = getChild<LLComboBox>("lod_source_" + lod_name[lod]); - - if (lod_source_combo->getCurrentIndex() == LLModelPreview::LOD_FROM_FILE - && mModelPreview->mLODFile[lod].empty()) - { - // File wasn't selected, so nothing to do yet, refreshing - // hovewer will cause a small freeze with large meshes - // Might be good idea to open filepicker here - return; - } - - refresh(); - - if (lod_source_combo->getCurrentIndex() == LLModelPreview::GENERATE) + S32 index = lod_source_combo->getCurrentIndex(); + if (index == LLModelPreview::MESH_OPTIMIZER_AUTO + || index == LLModelPreview::MESH_OPTIMIZER_SLOPPY + || index == LLModelPreview::MESH_OPTIMIZER_COMBINE) { //rebuild LoD to update triangle counts onLODParamCommit(lod, true); } @@ -1782,7 +1776,7 @@ void LLFloaterModelPreview::resetUploadOptions() getChild<LLComboBox>("lod_source_" + lod_name[NUM_LOD - 1])->setCurrentByIndex(LLModelPreview::LOD_FROM_FILE); for (S32 lod = 0; lod < NUM_LOD - 1; ++lod) { - getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::GENERATE); + getChild<LLComboBox>("lod_source_" + lod_name[lod])->setCurrentByIndex(LLModelPreview::MESH_OPTIMIZER_AUTO); childSetValue("lod_file_" + lod_name[lod], ""); } diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h index b5dab262a3..1e147cd555 100644 --- a/indra/newview/llfloatermodelpreview.h +++ b/indra/newview/llfloatermodelpreview.h @@ -197,9 +197,7 @@ protected: std::map<std::string, bool> mViewOptionDisabled; //store which lod mode each LOD is using - // 0 - load from file - // 1 - auto generate - // 2 - use LoD above + // See eLoDMode S32 mLODMode[4]; LLMutex* mStatusLock; diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 9064a65d05..8d19aa36bb 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -1196,14 +1196,11 @@ void LLFloaterPreference::refreshEnabledState() //Deferred/SSAO/Shadows BOOL bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump"); - BOOL transparent_water = LLFeatureManager::getInstance()->isFeatureAvailable("RenderTransparentWater") && gSavedSettings.getBOOL("RenderTransparentWater"); BOOL shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && bumpshiny && - transparent_water && shaders && gGLManager.mHasFramebufferObject && - gSavedSettings.getBOOL("RenderAvatarVP") && (ctrl_wind_light->get()) ? TRUE : FALSE; ctrl_deferred->setEnabled(enabled); @@ -1224,37 +1221,14 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() ctrl_reflections->setEnabled(reflections); reflections_text->setEnabled(reflections); - // Transparent Water - LLCheckBoxCtrl* transparent_water_ctrl = getChild<LLCheckBoxCtrl>("TransparentWater"); - // Bump & Shiny LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny"); bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE); // Avatar Mode - // Enable Avatar Shaders - LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram"); // Avatar Render Mode - LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth"); - - bool avatar_vp_enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"); - if (LLViewerShaderMgr::sInitialized) - { - S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel; - avatar_vp_enabled = (max_avatar_shader > 0) ? TRUE : FALSE; - } - - ctrl_avatar_vp->setEnabled(avatar_vp_enabled); - - if (gSavedSettings.getBOOL("RenderAvatarVP") == FALSE) - { - ctrl_avatar_cloth->setEnabled(FALSE); - } - else - { - ctrl_avatar_cloth->setEnabled(TRUE); - } + getChild<LLCheckBoxCtrl>("AvatarCloth")->setEnabled(TRUE); // Vertex Shaders, Global Shader Enable // SL-12594 Basic shaders are always enabled. DJH TODO clean up now-orphaned state handling code @@ -1277,9 +1251,7 @@ void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) && - ((transparent_water_ctrl && transparent_water_ctrl->get()) ? TRUE : FALSE) && gGLManager.mHasFramebufferObject && - gSavedSettings.getBOOL("RenderAvatarVP") && (ctrl_wind_light->get()) ? TRUE : FALSE; ctrl_deferred->setEnabled(enabled); @@ -1378,7 +1350,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() { LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections"); LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText"); - LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram"); LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth"); LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); @@ -1454,30 +1425,6 @@ void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() reflections_text->setEnabled(FALSE); } - // disabled av - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP")) - { - ctrl_avatar_vp->setEnabled(FALSE); - ctrl_avatar_vp->setValue(FALSE); - - ctrl_avatar_cloth->setEnabled(FALSE); - ctrl_avatar_cloth->setValue(FALSE); - - //deferred needs AvatarVP, disable deferred - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - - ctrl_deferred->setEnabled(FALSE); - ctrl_deferred->setValue(FALSE); - } - // disabled cloth if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth")) { diff --git a/indra/newview/llfloaterwebcontent.cpp b/indra/newview/llfloaterwebcontent.cpp index 23fd6d9c8e..ceab472c55 100644 --- a/indra/newview/llfloaterwebcontent.cpp +++ b/indra/newview/llfloaterwebcontent.cpp @@ -159,7 +159,7 @@ LLFloater* LLFloaterWebContent::create( Params p) //static void LLFloaterWebContent::closeRequest(const std::string &uuid) { - LLFloaterWebContent* floaterp = instance_tracker_t::getInstance(uuid); + auto floaterp = instance_tracker_t::getInstance(uuid); if (floaterp) { floaterp->closeFloater(false); @@ -169,7 +169,7 @@ void LLFloaterWebContent::closeRequest(const std::string &uuid) //static void LLFloaterWebContent::geometryChanged(const std::string &uuid, S32 x, S32 y, S32 width, S32 height) { - LLFloaterWebContent* floaterp = instance_tracker_t::getInstance(uuid); + auto floaterp = instance_tracker_t::getInstance(uuid); if (floaterp) { floaterp->geometryChanged(x, y, width, height); diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 698c15bd2d..175f1849cf 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -791,10 +791,7 @@ void LLViewerObjectList::renderObjectBeacons() LLGLSUIDefault gls_ui; - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -882,10 +879,7 @@ void LLViewerObjectList::renderObjectBeacons() void LLSky::renderSunMoonBeacons(const LLVector3& pos_agent, const LLVector3& direction, LLColor4 color) { LLGLSUIDefault gls_ui; - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLVector3 pos_end; @@ -993,9 +987,8 @@ private: //----------------------------------------------------------------------------- F32 gpu_benchmark() { - if (!gGLManager.mHasShaderObjects || !gGLManager.mHasTimerQuery) - { // don't bother benchmarking the fixed function - // or venerable drivers which don't support accurate timing anyway + if (!gGLManager.mHasTimerQuery) + { // don't bother benchmarking venerable drivers which don't support accurate timing anyway // and are likely to be correctly identified by the GPU table already. return -1.f; } @@ -1091,7 +1084,7 @@ F32 gpu_benchmark() delete [] pixels; //make a dummy triangle to draw with - LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STREAM_DRAW_ARB); + LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_STREAM_DRAW_ARB); if (!buff->allocateBuffer(3, 0, true)) { @@ -1101,7 +1094,6 @@ F32 gpu_benchmark() } LLStrider<LLVector3> v; - LLStrider<LLVector2> tc; if (! buff->getVertexStrider(v)) { @@ -1123,6 +1115,16 @@ F32 gpu_benchmark() // ensure matched pair of bind() and unbind() calls ShaderBinder binder(gBenchmarkProgram); +#ifdef GL_ARB_vertex_array_object + U32 glarray = 0; + + if (LLRender::sGLCoreProfile) + { + glGenVertexArrays(1, &glarray); + glBindVertexArray(glarray); + } +#endif + buff->setBuffer(LLVertexBuffer::MAP_VERTEX); glFinish(); @@ -1155,6 +1157,15 @@ F32 gpu_benchmark() } } +#ifdef GL_ARB_vertex_array_object + if (LLRender::sGLCoreProfile) + { + glBindVertexArray(0); + glDeleteVertexArrays(1, &glarray); + } +#endif + + std::sort(results.begin(), results.end()); F32 gbps = results[results.size()/2]; diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 32f88b49ac..7f65153879 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -944,12 +944,10 @@ static void formatDateString(std::string &date_string) } } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_MEMBERS_REPLY("Process Group Members"); - // static void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_MEMBERS_REPLY); + LL_PROFILE_ZONE_SCOPED; LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupMembersReply" << LL_ENDL; LLUUID agent_id; @@ -1054,12 +1052,10 @@ void LLGroupMgr::processGroupMembersReply(LLMessageSystem* msg, void** data) LLGroupMgr::getInstance()->notifyObservers(GC_MEMBER_DATA); } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_PROPERTIES_REPLY("Process Group Properties"); - //static void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_PROPERTIES_REPLY); + LL_PROFILE_ZONE_SCOPED; LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupPropertiesReply" << LL_ENDL; if (!msg) @@ -1139,11 +1135,10 @@ void LLGroupMgr::processGroupPropertiesReply(LLMessageSystem* msg, void** data) LLGroupMgr::getInstance()->notifyObservers(GC_PROPERTIES); } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_ROLE_DATA_REPLY("Process Group Role Data"); // static void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_ROLE_DATA_REPLY); + LL_PROFILE_ZONE_SCOPED; LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleDataReply" << LL_ENDL; LLUUID agent_id; @@ -1227,11 +1222,10 @@ void LLGroupMgr::processGroupRoleDataReply(LLMessageSystem* msg, void** data) LLGroupMgr::getInstance()->notifyObservers(GC_ROLE_DATA); } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_GROUP_ROLE_MEMBERS_REPLY("Process Group Role Members"); // static void LLGroupMgr::processGroupRoleMembersReply(LLMessageSystem* msg, void** data) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_GROUP_ROLE_MEMBERS_REPLY); + LL_PROFILE_ZONE_SCOPED; LL_DEBUGS("GrpMgr") << "LLGroupMgr::processGroupRoleMembersReply" << LL_ENDL; LLUUID agent_id; diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index 9d49c30a49..952fbf8e4b 100644 --- a/indra/newview/llhudnametag.cpp +++ b/indra/newview/llhudnametag.cpp @@ -224,6 +224,7 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector4a& start, const LLVector4 void LLHUDNameTag::render() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; if (sDisplayText) { LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); @@ -322,8 +323,6 @@ void LLHUDNameTag::renderText(BOOL for_select) // Render label { - //gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin(); segment_iter != mLabelSegments.end(); ++segment_iter ) { @@ -731,6 +730,7 @@ void LLHUDNameTag::updateSize() void LLHUDNameTag::updateAll() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; // iterate over all text objects, calculate their restoration forces, // and add them to the visible set if they are on screen and close enough sVisibleTextObjects.clear(); diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 598a8d4c05..7be35ac260 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -188,9 +188,6 @@ void LLHUDText::renderText() F32 y_offset = (F32)mOffsetY; // Render label - { - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } // Render text { @@ -573,7 +570,6 @@ void LLHUDText::renderAllHUD() { LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); { LLGLEnable color_mat(GL_COLOR_MATERIAL); @@ -591,7 +587,6 @@ void LLHUDText::renderAllHUD() LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); } void LLHUDText::shiftAll(const LLVector3& offset) diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 3017d927e5..b7e0a6a794 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -1229,7 +1229,6 @@ LLIMModel::LLIMSession* LLIMModel::addMessageSilently(const LLUUID& session_id, if (!session) { - LL_WARNS() << "session " << session_id << "does not exist " << LL_ENDL; return NULL; } diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 342920630b..a0de3a2af1 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -5755,14 +5755,14 @@ class LLCallingCardObserver : public LLFriendObserver public: LLCallingCardObserver(LLCallingCardBridge* bridge) : mBridgep(bridge) {} virtual ~LLCallingCardObserver() { mBridgep = NULL; } - virtual void changed(U32 mask) - { - mBridgep->refreshFolderViewItem(); - if (mask & LLFriendObserver::ONLINE) - { - mBridgep->checkSearchBySuffixChanges(); - } - } + virtual void changed(U32 mask) + { + if (mask & LLFriendObserver::ONLINE) + { + mBridgep->refreshFolderViewItem(); + mBridgep->checkSearchBySuffixChanges(); + } + } protected: LLCallingCardBridge* mBridgep; }; @@ -5776,14 +5776,16 @@ LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory, const LLUUID& uuid ) : LLItemBridge(inventory, root, uuid) { - mObserver = new LLCallingCardObserver(this); - LLAvatarTracker::instance().addObserver(mObserver); + mObserver = new LLCallingCardObserver(this); + mCreatorUUID = getItem()->getCreatorUUID(); + LLAvatarTracker::instance().addParticularFriendObserver(mCreatorUUID, mObserver); } LLCallingCardBridge::~LLCallingCardBridge() { - LLAvatarTracker::instance().removeObserver(mObserver); - delete mObserver; + LLAvatarTracker::instance().removeParticularFriendObserver(mCreatorUUID, mObserver); + + delete mObserver; } void LLCallingCardBridge::refreshFolderViewItem() diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index c21bfbd02d..0b0ef273e1 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -457,6 +457,7 @@ public: void checkSearchBySuffixChanges(); protected: LLCallingCardObserver* mObserver; + LLUUID mCreatorUUID; }; class LLNotecardBridge : public LLItemBridge diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp index 3b5ba24b9f..707ff2b7b6 100644 --- a/indra/newview/llinventoryfilter.cpp +++ b/indra/newview/llinventoryfilter.cpp @@ -48,8 +48,6 @@ #include "llclipboard.h" #include "lltrans.h" -LLTrace::BlockTimerStatHandle FT_FILTER_CLIPBOARD("Filter Clipboard"); - LLInventoryFilter::FilterOps::FilterOps(const Params& p) : mFilterObjectTypes(p.object_types), mFilterCategoryTypes(p.category_types), @@ -506,7 +504,7 @@ bool LLInventoryFilter::checkAgainstClipboard(const LLUUID& object_id) const { if (LLClipboard::instance().isCutMode()) { - LL_RECORD_BLOCK_TIME(FT_FILTER_CLIPBOARD); + LL_PROFILE_ZONE_SCOPED; LLUUID current_id = object_id; LLInventoryObject *current_object = gInventory.getObject(object_id); while (current_id.notNull() && current_object) diff --git a/indra/newview/llinventoryitemslist.cpp b/indra/newview/llinventoryitemslist.cpp index 1dc1aa395e..23129f7d44 100644 --- a/indra/newview/llinventoryitemslist.cpp +++ b/indra/newview/llinventoryitemslist.cpp @@ -133,11 +133,9 @@ void LLInventoryItemsList::idle(void* user_data) } } -LLTrace::BlockTimerStatHandle FTM_INVENTORY_ITEMS_REFRESH("Inventory List Refresh"); - void LLInventoryItemsList::refresh() { - LL_RECORD_BLOCK_TIME(FTM_INVENTORY_ITEMS_REFRESH); + LL_PROFILE_ZONE_SCOPED; switch (mRefreshState) { diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index fe7f2c6a43..6b102c7500 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -688,10 +688,9 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve } // Called when something changed in the global model (new item, item coming through the wire, rename, move, etc...) (CHUI-849) -static LLTrace::BlockTimerStatHandle FTM_REFRESH("Inventory Refresh"); void LLInventoryPanel::modelChanged(U32 mask) { - LL_RECORD_BLOCK_TIME(FTM_REFRESH); + LL_PROFILE_ZONE_SCOPED; if (mViewsInitialized != VIEWS_INITIALIZED) return; @@ -1835,10 +1834,9 @@ void LLInventoryPanel::removeItemID(const LLUUID& id) } } -LLTrace::BlockTimerStatHandle FTM_GET_ITEM_BY_ID("Get FolderViewItem by ID"); LLFolderViewItem* LLInventoryPanel::getItemByID(const LLUUID& id) { - LL_RECORD_BLOCK_TIME(FTM_GET_ITEM_BY_ID); + LL_PROFILE_ZONE_SCOPED; std::map<LLUUID, LLFolderViewItem*>::iterator map_it; map_it = mItemMap.find(id); diff --git a/indra/newview/lllegacyatmospherics.cpp b/indra/newview/lllegacyatmospherics.cpp index a2acb3efe2..1364067949 100644 --- a/indra/newview/lllegacyatmospherics.cpp +++ b/indra/newview/lllegacyatmospherics.cpp @@ -202,17 +202,11 @@ void LLAtmospherics::init() mInitialized = true; } -LLColor4 LLAtmospherics::calcSkyColorInDir(AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny) -{ - LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - return calcSkyColorInDir(psky, vars, dir, isShiny); -} - // This cubemap is used as "environmentMap" in indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl -LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny) +LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3 &dir, bool isShiny, bool low_end) { - F32 sky_saturation = 0.25f; - F32 land_saturation = 0.1f; + const F32 sky_saturation = 0.25f; + const F32 land_saturation = 0.1f; if (isShiny && dir.mV[VZ] < -0.02f) { @@ -227,7 +221,7 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm } F32 greyscale_sat = brightness * (1.0f - land_saturation); desat_fog = desat_fog * land_saturation + smear(greyscale_sat); - if (!gPipeline.canUseWindLightShaders()) + if (low_end) { col = LLColor4(desat_fog, 0.f); } @@ -258,8 +252,7 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm return LLColor4(sky_color, 0.0f); } - bool low_end = !gPipeline.canUseWindLightShaders(); - LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f); + LLColor3 sky_color = low_end ? vars.hazeColor * 2.0f : psky->gammaCorrect(vars.hazeColor * 2.0f, vars.gamma); return LLColor4(sky_color, 0.0f); } @@ -270,11 +263,12 @@ LLColor4 LLAtmospherics::calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, Atm // indra\newview\lllegacyatmospherics.cpp void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars) { - LLColor3 blue_density = vars.blue_density; - LLColor3 blue_horizon = vars.blue_horizon; - F32 haze_horizon = vars.haze_horizon; - F32 haze_density = vars.haze_density; - F32 density_multiplier = vars.density_multiplier; + const LLColor3 blue_density = vars.blue_density; + const LLColor3 blue_horizon = vars.blue_horizon; + const F32 haze_horizon = vars.haze_horizon; + const F32 haze_density = vars.haze_density; + const F32 density_multiplier = vars.density_multiplier; + F32 max_y = vars.max_y; LLVector4 sun_norm = vars.sun_norm; @@ -313,7 +307,7 @@ void LLAtmospherics::calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVect // Sunlight attenuation effect (hue and brightness) due to atmosphere // this is used later for sunlight modulation at various altitudes LLColor3 light_atten = vars.light_atten; - LLColor3 light_transmittance = psky->getLightTransmittance(Plen); + LLColor3 light_transmittance = psky->getLightTransmittanceFast(vars.total_density, vars.density_multiplier, Plen); (void)light_transmittance; // silence Clang warn-error // Calculate relative weights @@ -389,12 +383,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in) if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG)) { - if (!LLGLSLShader::sNoFixedFunction) - { - glFogf(GL_FOG_DENSITY, 0); - glFogfv(GL_FOG_COLOR, (F32 *) &LLColor4::white.mV); - glFogf(GL_FOG_END, 1000000.f); - } return; } @@ -436,12 +424,16 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in) LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + // NOTE: This is very similar to LLVOSky::cacheEnvironment() + // Differences: + // vars.sun_norm + // vars.sunlight // invariants across whole sky tex process... - vars.blue_density = psky->getBlueDensity(); + vars.blue_density = psky->getBlueDensity(); vars.blue_horizon = psky->getBlueHorizon(); vars.haze_density = psky->getHazeDensity(); vars.haze_horizon = psky->getHazeHorizon(); - vars.density_multiplier = psky->getDensityMultiplier(); + vars.density_multiplier = psky->getDensityMultiplier(); vars.distance_multiplier = psky->getDistanceMultiplier(); vars.max_y = psky->getMaxY(); vars.sun_norm = LLEnvironment::instance().getSunDirectionCFR(); @@ -456,9 +448,9 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in) vars.total_density = psky->getTotalDensity(); vars.gamma = psky->getGamma(); - res_color[0] = calcSkyColorInDir(vars, tosun); - res_color[1] = calcSkyColorInDir(vars, perp_tosun); - res_color[2] = calcSkyColorInDir(vars, tosun_45); + res_color[0] = calcSkyColorInDir(psky, vars, tosun); + res_color[1] = calcSkyColorInDir(psky, vars, perp_tosun); + res_color[2] = calcSkyColorInDir(psky, vars, tosun_45); sky_fog_color = color_norm(res_color[0] + res_color[1] + res_color[2]); @@ -486,10 +478,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in) if (camera_height > water_height) { LLColor4 fog(render_fog_color); - if (!LLGLSLShader::sNoFixedFunction) - { - glFogfv(GL_FOG_COLOR, fog.mV); - } mGLFogCol = fog; if (hide_clip_plane) @@ -497,19 +485,11 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in) // For now, set the density to extend to the cull distance. const F32 f_log = 2.14596602628934723963618357029f; // sqrt(fabs(log(0.01f))) fog_density = f_log/fog_distance; - if (!LLGLSLShader::sNoFixedFunction) - { - glFogi(GL_FOG_MODE, GL_EXP2); - } } else { const F32 f_log = 4.6051701859880913680359829093687f; // fabs(log(0.01f)) fog_density = (f_log)/fog_distance; - if (!LLGLSLShader::sNoFixedFunction) - { - glFogi(GL_FOG_MODE, GL_EXP); - } } } else @@ -535,12 +515,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in) // set the density based on what the shaders use fog_density = water_fog_density * gSavedSettings.getF32("WaterGLFogDensityScale"); - - if (!LLGLSLShader::sNoFixedFunction) - { - glFogfv(GL_FOG_COLOR, (F32 *) &fogCol.mV); - glFogi(GL_FOG_MODE, GL_EXP2); - } } mFogColor = sky_fog_color; @@ -548,13 +522,6 @@ void LLAtmospherics::updateFog(const F32 distance, const LLVector3& tosun_in) LLDrawPoolWater::sWaterFogEnd = fog_distance*2.2f; - if (!LLGLSLShader::sNoFixedFunction) - { - LLGLSFog gls_fog; - glFogf(GL_FOG_END, fog_distance*2.2f); - glFogf(GL_FOG_DENSITY, fog_density); - glHint(GL_FOG_HINT, GL_NICEST); - } stop_glerror(); } diff --git a/indra/newview/lllegacyatmospherics.h b/indra/newview/lllegacyatmospherics.h index 03c8efb91a..d48f3040c3 100644 --- a/indra/newview/lllegacyatmospherics.h +++ b/indra/newview/lllegacyatmospherics.h @@ -257,13 +257,11 @@ public: void setCloudDensity(F32 cloud_density) { mCloudDensity = cloud_density; } void setWind ( const LLVector3& wind ) { mWind = wind.length(); } - LLColor4 calcSkyColorInDir(AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false); - LLColor4 calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false); + LLColor4 calcSkyColorInDir(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const LLVector3& dir, bool isShiny = false, const bool low_end = false); -protected: +protected: void calcSkyColorWLVert(const LLSettingsSky::ptr_t &psky, LLVector3 & Pn, AtmosphericsVars& vars); - LLColor3 getHazeColor(LLSettingsSky::ptr_t psky, AtmosphericsVars& vars, F32 costheta, F32 cloud_shadow); LLHaze mHaze; F32 mHazeConcentration; diff --git a/indra/newview/llmainlooprepeater.cpp b/indra/newview/llmainlooprepeater.cpp deleted file mode 100644 index 6736e9a950..0000000000 --- a/indra/newview/llmainlooprepeater.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/** - * @file llmachineid.cpp - * @brief retrieves unique machine ids - * - * $LicenseInfo:firstyear=2009&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$ - */ - -#include "llviewerprecompiledheaders.h" -#include "llapr.h" -#include "llevents.h" -#include "llmainlooprepeater.h" - - - -// LLMainLoopRepeater -//----------------------------------------------------------------------------- - - -LLMainLoopRepeater::LLMainLoopRepeater(void): - mQueue(0) -{ - ; // No op. -} - - -void LLMainLoopRepeater::start(void) -{ - if(mQueue != 0) return; - - mQueue = new LLThreadSafeQueue<LLSD>(1024); - mMainLoopConnection = LLEventPumps::instance(). - obtain("mainloop").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMainLoop, this, _1)); - mRepeaterConnection = LLEventPumps::instance(). - obtain("mainlooprepeater").listen(LLEventPump::inventName(), boost::bind(&LLMainLoopRepeater::onMessage, this, _1)); -} - - -void LLMainLoopRepeater::stop(void) -{ - mMainLoopConnection.release(); - mRepeaterConnection.release(); - - delete mQueue; - mQueue = 0; -} - - -bool LLMainLoopRepeater::onMainLoop(LLSD const &) -{ - LLSD message; - while(mQueue->tryPopBack(message)) { - std::string pump = message["pump"].asString(); - if(pump.length() == 0 ) continue; // No pump. - LLEventPumps::instance().obtain(pump).post(message["payload"]); - } - return false; -} - - -bool LLMainLoopRepeater::onMessage(LLSD const & event) -{ - try { - mQueue->pushFront(event); - } catch(LLThreadSafeQueueError & e) { - LL_WARNS() << "could not repeat message (" << e.what() << ")" << - event.asString() << LL_ENDL; - } - return false; -} diff --git a/indra/newview/llmainlooprepeater.h b/indra/newview/llmainlooprepeater.h deleted file mode 100644 index 2ec3a74e4a..0000000000 --- a/indra/newview/llmainlooprepeater.h +++ /dev/null @@ -1,64 +0,0 @@ -/** - * @file llmainlooprepeater.h - * @brief a service for repeating messages on the main loop. - * - * $LicenseInfo:firstyear=2010&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_LLMAINLOOPREPEATER_H -#define LL_LLMAINLOOPREPEATER_H - - -#include "llsd.h" -#include "llthreadsafequeue.h" - - -// -// A service which creates the pump 'mainlooprepeater' to which any thread can -// post a message that will be re-posted on the main loop. -// -// The posted message should contain two map elements: pump and payload. The -// pump value is a string naming the pump to which the message should be -// re-posted. The payload value is what will be posted to the designated pump. -// -class LLMainLoopRepeater: - public LLSingleton<LLMainLoopRepeater> -{ - LLSINGLETON(LLMainLoopRepeater); -public: - // Start the repeater service. - void start(void); - - // Stop the repeater service. - void stop(void); - -private: - LLTempBoundListener mMainLoopConnection; - LLTempBoundListener mRepeaterConnection; - LLThreadSafeQueue<LLSD> * mQueue; - - bool onMainLoop(LLSD const &); - bool onMessage(LLSD const & event); -}; - - -#endif diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index 3566ca7a35..d85a846f4d 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -157,10 +157,7 @@ void LLManipRotate::render() } else { - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.bind(); - } + gDebugProgram.bind(); LLGLEnable cull_face(GL_CULL_FACE); LLGLDepthTest gls_depth(GL_FALSE); @@ -213,10 +210,7 @@ void LLManipRotate::render() } gGL.popMatrix(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); } gGL.translatef( center.mV[VX], center.mV[VY], center.mV[VZ] ); @@ -234,10 +228,7 @@ void LLManipRotate::render() gGL.rotatef(angle_radians * RAD_TO_DEG, x, y, z); - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.bind(); - } + gDebugProgram.bind(); if (mManipPart == LL_ROT_Z) { @@ -355,11 +346,7 @@ void LLManipRotate::render() } - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } - + gUIProgram.bind(); } gGL.popMatrix(); gGL.popMatrix(); diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index 8736d3b51f..0b2a1ef389 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -1565,11 +1565,6 @@ void LLManipTranslate::renderSnapGuides() LLGLEnable stipple(GL_LINE_STIPPLE); gGL.flush(); - if (!LLGLSLShader::sNoFixedFunction) - { - glLineStipple(1, 0x3333); - } - switch (mManipPart) { case LL_YZ_PLANE: @@ -1633,7 +1628,7 @@ void LLManipTranslate::highlightIntersection(LLVector3 normal, LLQuaternion grid_rotation, LLColor4 inner_color) { - if (!gSavedSettings.getBOOL("GridCrossSections") || !LLGLSLShader::sNoFixedFunction) + if (!gSavedSettings.getBOOL("GridCrossSections")) { return; } diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp index 52b9fb40ae..11aa607393 100644 --- a/indra/newview/llmaterialmgr.cpp +++ b/indra/newview/llmaterialmgr.cpp @@ -580,11 +580,9 @@ void LLMaterialMgr::onPutResponse(bool success, const LLSD& content) } } -static LLTrace::BlockTimerStatHandle FTM_MATERIALS_IDLE("Idle Materials"); - void LLMaterialMgr::onIdle(void*) { - LL_RECORD_BLOCK_TIME(FTM_MATERIALS_IDLE); + LL_PROFILE_ZONE_SCOPED; LLMaterialMgr* instancep = LLMaterialMgr::getInstance(); diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 8080e43383..d28e929b48 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1972,7 +1972,7 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat LLMeshSkinInfo info(skin); info.mMeshID = mesh_id; - // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL; + // LL_DEBUGS(LOG_MESH) << "info pelvis offset" << info.mPelvisOffset << LL_ENDL; { LLMutexLock lock(mMutex); mSkinInfoQ.push_back(info); @@ -3639,7 +3639,7 @@ S32 LLMeshRepository::update() S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_params, S32 detail, S32 last_lod) { - LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); // Manage time-to-load metrics for mesh download operations. metricsProgress(1); @@ -3722,7 +3722,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para void LLMeshRepository::notifyLoadedMeshes() { //called from main thread - LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); // GetMesh2 operation with keepalives, etc. With pipelining, // we'll increase this. See llappcorehttp and llcorehttp for @@ -4070,35 +4070,34 @@ S32 LLMeshRepository::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo const LLMeshSkinInfo* LLMeshRepository::getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj) { - LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); - - if (mesh_id.notNull()) - { - skin_map::iterator iter = mSkinMap.find(mesh_id); - if (iter != mSkinMap.end()) - { - return &(iter->second); - } - - //no skin info known about given mesh, try to fetch it - { - LLMutexLock lock(mMeshMutex); - //add volume to list of loading meshes - skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); - if (iter == mLoadingSkins.end()) - { //no request pending for this skin info - mPendingSkinRequests.push(mesh_id); - } - mLoadingSkins[mesh_id].insert(requesting_obj->getID()); - } - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + if (mesh_id.notNull()) + { + skin_map::iterator iter = mSkinMap.find(mesh_id); + if (iter != mSkinMap.end()) + { + return &(iter->second); + } + //no skin info known about given mesh, try to fetch it + if (requesting_obj != nullptr) + { + LLMutexLock lock(mMeshMutex); + //add volume to list of loading meshes + skin_load_map::iterator iter = mLoadingSkins.find(mesh_id); + if (iter == mLoadingSkins.end()) + { //no request pending for this skin info + mPendingSkinRequests.push(mesh_id); + } + mLoadingSkins[mesh_id].insert(requesting_obj->getID()); + } + } return NULL; } void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) { - LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); if (mesh_id.notNull()) { @@ -4127,7 +4126,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id) LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id) { - LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; //LL_RECORD_BLOCK_TIME(FTM_MESH_FETCH); LLModel::Decomposition* ret = NULL; diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 441264d42f..1989350303 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -27,6 +27,7 @@ #ifndef LL_MESH_REPOSITORY_H #define LL_MESH_REPOSITORY_H +#include <unordered_map> #include "llassettype.h" #include "llmodel.h" #include "lluuid.h" @@ -584,7 +585,7 @@ public: S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); static S32 getActualMeshLOD(LLSD& header, S32 lod); - const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj); + const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, const LLVOVolume* requesting_obj = nullptr); LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id); void fetchPhysicsShape(const LLUUID& mesh_id); bool hasPhysicsShape(const LLUUID& mesh_id); @@ -612,7 +613,7 @@ public: typedef std::map<LLVolumeParams, std::set<LLUUID> > mesh_load_map; mesh_load_map mLoadingMeshes[4]; - typedef std::map<LLUUID, LLMeshSkinInfo> skin_map; + typedef std::unordered_map<LLUUID, LLMeshSkinInfo> skin_map; skin_map mSkinMap; typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map; diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index fef169cbbc..859d987fc3 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -41,6 +41,7 @@ #include "lliconctrl.h" #include "llmatrix4a.h" #include "llmeshrepository.h" +#include "llmeshoptimizer.h" #include "llrender.h" #include "llsdutil_math.h" #include "llskinningutil.h" @@ -66,7 +67,6 @@ #include "lltabcontainer.h" #include "lltextbox.h" -#include "glod/glod.h" #include <boost/algorithm/string.hpp> bool LLModelPreview::sIgnoreLoadedCallback = false; @@ -89,19 +89,6 @@ static const F32 PREVIEW_ZOOM_LIMIT(10.f); const F32 SKIN_WEIGHT_CAMERA_DISTANCE = 16.f; -BOOL stop_gloderror() -{ - GLuint error = glodGetError(); - - if (error != GLOD_NO_ERROR) - { - LL_WARNS() << "GLOD error detected, cannot generate LOD: " << std::hex << error << LL_ENDL; - return TRUE; - } - - return FALSE; -} - LLViewerFetchedTexture* bindMaterialDiffuseTexture(const LLImportMaterial& material) { LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(material.getDiffuseMap(), FTT_DEFAULT, TRUE, LLGLTexture::BOOST_PREVIEW); @@ -200,10 +187,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mLoadState = LLModelLoader::STARTING; mGroup = 0; mLODFrozen = false; - mBuildShareTolerance = 0.f; - mBuildQueueMode = GLOD_QUEUE_GREEDY; - mBuildBorderMode = GLOD_BORDER_UNLOCK; - mBuildOperator = GLOD_OPERATOR_EDGE_COLLAPSE; for (U32 i = 0; i < LLModel::NUM_LODS; ++i) { @@ -211,10 +194,6 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mRequestedCreaseAngle[i] = -1.f; mRequestedLoDMode[i] = 0; mRequestedErrorThreshold[i] = 0.f; - mRequestedBuildOperator[i] = 0; - mRequestedQueueMode[i] = 0; - mRequestedBorderMode[i] = 0; - mRequestedShareTolerance[i] = 0.f; } mViewOption["show_textures"] = false; @@ -224,23 +203,11 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp) mHasPivot = false; mModelPivot = LLVector3(0.0f, 0.0f, 0.0f); - glodInit(); - createPreviewAvatar(); } LLModelPreview::~LLModelPreview() { - // glod apparently has internal mem alignment issues that are angering - // the heap-check code in windows, these should be hunted down in that - // TP code, if possible - // - // kernel32.dll!HeapFree() + 0x14 bytes - // msvcr100.dll!free(void * pBlock) Line 51 C - // glod.dll!glodGetGroupParameteriv() + 0x119 bytes - // glod.dll!glodShutdown() + 0x77 bytes - // - //glodShutdown(); if (mModelLoader) { mModelLoader->shutdown(); @@ -527,7 +494,7 @@ void LLModelPreview::rebuildUploadData() bool upload_skinweights = fmp && fmp->childGetValue("upload_skin").asBoolean(); if (upload_skinweights && high_lod_model->mSkinInfo.mJointNames.size() > 0) { - LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(high_lod_model->mSkinInfo.mBindShapeMatrix); + LLQuaternion bind_rot = LLSkinningUtil::getUnscaledQuaternion(LLMatrix4(high_lod_model->mSkinInfo.mBindShapeMatrix)); LLQuaternion identity; if (!bind_rot.isEqualEps(identity, 0.01)) { @@ -762,11 +729,6 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable mLODFile[lod] = filename; - if (lod == LLModel::LOD_HIGH) - { - clearGLODGroup(); - } - std::map<std::string, std::string> joint_alias_map; getJointAliases(joint_alias_map); @@ -867,7 +829,6 @@ void LLModelPreview::clearIncompatible(S32 lod) if (i == LLModel::LOD_HIGH) { mBaseModel = mModel[lod]; - clearGLODGroup(); mBaseScene = mScene[lod]; mVertexBuffer[5].clear(); } @@ -876,23 +837,6 @@ void LLModelPreview::clearIncompatible(S32 lod) } } -void LLModelPreview::clearGLODGroup() -{ - if (mGroup) - { - for (std::map<LLPointer<LLModel>, U32>::iterator iter = mObject.begin(); iter != mObject.end(); ++iter) - { - glodDeleteObject(iter->second); - stop_gloderror(); - } - mObject.clear(); - - glodDeleteGroup(mGroup); - stop_gloderror(); - mGroup = 0; - } -} - void LLModelPreview::loadModelCallback(S32 loaded_lod) { assert_main_thread(); @@ -1044,7 +988,6 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod) } mBaseModel = mModel[loaded_lod]; - clearGLODGroup(); mBaseScene = mScene[loaded_lod]; mVertexBuffer[5].clear(); @@ -1275,240 +1218,483 @@ void LLModelPreview::restoreNormals() updateStatusMessages(); } -void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_limit) +// Runs per object, but likely it is a better way to run per model+submodels +// returns a ratio of base model indices to resulting indices +// returns -1 in case of failure +F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_decimator, F32 error_threshold, bool sloppy) { - // Allow LoD from -1 to LLModel::LOD_PHYSICS - if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) + // Figure out buffer size + S32 size_indices = 0; + S32 size_vertices = 0; + + for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx) { - std::ostringstream out; - out << "Invalid level of detail: " << which_lod; - LL_WARNS() << out.str() << LL_ENDL; - LLFloaterModelPreview::addStringToLog(out, false); - assert(which_lod >= -1 && which_lod < LLModel::NUM_LODS); - return; + const LLVolumeFace &face = base_model->getVolumeFace(face_idx); + size_indices += face.mNumIndices; + size_vertices += face.mNumVertices; } - if (mBaseModel.empty()) + if (size_indices < 3) { - return; + return -1; } - LLVertexBuffer::unbind(); + // Allocate buffers, note that we are using U32 buffer instead of U16 + U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); + U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32)); - bool no_ff = LLGLSLShader::sNoFixedFunction; - LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; - LLGLSLShader::sNoFixedFunction = false; + // extra space for normals and text coords + S32 tc_bytes_size = ((size_vertices * sizeof(LLVector2)) + 0xF) & ~0xF; + LLVector4a* combined_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); + LLVector4a* combined_normals = combined_positions + size_vertices; + LLVector2* combined_tex_coords = (LLVector2*)(combined_normals + size_vertices); - if (shader) + // copy indices and vertices into new buffers + S32 combined_positions_shift = 0; + S32 indices_idx_shift = 0; + S32 combined_indices_shift = 0; + for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx) { - shader->unbind(); - } + const LLVolumeFace &face = base_model->getVolumeFace(face_idx); - stop_gloderror(); - static U32 cur_name = 1; + // vertices + S32 copy_bytes = face.mNumVertices * sizeof(LLVector4a); + LLVector4a::memcpyNonAliased16((F32*)(combined_positions + combined_positions_shift), (F32*)face.mPositions, copy_bytes); - S32 limit = -1; + // normals + LLVector4a::memcpyNonAliased16((F32*)(combined_normals + combined_positions_shift), (F32*)face.mNormals, copy_bytes); - U32 triangle_count = 0; + // tex coords + copy_bytes = face.mNumVertices * sizeof(LLVector2); + memcpy((void*)(combined_tex_coords + combined_positions_shift), (void*)face.mTexCoords, copy_bytes); - U32 instanced_triangle_count = 0; + combined_positions_shift += face.mNumVertices; - //get the triangle count for the whole scene - for (LLModelLoader::scene::iterator iter = mBaseScene.begin(), endIter = mBaseScene.end(); iter != endIter; ++iter) - { - for (LLModelLoader::model_instance_list::iterator instance = iter->second.begin(), end_instance = iter->second.end(); instance != end_instance; ++instance) + // indices, sadly can't do dumb memcpy for indices, need to adjust each value + for (S32 i = 0; i < face.mNumIndices; ++i) { - LLModel* mdl = instance->mModel; - if (mdl) - { - instanced_triangle_count += mdl->getNumTriangles(); - } + U16 idx = face.mIndices[i]; + + combined_indices[combined_indices_shift] = idx + indices_idx_shift; + combined_indices_shift++; } + indices_idx_shift += face.mNumVertices; } - //get the triangle count for the non-instanced set of models - for (U32 i = 0; i < mBaseModel.size(); ++i) + // Now that we have buffers, optimize + S32 target_indices = 0; + F32 result_error = 0; // how far from original the model is, 1 == 100% + S32 new_indices = 0; + + if (indices_decimator > 0) { - triangle_count += mBaseModel[i]->getNumTriangles(); + target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle } + else // indices_decimator can be zero for error_threshold based calculations + { + target_indices = 3; + } + new_indices = LLMeshOptimizer::simplifyU32( + output_indices, + combined_indices, + size_indices, + combined_positions, + size_vertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], + target_indices, + error_threshold, + sloppy, + &result_error); - //get ratio of uninstanced triangles to instanced triangles - F32 triangle_ratio = (F32)triangle_count / (F32)instanced_triangle_count; - U32 base_triangle_count = triangle_count; + if (result_error < 0) + { + LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << size_indices << LL_ENDL; + } - U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; + if (new_indices < 3) + { + // Model should have at least one visible triangle + ll_aligned_free<64>(combined_positions); + ll_aligned_free_32(output_indices); + ll_aligned_free_32(combined_indices); - U32 lod_mode = 0; + return -1; + } - F32 lod_error_threshold = 0; + // repack back into individual faces - // The LoD should be in range from Lowest to High - if (which_lod > -1 && which_lod < NUM_LOD) + LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size); + LLVector4a* buffer_normals = buffer_positions + size_vertices; + LLVector2* buffer_tex_coords = (LLVector2*)(buffer_normals + size_vertices); + S32 buffer_idx_size = (size_indices * sizeof(U16) + 0xF) & ~0xF; + U16* buffer_indices = (U16*)ll_aligned_malloc_16(buffer_idx_size); + S32* old_to_new_positions_map = new S32[size_vertices]; + + S32 buf_positions_copied = 0; + S32 buf_indices_copied = 0; + indices_idx_shift = 0; + S32 valid_faces = 0; + + // Crude method to copy indices back into face + for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx) { - LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]); - if (iface) + const LLVolumeFace &face = base_model->getVolumeFace(face_idx); + + // reset data for new run + buf_positions_copied = 0; + buf_indices_copied = 0; + bool copy_triangle = false; + S32 range = indices_idx_shift + face.mNumVertices; + + for (S32 i = 0; i < size_vertices; i++) { - lod_mode = iface->getFirstSelectedIndex(); + old_to_new_positions_map[i] = -1; } - lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal(); + // Copy relevant indices and vertices + for (S32 i = 0; i < new_indices; ++i) + { + U32 idx = output_indices[i]; + + if ((i % 3) == 0) + { + copy_triangle = idx >= indices_idx_shift && idx < range; + } + + if (copy_triangle) + { + if (old_to_new_positions_map[idx] == -1) + { + // New position, need to copy it + // Validate size + if (buf_positions_copied >= U16_MAX) + { + // Normally this shouldn't happen since the whole point is to reduce amount of vertices + // but it might happen if user tries to run optimization with too large triangle or error value + // so fallback to 'per face' mode or verify requested limits and copy base model as is. + LL_WARNS() << "Over triangle limit. Failed to optimize in 'per object' mode, falling back to per face variant for" + << " model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << size_indices + << " error treshold: " << error_threshold + << LL_ENDL; + + // U16 vertices overflow shouldn't happen, but just in case + new_indices = 0; + valid_faces = 0; + for (U32 face_idx = 0; face_idx < base_model->getNumVolumeFaces(); ++face_idx) + { + genMeshOptimizerPerFace(base_model, target_model, face_idx, indices_decimator, error_threshold, false); + const LLVolumeFace &face = target_model->getVolumeFace(face_idx); + new_indices += face.mNumIndices; + if (face.mNumIndices >= 3) + { + valid_faces++; + } + } + if (valid_faces) + { + return (F32)size_indices / (F32)new_indices; + } + else + { + return -1; + } + } + + // Copy vertice, normals, tcs + buffer_positions[buf_positions_copied] = combined_positions[idx]; + buffer_normals[buf_positions_copied] = combined_normals[idx]; + buffer_tex_coords[buf_positions_copied] = combined_tex_coords[idx]; + + old_to_new_positions_map[idx] = buf_positions_copied; + + buffer_indices[buf_indices_copied] = (U16)buf_positions_copied; + buf_positions_copied++; + } + else + { + // existing position + buffer_indices[buf_indices_copied] = (U16)old_to_new_positions_map[idx]; + } + buf_indices_copied++; + } + } + + if (buf_positions_copied >= U16_MAX) + { + break; + } + + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + //new_face = face; //temp + + if (buf_indices_copied < 3) + { + // face was optimized away + new_face.resizeIndices(3); + new_face.resizeVertices(1); + memset(new_face.mIndices, 0, sizeof(U16) * 3); + new_face.mPositions[0].clear(); // set first vertice to 0 + new_face.mNormals[0].clear(); + new_face.mTexCoords[0].setZero(); + } + else + { + new_face.resizeIndices(buf_indices_copied); + new_face.resizeVertices(buf_positions_copied); + + S32 idx_size = (buf_indices_copied * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)buffer_indices, idx_size); + + LLVector4a::memcpyNonAliased16((F32*)new_face.mPositions, (F32*)buffer_positions, buf_positions_copied * sizeof(LLVector4a)); + LLVector4a::memcpyNonAliased16((F32*)new_face.mNormals, (F32*)buffer_normals, buf_positions_copied * sizeof(LLVector4a)); + + U32 tex_size = (buf_positions_copied * sizeof(LLVector2) + 0xF)&~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mTexCoords, (F32*)buffer_tex_coords, tex_size); + + valid_faces++; + } + + indices_idx_shift += face.mNumVertices; } - if (which_lod != -1) + delete[]old_to_new_positions_map; + ll_aligned_free<64>(combined_positions); + ll_aligned_free<64>(buffer_positions); + ll_aligned_free_32(output_indices); + ll_aligned_free_16(buffer_indices); + ll_aligned_free_32(combined_indices); + + if (new_indices < 3 || valid_faces == 0) { - mRequestedLoDMode[which_lod] = lod_mode; + // Model should have at least one visible triangle + return -1; } - if (lod_mode == 0) + return (F32)size_indices / (F32)new_indices; +} + +F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_decimator, F32 error_threshold, bool sloppy) +{ + const LLVolumeFace &face = base_model->getVolumeFace(face_idx); + S32 size_indices = face.mNumIndices; + if (size_indices < 3) { - lod_mode = GLOD_TRIANGLE_BUDGET; + return -1; + } + // todo: do not allocate per each face, add one large buffer somewhere + // faces have limited amount of indices + S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF; + U16* output = (U16*)ll_aligned_malloc_16(size); - // The LoD should be in range from Lowest to High - if (which_lod > -1 && which_lod < NUM_LOD) + S32 target_indices = 0; + F32 result_error = 0; // how far from original the model is, 1 == 100% + S32 new_indices = 0; + + if (indices_decimator > 0) + { + target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle + } + else + { + target_indices = 3; + } + new_indices = LLMeshOptimizer::simplify( + output, + face.mIndices, + size_indices, + face.mPositions, + face.mNumVertices, + LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_VERTEX], + target_indices, + error_threshold, + sloppy, + &result_error); + + + if (result_error < 0) + { + LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " new Indices: " << new_indices + << " original count: " << size_indices + << " error treshold: " << error_threshold + << LL_ENDL; + } + + LLVolumeFace &new_face = target_model->getVolumeFace(face_idx); + + // Copy old values + new_face = face; + + + if (new_indices < 3) + { + if (!sloppy) { - limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger(); - //convert from "scene wide" to "non-instanced" triangle limit - limit = (S32)((F32)limit*triangle_ratio); + // meshopt_optimizeSloppy() can optimize triangles away even if target_indices is > 2, + // but optimize() isn't supposed to + LL_INFOS() << "No indices generated by meshoptimizer for face " << face_idx + << " of model " << target_model->mLabel + << " target Indices: " << target_indices + << " original count: " << size_indices + << " error treshold: " << error_threshold + << LL_ENDL; } + + // Face got optimized away + // Generate empty triangle + new_face.resizeIndices(3); + new_face.resizeVertices(1); + memset(new_face.mIndices, 0, sizeof(U16) * 3); + new_face.mPositions[0].clear(); // set first vertice to 0 + new_face.mNormals[0].clear(); + new_face.mTexCoords[0].setZero(); } else { - lod_mode = GLOD_ERROR_THRESHOLD; - } + // Assign new values + new_face.resizeIndices(new_indices); // will wipe out mIndices, so new_face can't substitute output + S32 idx_size = (new_indices * sizeof(U16) + 0xF) & ~0xF; + LLVector4a::memcpyNonAliased16((F32*)new_face.mIndices, (F32*)output, idx_size); - bool object_dirty = false; + // clear unused values + new_face.optimize(); + } - if (mGroup == 0) + ll_aligned_free_16(output); + + if (new_indices < 3) { - object_dirty = true; - mGroup = cur_name++; - glodNewGroup(mGroup); + // At least one triangle is needed + return -1; } - if (object_dirty) + return (F32)size_indices / (F32)new_indices; +} + +void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation, bool enforce_tri_limit) +{ + LL_INFOS() << "Generating lod " << which_lod << " using meshoptimizer" << LL_ENDL; + // Allow LoD from -1 to LLModel::LOD_PHYSICS + if (which_lod < -1 || which_lod > LLModel::NUM_LODS - 1) { - for (LLModelLoader::model_list::iterator iter = mBaseModel.begin(); iter != mBaseModel.end(); ++iter) - { //build GLOD objects for each model in base model list - LLModel* mdl = *iter; + std::ostringstream out; + out << "Invalid level of detail: " << which_lod; + LL_WARNS() << out.str() << LL_ENDL; + LLFloaterModelPreview::addStringToLog(out, false); + assert(lod >= -1 && lod < LLModel::NUM_LODS); + return; + } - if (mObject[mdl] != 0) - { - glodDeleteObject(mObject[mdl]); - } + if (mBaseModel.empty()) + { + return; + } - mObject[mdl] = cur_name++; + //get the triangle count for all base models + S32 base_triangle_count = 0; + for (S32 i = 0; i < mBaseModel.size(); ++i) + { + base_triangle_count += mBaseModel[i]->getNumTriangles(); + } - glodNewObject(mObject[mdl], mGroup, GLOD_DISCRETE); - stop_gloderror(); + // Urgh... + // TODO: add interface to mFMP to get error treshold or let mFMP write one into LLModelPreview + // We should not be accesing views from other class! + U32 lod_mode = LIMIT_TRIANGLES; + F32 indices_decimator = 0; + F32 triangle_limit = 0; + F32 lod_error_threshold = 1; //100% - if (iter == mBaseModel.begin() && !mdl->mSkinWeights.empty()) - { //regenerate vertex buffer for skinned models to prevent animation feedback during LOD generation - mVertexBuffer[5].clear(); - } + // If requesting a single lod + if (which_lod > -1 && which_lod < NUM_LOD) + { + LLCtrlSelectionInterface* iface = mFMP->childGetSelectionInterface("lod_mode_" + lod_name[which_lod]); + if (iface) + { + lod_mode = iface->getFirstSelectedIndex(); + } - if (mVertexBuffer[5].empty()) + if (lod_mode == LIMIT_TRIANGLES) + { + if (!enforce_tri_limit) { - genBuffers(5, false); - } + triangle_limit = base_triangle_count; + // reset to default value for this lod + F32 pw = pow((F32)decimation, (F32)(LLModel::LOD_HIGH - which_lod)); - U32 tri_count = 0; - for (U32 i = 0; i < mVertexBuffer[5][mdl].size(); ++i) + triangle_limit /= pw; //indices_ratio can be 1/pw + } + else { - LLVertexBuffer* buff = mVertexBuffer[5][mdl][i]; - buff->setBuffer(type_mask & buff->getTypeMask()); - U32 num_indices = mVertexBuffer[5][mdl][i]->getNumIndices(); - if (num_indices > 2) - { - glodInsertElements(mObject[mdl], i, GL_TRIANGLES, num_indices, GL_UNSIGNED_SHORT, (U8*)mVertexBuffer[5][mdl][i]->getIndicesPointer(), 0, 0.f); - } - tri_count += num_indices / 3; - stop_gloderror(); - } + // UI spacifies limit for all models of single lod + triangle_limit = mFMP->childGetValue("lod_triangle_limit_" + lod_name[which_lod]).asInteger(); - glodBuildObject(mObject[mdl]); - stop_gloderror(); + } + // meshoptimizer doesn't use triangle limit, it uses indices limit, so convert it to aproximate ratio + // triangle_limit can be 0. + indices_decimator = (F32)base_triangle_count / llmax(triangle_limit, 1.f); } + else + { + // UI shows 0 to 100%, but meshoptimizer works with 0 to 1 + lod_error_threshold = mFMP->childGetValue("lod_error_threshold_" + lod_name[which_lod]).asReal() / 100.f; + } + } + else + { + // we are genrating all lods and each lod will get own indices_decimator + indices_decimator = 1; + triangle_limit = base_triangle_count; } + mMaxTriangleLimit = base_triangle_count; + + // Build models S32 start = LLModel::LOD_HIGH; S32 end = 0; if (which_lod != -1) { - start = end = which_lod; + start = which_lod; + end = which_lod; } - mMaxTriangleLimit = base_triangle_count; - for (S32 lod = start; lod >= end; --lod) { if (which_lod == -1) { + // we are genrating all lods and each lod gets own indices_ratio if (lod < start) { - triangle_count /= decimation; - } - } - else - { - if (enforce_tri_limit) - { - triangle_count = limit; - } - else - { - for (S32 j = LLModel::LOD_HIGH; j>which_lod; --j) - { - triangle_count /= decimation; - } + indices_decimator *= decimation; + triangle_limit /= decimation; } } + mRequestedTriangleCount[lod] = triangle_limit; + mRequestedErrorThreshold[lod] = lod_error_threshold * 100; + mRequestedLoDMode[lod] = lod_mode; + mModel[lod].clear(); mModel[lod].resize(mBaseModel.size()); mVertexBuffer[lod].clear(); - U32 actual_tris = 0; - U32 actual_verts = 0; - U32 submeshes = 0; - - mRequestedTriangleCount[lod] = (S32)((F32)triangle_count / triangle_ratio); - mRequestedErrorThreshold[lod] = lod_error_threshold; - - glodGroupParameteri(mGroup, GLOD_ADAPT_MODE, lod_mode); - stop_gloderror(); - - glodGroupParameteri(mGroup, GLOD_ERROR_MODE, GLOD_OBJECT_SPACE_ERROR); - stop_gloderror(); - - glodGroupParameterf(mGroup, GLOD_OBJECT_SPACE_ERROR_THRESHOLD, lod_error_threshold); - stop_gloderror(); - - if (lod_mode != GLOD_TRIANGLE_BUDGET) - { - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, 0); - } - else - { - //SH-632: always add 1 to desired amount to avoid decimating below desired amount - glodGroupParameteri(mGroup, GLOD_MAX_TRIANGLES, triangle_count + 1); - } - - stop_gloderror(); - glodAdaptGroup(mGroup); - stop_gloderror(); for (U32 mdl_idx = 0; mdl_idx < mBaseModel.size(); ++mdl_idx) { LLModel* base = mBaseModel[mdl_idx]; - GLint patch_count = 0; - glodGetObjectParameteriv(mObject[base], GLOD_NUM_PATCHES, &patch_count); - stop_gloderror(); - LLVolumeParams volume_params; volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE); mModel[lod][mdl_idx] = new LLModel(volume_params, 0.f); @@ -1517,74 +1703,159 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim mModel[lod][mdl_idx]->mLabel = name; mModel[lod][mdl_idx]->mSubmodelID = base->mSubmodelID; - - GLint* sizes = new GLint[patch_count * 2]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_SIZES, sizes); - stop_gloderror(); - - GLint* names = new GLint[patch_count]; - glodGetObjectParameteriv(mObject[base], GLOD_PATCH_NAMES, names); - stop_gloderror(); - - mModel[lod][mdl_idx]->setNumVolumeFaces(patch_count); + mModel[lod][mdl_idx]->setNumVolumeFaces(base->getNumVolumeFaces()); LLModel* target_model = mModel[lod][mdl_idx]; - for (GLint i = 0; i < patch_count; ++i) + S32 model_meshopt_mode = meshopt_mode; + + // Ideally this should run not per model, + // but combine all submodels with origin model as well + if (model_meshopt_mode == MESH_OPTIMIZER_COMBINE) { - type_mask = mVertexBuffer[5][base][i]->getTypeMask(); + // Run meshoptimizer for each model/object, up to 8 faces in one model. - LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(type_mask, 0); + // Ideally this should run not per model, + // but combine all submodels with origin model as well + F32 res = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + if (res < 0) + { + target_model->copyVolumeFaces(base); + } + } - if (sizes[i * 2 + 1] > 0 && sizes[i * 2] > 0) + if (model_meshopt_mode == MESH_OPTIMIZER_SLOPPY) + { + // Run meshoptimizer for each face + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) { - if (!buff->allocateBuffer(sizes[i * 2 + 1], sizes[i * 2], true)) + if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true) < 0) { - // Todo: find a way to stop preview in this case instead of crashing - LL_ERRS() << "Failed buffer allocation during preview LOD generation." - << " Vertices: " << sizes[i * 2 + 1] - << " Indices: " << sizes[i * 2] << LL_ENDL; + // Sloppy failed and returned an invalid model + genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false); } - buff->setBuffer(type_mask); - glodFillElements(mObject[base], names[i], GL_UNSIGNED_SHORT, (U8*)buff->getIndicesPointer()); - stop_gloderror(); } - else + } + + if (model_meshopt_mode == MESH_OPTIMIZER_AUTO) + { + // Switches between 'combine' method and 'sloppy' based on combine's result. + F32 allowed_ratio_drift = 2.f; + F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + + if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator)) { - // This face was eliminated or we failed to allocate buffer, - // attempt to create a dummy triangle (one vertex, 3 indices, all 0) - buff->allocateBuffer(1, 3, true); - memset((U8*)buff->getMappedData(), 0, buff->getSize()); - memset((U8*)buff->getIndicesPointer(), 0, buff->getIndicesSize()); - } + // Try sloppy variant if normal one failed to simplify model enough. + // Sloppy variant can fail entirely and has issues with precision, + // so code needs to do multiple attempts with different decimators. + // Todo: this is a bit of a mess, needs to be refined and improved + F32 last_working_decimator = 0.f; + F32 last_working_ratio = F32_MAX; - buff->validateRange(0, buff->getNumVerts() - 1, buff->getNumIndices(), 0); + F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); - LLStrider<LLVector3> pos; - LLStrider<LLVector3> norm; - LLStrider<LLVector2> tc; - LLStrider<U16> index; + if (sloppy_ratio > 0) + { + // Would be better to do a copy of target_model here, but if + // we need to use sloppy decimation, model should be cheap + // and fast to generate and it won't affect end result + last_working_decimator = indices_decimator; + last_working_ratio = sloppy_ratio; + } - buff->getVertexStrider(pos); - if (type_mask & LLVertexBuffer::MAP_NORMAL) - { - buff->getNormalStrider(norm); - } - if (type_mask & LLVertexBuffer::MAP_TEXCOORD0) - { - buff->getTexCoord0Strider(tc); - } + // Sloppy has a tendecy to error into lower side, so a request for 100 + // triangles turns into ~70, so check for significant difference from target decimation + F32 sloppy_ratio_drift = 1.4f; + if (lod_mode == LIMIT_TRIANGLES + && (sloppy_ratio > indices_decimator * sloppy_ratio_drift || sloppy_ratio < 0)) + { + // Apply a correction to compensate. + + // (indices_decimator / res_ratio) by itself is likely to overshoot to a differend + // side due to overal lack of precision, and we don't need an ideal result, which + // likely does not exist, just a better one, so a partial correction is enough. + F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2; + sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true); + } + + if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio) + { + // Compensation didn't work, return back to previous decimator + sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true); + } + + if (sloppy_ratio < 0) + { + // Sloppy method didn't work, try with smaller decimation values + S32 size_vertices = 0; + + for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx) + { + const LLVolumeFace &face = base->getVolumeFace(face_idx); + size_vertices += face.mNumVertices; + } + + // Complex models aren't supposed to get here, they are supposed + // to work on a first try of sloppy due to having more viggle room. + // If they didn't, something is likely wrong, no point locking the + // thread in a long calculation that will fail. + const U32 too_many_vertices = 27000; + if (size_vertices > too_many_vertices) + { + LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL; + } + else + { + // Find a decimator that does work + F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3 + F32 sloppy_decimator = indices_decimator / sloppy_decimation_step; - buff->getIndexStrider(index); + while (sloppy_ratio < 0 + && sloppy_decimator > precise_ratio + && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case + { + sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true); + sloppy_decimator = sloppy_decimator / sloppy_decimation_step; + } + } + } - target_model->setVolumeFaceData(names[i], pos, norm, tc, index, buff->getNumVerts(), buff->getNumIndices()); - actual_tris += buff->getNumIndices() / 3; - actual_verts += buff->getNumVerts(); - ++submeshes; + if (sloppy_ratio < 0 || sloppy_ratio < precise_ratio) + { + // Sloppy variant failed to generate triangles or is worse. + // Can happen with models that are too simple as is. - if (!validate_face(target_model->getVolumeFace(names[i]))) + if (precise_ratio < 0) + { + // Precise method failed as well, just copy face over + target_model->copyVolumeFaces(base); + precise_ratio = 1.f; + } + else + { + // Fallback to normal method + precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false); + } + + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " resulting ratio " << precise_ratio + << " simplified using per model method." << LL_ENDL; + } + else + { + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " resulting ratio " << sloppy_ratio + << " sloppily simplified using per model method." << LL_ENDL; + } + } + else { - LL_ERRS() << "Invalid face generated during LOD generation." << LL_ENDL; + LL_INFOS() << "Model " << target_model->getName() + << " lod " << which_lod + << " resulting ratio " << precise_ratio + << " simplified using per model method." << LL_ENDL; } } @@ -1594,6 +1865,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim target_model->mPosition = base->mPosition; target_model->mSkinWeights = base->mSkinWeights; target_model->mSkinInfo = base->mSkinInfo; + //copy material list target_model->mMaterialList = base->mMaterialList; @@ -1601,9 +1873,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim { LL_ERRS() << "Invalid model generated when creating LODs" << LL_ENDL; } - - delete[] sizes; - delete[] names; } //rebuild scene based on mBaseScene @@ -1629,13 +1898,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim } } } - - LLVertexBuffer::unbind(); - LLGLSLShader::sNoFixedFunction = no_ff; - if (shader) - { - shader->bind(); - } } void LLModelPreview::updateStatusMessages() @@ -2198,7 +2460,7 @@ void LLModelPreview::updateLodControls(S32 lod) S32 lod_mode = lod_combo->getCurrentIndex(); if (lod_mode == LOD_FROM_FILE) // LoD from file { - fmp->mLODMode[lod] = 0; + fmp->mLODMode[lod] = LOD_FROM_FILE; for (U32 i = 0; i < num_file_controls; ++i) { mFMP->childSetVisible(file_controls[i] + lod_name[lod], true); @@ -2211,7 +2473,7 @@ void LLModelPreview::updateLodControls(S32 lod) } else if (lod_mode == USE_LOD_ABOVE) // use LoD above { - fmp->mLODMode[lod] = 2; + fmp->mLODMode[lod] = USE_LOD_ABOVE; for (U32 i = 0; i < num_file_controls; ++i) { mFMP->childSetVisible(file_controls[i] + lod_name[lod], false); @@ -2237,7 +2499,7 @@ void LLModelPreview::updateLodControls(S32 lod) } else // auto generate, the default case for all LoDs except High { - fmp->mLODMode[lod] = 1; + fmp->mLODMode[lod] = MESH_OPTIMIZER_AUTO; //don't actually regenerate lod when refreshing UI mLODFrozen = true; @@ -2269,7 +2531,7 @@ void LLModelPreview::updateLodControls(S32 lod) threshold->setVisible(false); limit->setMaxValue(mMaxTriangleLimit); - limit->setIncrement(mMaxTriangleLimit / 32); + limit->setIncrement(llmax((U32)1, mMaxTriangleLimit / 32)); } else { @@ -2433,6 +2695,8 @@ void LLModelPreview::genBuffers(S32 lod, bool include_skin_weights) *(index_strider++) = vf.mIndices[i]; } + vb->flush(); + mVertexBuffer[lod][mdl].push_back(vb); vertex_count += num_vertices; @@ -2659,8 +2923,6 @@ BOOL LLModelPreview::render() LLMutexLock lock(this); mNeedsUpdate = FALSE; - bool use_shaders = LLGLSLShader::sNoFixedFunction; - bool edges = mViewOption["show_edges"]; bool joint_overrides = mViewOption["show_joint_overrides"]; bool joint_positions = mViewOption["show_joint_positions"]; @@ -2678,10 +2940,8 @@ BOOL LLModelPreview::render() LLGLDisable fog(GL_FOG); { - if (use_shaders) - { - gUIProgram.bind(); - } + gUIProgram.bind(); + //clear background to grey gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); @@ -2700,10 +2960,7 @@ BOOL LLModelPreview::render() gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); - if (use_shaders) - { - gUIProgram.unbind(); - } + gUIProgram.unbind(); } LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance; @@ -2854,10 +3111,7 @@ BOOL LLModelPreview::render() refresh(); } - if (use_shaders) - { - gObjectPreviewProgram.bind(); - } + gObjectPreviewProgram.bind(); gGL.loadIdentity(); gPipeline.enableLightsPreview(); @@ -2890,7 +3144,6 @@ BOOL LLModelPreview::render() { genBuffers(-1, skin_weight); //genBuffers(3); - //genLODs(); } if (!mModel[mPreviewLOD].empty()) @@ -2918,6 +3171,11 @@ BOOL LLModelPreview::render() genBuffers(mPreviewLOD, skin_weight); } + if (physics && mVertexBuffer[LLModel::LOD_PHYSICS].empty()) + { + genBuffers(LLModel::LOD_PHYSICS, false); + } + if (!skin_weight) { for (LLMeshUploadThread::instance_list::iterator iter = mUploadData.begin(); iter != mUploadData.end(); ++iter) @@ -2979,6 +3237,7 @@ BOOL LLModelPreview::render() glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glLineWidth(1.f); } + buffer->flush(); } gGL.popMatrix(); } @@ -3039,6 +3298,14 @@ BOOL LLModelPreview::render() if (!physics.mMesh.empty()) { //render hull instead of mesh + // SL-16993 physics.mMesh[i].mNormals were being used to light the exploded + // analyzed physics shape but the drawArrays() interface changed + // causing normal data <0,0,0> to be passed to the shader. + // The Phyics Preview shader uses plain vertex coloring so the physics hull is full lit. + // We could also use interface/ui shaders. + gObjectPreviewProgram.unbind(); + gPhysicsPreviewProgram.bind(); + for (U32 i = 0; i < physics.mMesh.size(); ++i) { if (explode > 0.f) @@ -3059,24 +3326,22 @@ BOOL LLModelPreview::render() } gGL.diffuseColor4ubv(hull_colors[i].mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions); if (explode > 0.f) { gGL.popMatrix(); } } + + gPhysicsPreviewProgram.unbind(); + gObjectPreviewProgram.bind(); } } } if (render_mesh) { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); if (pass > 0){ for (U32 i = 0; i < num_models; ++i) @@ -3096,6 +3361,8 @@ BOOL LLModelPreview::render() glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glLineWidth(1.f); + + buffer->flush(); } } } @@ -3140,11 +3407,6 @@ BOOL LLModelPreview::render() if (physics.mHull.empty()) { - if (mVertexBuffer[LLModel::LOD_PHYSICS].empty()) - { - genBuffers(LLModel::LOD_PHYSICS, false); - } - U32 num_models = mVertexBuffer[LLModel::LOD_PHYSICS][model].size(); for (U32 v = 0; v < num_models; ++v) { @@ -3171,6 +3433,8 @@ BOOL LLModelPreview::render() buffer->draw(LLRender::POINTS, 3, i); } } + + buffer->flush(); } } } @@ -3231,7 +3495,7 @@ BOOL LLModelPreview::render() LLJoint *joint = getPreviewAvatar()->getJoint(skin->mJointNums[j]); if (joint) { - const LLVector3& jointPos = skin->mAlternateBindMatrix[j].getTranslation(); + const LLVector3& jointPos = LLVector3(skin->mAlternateBindMatrix[j].getTranslation()); if (joint->aboveJointPosThreshold(jointPos)) { bool override_changed; @@ -3273,11 +3537,10 @@ BOOL LLModelPreview::render() //build matrix palette LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, joint_count, + LLSkinningUtil::initSkinningMatrixPalette(mat, joint_count, skin, getPreviewAvatar()); - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); + const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix; U32 max_joints = LLSkinningUtil::getMaxJointCount(); for (U32 j = 0; j < buffer->getNumVerts(); ++j) { @@ -3360,10 +3623,7 @@ BOOL LLModelPreview::render() } } - if (use_shaders) - { - gObjectPreviewProgram.unbind(); - } + gObjectPreviewProgram.unbind(); gGL.popMatrix(); @@ -3477,7 +3737,7 @@ bool LLModelPreview::lodQueryCallback() { S32 lod = preview->mLodsQuery.back(); preview->mLodsQuery.pop_back(); - preview->genLODs(lod); + preview->genMeshOptimizerLODs(lod, MESH_OPTIMIZER_AUTO); if (preview->mLookUpLodFiles && (lod == LLModel::LOD_HIGH)) { @@ -3492,12 +3752,13 @@ bool LLModelPreview::lodQueryCallback() return true; } -void LLModelPreview::onLODParamCommit(S32 lod, bool enforce_tri_limit) +void LLModelPreview::onLODMeshOptimizerParamCommit(S32 requested_lod, bool enforce_tri_limit, S32 mode) { if (!mLODFrozen) { - genLODs(lod, 3, enforce_tri_limit); + genMeshOptimizerLODs(requested_lod, mode, 3, enforce_tri_limit); refresh(); + mDirty = true; } } diff --git a/indra/newview/llmodelpreview.h b/indra/newview/llmodelpreview.h index 8e59c71a55..9e32215e6a 100644 --- a/indra/newview/llmodelpreview.h +++ b/indra/newview/llmodelpreview.h @@ -124,10 +124,18 @@ public: typedef enum { LOD_FROM_FILE = 0, - GENERATE, + MESH_OPTIMIZER_AUTO, // automatically selects method based on model or face + MESH_OPTIMIZER_COMBINE, // combines faces into a single model, simplifies, then splits back into faces + MESH_OPTIMIZER_SLOPPY, // uses sloppy method, works per face USE_LOD_ABOVE, } eLoDMode; + typedef enum + { + LIMIT_TRIANGLES = 0, + LIMIT_ERROR_TRESHOLD, + } eLoDLimit; + public: // Todo: model preview shouldn't need floater dependency, it // should just expose data to floater, not control flaoter like it does @@ -155,7 +163,7 @@ public: void loadModelCallback(S32 lod); bool lodsReady() { return !mGenLOD && mLodsQuery.empty(); } void queryLODs() { mGenLOD = true; }; - void genLODs(S32 which_lod = -1, U32 decimation = 3, bool enforce_tri_limit = false); + void genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 decimation = 3, bool enforce_tri_limit = false); void generateNormals(); void restoreNormals(); void updateDimentionsAndOffsets(); @@ -165,8 +173,7 @@ public: void clearIncompatible(S32 lod); void updateStatusMessages(); void updateLodControls(S32 lod); - void clearGLODGroup(); - void onLODParamCommit(S32 lod, bool enforce_tri_limit); + void onLODMeshOptimizerParamCommit(S32 lod, bool enforce_tri_limit, S32 mode); void addEmptyFace(LLModel* pTarget); const bool getModelPivot(void) const { return mHasPivot; } @@ -218,6 +225,14 @@ private: // Count amount of original models, excluding sub-models static U32 countRootModels(LLModelLoader::model_list models); + // Merges faces into single mesh, simplifies using mesh optimizer, + // then splits back into faces. + // Returns reached simplification ratio. -1 in case of a failure. + F32 genMeshOptimizerPerModel(LLModel *base_model, LLModel *target_model, F32 indices_ratio, F32 error_threshold, bool sloppy); + // Simplifies specified face using mesh optimizer. + // Returns reached simplification ratio. -1 in case of a failure. + F32 genMeshOptimizerPerFace(LLModel *base_model, LLModel *target_model, U32 face_idx, F32 indices_ratio, F32 error_threshold, bool sloppy); + protected: friend class LLModelLoader; friend class LLFloaterModelPreview; @@ -248,19 +263,11 @@ protected: std::map<std::string, bool> mViewOption; - //GLOD object parameters (must rebuild object if these change) + // Model generation parameters (must rebuild object if these change) bool mLODFrozen; - F32 mBuildShareTolerance; - U32 mBuildQueueMode; - U32 mBuildOperator; - U32 mBuildBorderMode; U32 mRequestedLoDMode[LLModel::NUM_LODS]; S32 mRequestedTriangleCount[LLModel::NUM_LODS]; F32 mRequestedErrorThreshold[LLModel::NUM_LODS]; - U32 mRequestedBuildOperator[LLModel::NUM_LODS]; - U32 mRequestedQueueMode[LLModel::NUM_LODS]; - U32 mRequestedBorderMode[LLModel::NUM_LODS]; - F32 mRequestedShareTolerance[LLModel::NUM_LODS]; F32 mRequestedCreaseAngle[LLModel::NUM_LODS]; LLModelLoader* mModelLoader; @@ -279,6 +286,8 @@ protected: U32 mGroup; std::map<LLPointer<LLModel>, U32> mObject; + + // Amount of triangles in original(base) model U32 mMaxTriangleLimit; LLMeshUploadThread::instance_list mUploadData; diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 112da55682..1240ce7c0f 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -147,6 +147,11 @@ void LLNetMap::setScale( F32 scale ) void LLNetMap::draw() { + if (!LLWorld::instanceExists()) + { + return; + } + LL_PROFILE_ZONE_SCOPED; static LLFrameTimer map_timer; static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white); static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white); @@ -258,7 +263,7 @@ void LLNetMap::draw() gGL.end(); // Draw water - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, ABOVE_WATERLINE_ALPHA / 255.f); + gGL.flush(); { if (regionp->getLand().getWaterTexture()) { @@ -275,7 +280,7 @@ void LLNetMap::draw() gGL.end(); } } - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.flush(); } // Redraw object layer periodically diff --git a/indra/newview/llnotificationofferhandler.cpp b/indra/newview/llnotificationofferhandler.cpp index 201eaeb9f8..3f22467544 100644 --- a/indra/newview/llnotificationofferhandler.cpp +++ b/indra/newview/llnotificationofferhandler.cpp @@ -166,14 +166,14 @@ bool LLOfferHandler::processNotification(const LLNotificationPtr& notification, /*virtual*/ void LLOfferHandler::onChange(LLNotificationPtr p) { - LLToastNotifyPanel* panelp = LLToastNotifyPanel::getInstance(p->getID()); + auto panelp = LLToastNotifyPanel::getInstance(p->getID()); if (panelp) { // // HACK: if we're dealing with a notification embedded in IM, update it // otherwise remove its toast // - if (dynamic_cast<LLIMToastNotifyPanel*>(panelp)) + if (dynamic_cast<LLIMToastNotifyPanel*>(panelp.get())) { panelp->updateNotification(); } diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp index 43c3ee3ce2..bb39d8f362 100644 --- a/indra/newview/llnotificationscripthandler.cpp +++ b/indra/newview/llnotificationscripthandler.cpp @@ -69,7 +69,8 @@ void LLScriptHandler::initChannel() //-------------------------------------------------------------------------- void LLScriptHandler::addToastWithNotification(const LLNotificationPtr& notification) { - LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification); + LL_PROFILE_ZONE_SCOPED + LLToastPanel* notify_box = LLToastPanel::buidPanelFromNotification(notification); LLToast::Params p; p.notif_id = notification->getID(); diff --git a/indra/newview/llpersistentnotificationstorage.cpp b/indra/newview/llpersistentnotificationstorage.cpp index 18888f2723..9bc77393dc 100644 --- a/indra/newview/llpersistentnotificationstorage.cpp +++ b/indra/newview/llpersistentnotificationstorage.cpp @@ -47,11 +47,9 @@ LLPersistentNotificationStorage::~LLPersistentNotificationStorage() { } -static LLTrace::BlockTimerStatHandle FTM_SAVE_NOTIFICATIONS("Save Notifications"); - void LLPersistentNotificationStorage::saveNotifications() { - LL_RECORD_BLOCK_TIME(FTM_SAVE_NOTIFICATIONS); + LL_PROFILE_ZONE_SCOPED; boost::intrusive_ptr<LLPersistentNotificationChannel> history_channel = boost::dynamic_pointer_cast<LLPersistentNotificationChannel>(LLNotifications::instance().getChannel("Persistent")); if (!history_channel) @@ -90,11 +88,9 @@ void LLPersistentNotificationStorage::saveNotifications() writeNotifications(output); } -static LLTrace::BlockTimerStatHandle FTM_LOAD_NOTIFICATIONS("Load Notifications"); - void LLPersistentNotificationStorage::loadNotifications() { - LL_RECORD_BLOCK_TIME(FTM_LOAD_NOTIFICATIONS); + LL_PROFILE_ZONE_SCOPED; LL_INFOS("LLPersistentNotificationStorage") << "start loading notifications" << LL_ENDL; diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp index f48ce680fd..03a02ba26f 100644 --- a/indra/newview/llphysicsmotion.cpp +++ b/indra/newview/llphysicsmotion.cpp @@ -453,6 +453,7 @@ F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local, const BOOL LLPhysicsMotionController::onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; // Skip if disabled globally. if (!gSavedSettings.getBOOL("AvatarPhysics")) { diff --git a/indra/newview/llscenemonitor.cpp b/indra/newview/llscenemonitor.cpp index f9baf5fbd3..2e44dc1459 100644 --- a/indra/newview/llscenemonitor.cpp +++ b/indra/newview/llscenemonitor.cpp @@ -271,7 +271,7 @@ void LLSceneMonitor::capture() static LLCachedControl<F32> scene_load_sample_time(gSavedSettings, "SceneLoadingMonitorSampleTime"); static bool force_capture = true; - bool enabled = LLGLSLShader::sNoFixedFunction && (monitor_enabled || mDebugViewerVisible); + bool enabled = monitor_enabled || mDebugViewerVisible; if(mEnabled != enabled) { if(mEnabled) @@ -332,9 +332,6 @@ bool LLSceneMonitor::needsUpdate() const return mDiffState == NEED_DIFF; } -static LLTrace::BlockTimerStatHandle FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE("Generate Scene Load Dither Texture"); -static LLTrace::BlockTimerStatHandle FTM_SCENE_LOAD_IMAGE_DIFF("Scene Load Image Diff"); - static LLStaticHashedString sDitherScale("dither_scale"); static LLStaticHashedString sDitherScaleS("dither_scale_s"); static LLStaticHashedString sDitherScaleT("dither_scale_t"); @@ -356,14 +353,12 @@ void LLSceneMonitor::compare() return; } - LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF); mDiffState = EXECUTE_DIFF; S32 width = gViewerWindow->getWindowWidthRaw(); S32 height = gViewerWindow->getWindowHeightRaw(); if(!mDiff) { - LL_RECORD_BLOCK_TIME(FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE); mDiff = new LLRenderTarget(); mDiff->allocate(width, height, GL_RGBA, false, false, LLTexUnit::TT_TEXTURE, true); @@ -371,7 +366,6 @@ void LLSceneMonitor::compare() } else if(mDiff->getWidth() != width || mDiff->getHeight() != height) { - LL_RECORD_BLOCK_TIME(FTM_GENERATE_SCENE_LOAD_DITHER_TEXTURE); mDiff->resize(width, height); generateDitheringTexture(width, height); } @@ -427,8 +421,6 @@ void LLSceneMonitor::calcDiffAggregate() { #ifdef LL_WINDOWS - LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF); - if(mDiffState != EXECUTE_DIFF && !mDebugViewerVisible) { return; @@ -481,8 +473,6 @@ void LLSceneMonitor::calcDiffAggregate() static LLTrace::EventStatHandle<> sFramePixelDiff("FramePixelDifference"); void LLSceneMonitor::fetchQueryResult() { - LL_RECORD_BLOCK_TIME(FTM_SCENE_LOAD_IMAGE_DIFF); - // also throttle timing here, to avoid going below sample time due to phasing with frame capture static LLCachedControl<F32> scene_load_sample_time_control(gSavedSettings, "SceneLoadingMonitorSampleTime"); F32Seconds scene_load_sample_time = (F32Seconds)scene_load_sample_time_control(); @@ -729,13 +719,6 @@ void LLSceneMonitorView::onTeleportFinished() void LLSceneMonitorView::onVisibilityChange(BOOL visible) { - if (!LLGLSLShader::sNoFixedFunction && visible) - { - visible = false; - // keep Scene monitor and its view in sycn - setVisible(false); - LL_WARNS("SceneMonitor") << "Incompatible graphical settings, Scene Monitor can't be turned on" << LL_ENDL; - } LLSceneMonitor::getInstance()->setDebugViewerVisible(visible); } diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp index 681787bcbe..17f2970f99 100644 --- a/indra/newview/llscreenchannel.cpp +++ b/indra/newview/llscreenchannel.cpp @@ -49,10 +49,9 @@ using namespace LLNotificationsUI; bool LLScreenChannel::mWasStartUpToastShown = false; -LLTrace::BlockTimerStatHandle FTM_GET_CHANNEL_RECT("Calculate Notification Channel Region"); LLRect LLScreenChannelBase::getChannelRect() { - LL_RECORD_BLOCK_TIME(FTM_GET_CHANNEL_RECT); + LL_PROFILE_ZONE_SCOPED; if (mFloaterSnapRegion == NULL) { @@ -259,7 +258,8 @@ void LLScreenChannel::updatePositionAndSize(LLRect new_world_rect) //-------------------------------------------------------------------------- void LLScreenChannel::addToast(const LLToast::Params& p) { - bool store_toast = false, show_toast = false; + LL_PROFILE_ZONE_SCOPED + bool store_toast = false, show_toast = false; if (mDisplayToastsAlways) { diff --git a/indra/newview/llscripteditor.cpp b/indra/newview/llscripteditor.cpp index cd3a4dfd11..c6bb2f19dd 100644 --- a/indra/newview/llscripteditor.cpp +++ b/indra/newview/llscripteditor.cpp @@ -138,11 +138,9 @@ void LLScriptEditor::initKeywords() mKeywords.initialize(LLSyntaxIdLSL::getInstance()->getKeywordsXML()); } -LLTrace::BlockTimerStatHandle FTM_SYNTAX_HIGHLIGHTING("Syntax Highlighting"); - void LLScriptEditor::loadKeywords() { - LL_RECORD_BLOCK_TIME(FTM_SYNTAX_HIGHLIGHTING); + LL_PROFILE_ZONE_SCOPED; mKeywords.processTokens(); segment_vec_t segment_list; @@ -160,7 +158,7 @@ void LLScriptEditor::updateSegments() { if (mReflowIndex < S32_MAX && mKeywords.isLoaded() && mParseOnTheFly) { - LL_RECORD_BLOCK_TIME(FTM_SYNTAX_HIGHLIGHTING); + LL_PROFILE_ZONE_SCOPED; // HACK: No non-ascii keywords for now segment_vec_t segment_list; mKeywords.findSegments(&segment_list, getWText(), mDefaultColor.get(), *this); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 7ed2d7ef62..82a165cb35 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -209,8 +209,6 @@ void LLSelectMgr::cleanupGlobals() LLSelectMgr::getInstance()->clearSelections(); } -// Build time optimization, generate this function once here -template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance(); //----------------------------------------------------------------------------- // LLSelectMgr() //----------------------------------------------------------------------------- @@ -5898,8 +5896,6 @@ void LLSelectMgr::updateSilhouettes() LLViewerObject* objectp = *iter; objectp->clearChanged(LLXform::MOVED | LLXform::SILHOUETTE); } - - //gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } void LLSelectMgr::updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector<LLViewerObject*>& changed_objects) @@ -6624,7 +6620,7 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color) glFogfv(GL_FOG_COLOR, fogCol.mV); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.flush(); gGL.begin(LLRender::LINES); { gGL.color4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 2b00fa1595..ce0316e610 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -407,11 +407,8 @@ private: LLObjectSelectionHandle mSelectedObjects; }; -class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr> +class LLSelectMgr : public LLEditMenuHandler, public LLSimpleton<LLSelectMgr> { - LLSINGLETON(LLSelectMgr); - ~LLSelectMgr(); - public: static BOOL sRectSelectInclusive; // do we need to surround an object to pick it? static BOOL sRenderHiddenSelections; // do we show selection silhouettes that are occluded? @@ -437,6 +434,9 @@ public: LLCachedControl<bool> mDebugSelectMgr; public: + LLSelectMgr(); + ~LLSelectMgr(); + static void cleanupGlobals(); // LLEditMenuHandler interface diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 58cbe0e20a..14a9f4aa30 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -637,6 +637,7 @@ LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isA //------------------------------------------------------------------------- void LLSettingsVOSky::updateSettings() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; LLSettingsSky::updateSettings(); LLVector3 sun_direction = getSunDirection(); LLVector3 moon_direction = getMoonDirection(); @@ -665,55 +666,56 @@ void LLSettingsVOSky::updateSettings() void LLSettingsVOSky::applySpecial(void *ptarget, bool force) { - LLGLSLShader *shader = (LLGLSLShader *)ptarget; - + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; LLVector4 light_direction = LLEnvironment::instance().getClampedLightNorm(); - if (shader->mShaderGroup == LLGLSLShader::SG_DEFAULT) + LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_DEFAULT]; { - shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, light_direction.mV); - shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); + shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, light_direction); + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, LLViewerCamera::getInstance()->getOrigin()); } - else if (shader->mShaderGroup == LLGLSLShader::SG_SKY) + + shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_SKY]; { - shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, 1, light_direction.mV); + shader->uniform4fv(LLViewerShaderMgr::LIGHTNORM, light_direction); - // Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate") - LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]); - LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() ); + // Legacy? SETTING_CLOUD_SCROLL_RATE("cloud_scroll_rate") + LLVector4 vect_c_p_d1(mSettings[SETTING_CLOUD_POS_DENSITY1]); + LLVector4 cloud_scroll( LLEnvironment::instance().getCloudScrollDelta() ); - // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll - // Keep in Sync! - // * indra\newview\llsettingsvo.cpp - // * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl - // * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl - cloud_scroll[0] = -cloud_scroll[0]; - vect_c_p_d1 += cloud_scroll; - shader->uniform4fv(LLShaderMgr::CLOUD_POS_DENSITY1, 1, vect_c_p_d1.mV); + // SL-13084 EEP added support for custom cloud textures -- flip them horizontally to match the preview of Clouds > Cloud Scroll + // Keep in Sync! + // * indra\newview\llsettingsvo.cpp + // * indra\newview\app_settings\shaders\class2\windlight\cloudsV.glsl + // * indra\newview\app_settings\shaders\class1\deferred\cloudsV.glsl + cloud_scroll[0] = -cloud_scroll[0]; + vect_c_p_d1 += cloud_scroll; + shader->uniform4fv(LLShaderMgr::CLOUD_POS_DENSITY1, vect_c_p_d1); - LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - LLColor4 sunDiffuse = psky->getSunlightColor(); - LLColor4 moonDiffuse = psky->getMoonlightColor(); + LLVector4 sunDiffuse = LLVector4(psky->getSunlightColor().mV); + LLVector4 moonDiffuse = LLVector4(psky->getMoonlightColor().mV); - shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, sunDiffuse.mV); - shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, 1, moonDiffuse.mV); + shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, sunDiffuse); + shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, moonDiffuse); - LLColor4 cloud_color(psky->getCloudColor(), 1.0); - shader->uniform4fv(LLShaderMgr::CLOUD_COLOR, 1, cloud_color.mV); + LLVector4 cloud_color(LLVector3(psky->getCloudColor().mV), 1.0); + shader->uniform4fv(LLShaderMgr::CLOUD_COLOR, cloud_color); } + shader = &((LLShaderUniforms*)ptarget)[LLGLSLShader::SG_ANY]; shader->uniform1f(LLShaderMgr::SCENE_LIGHT_STRENGTH, mSceneLightStrength); LLColor4 ambient(getTotalAmbient()); - shader->uniform4fv(LLShaderMgr::AMBIENT, 1, ambient.mV); + shader->uniform4fv(LLShaderMgr::AMBIENT, LLVector4(ambient.mV)); shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, getIsSunUp() ? 1 : 0); shader->uniform1f(LLShaderMgr::SUN_MOON_GLOW_FACTOR, getSunMoonGlowFactor()); shader->uniform1f(LLShaderMgr::DENSITY_MULTIPLIER, getDensityMultiplier()); shader->uniform1f(LLShaderMgr::DISTANCE_MULTIPLIER, getDistanceMultiplier()); - F32 g = getGamma(); + F32 g = getGamma(); F32 display_gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); shader->uniform1f(LLShaderMgr::GAMMA, g); @@ -907,11 +909,13 @@ LLSD LLSettingsVOWater::convertToLegacy(const LLSettingsWater::ptr_t &pwater) //------------------------------------------------------------------------- void LLSettingsVOWater::applySpecial(void *ptarget, bool force) { - LLGLSLShader *shader = (LLGLSLShader *)ptarget; + LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; LLEnvironment& env = LLEnvironment::instance(); - if (force || (shader->mShaderGroup == LLGLSLShader::SG_WATER)) + auto group = LLGLSLShader::SG_WATER; + LLShaderUniforms* shader = &((LLShaderUniforms*)ptarget)[group]; + { F32 water_height = env.getWaterHeight(); @@ -935,7 +939,7 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force) LLVector4 waterPlane(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm)); - shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, 1, waterPlane.mV); + shader->uniform4fv(LLShaderMgr::WATER_WATERPLANE, waterPlane.mV); LLVector4 light_direction = env.getClampedLightNorm(); @@ -950,18 +954,19 @@ void LLSettingsVOWater::applySpecial(void *ptarget, bool force) shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, waterFogDensity); LLColor4 fog_color(env.getCurrentWater()->getWaterFogColor(), 0.0f); - shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV); + shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, fog_color.mV); F32 blend_factor = env.getCurrentWater()->getBlendFactor(); shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); // update to normal lightnorm, water shader itself will use rotated lightnorm as necessary - shader->uniform4fv(LLShaderMgr::LIGHTNORM, 1, light_direction.mV); + shader->uniform4fv(LLShaderMgr::LIGHTNORM, light_direction.mV); } } void LLSettingsVOWater::updateSettings() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; // base class clears dirty flag so as to not trigger recursive update LLSettingsBase::updateSettings(); diff --git a/indra/newview/llsettingsvo.h b/indra/newview/llsettingsvo.h index a1baf02fe7..05ec0e9275 100644 --- a/indra/newview/llsettingsvo.h +++ b/indra/newview/llsettingsvo.h @@ -101,8 +101,6 @@ public: bool isAdvanced() const { return m_isAdvanced; } - virtual void updateShader(LLGLSLShader* shader) { applySpecial(shader, true); } - protected: LLSettingsVOSky(); @@ -135,8 +133,6 @@ public: static LLSD convertToLegacy(const ptr_t &); - virtual void updateShader(LLGLSLShader* shader) { applySpecial(shader, true); } - protected: LLSettingsVOWater(); diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index e02b21f036..cf3519c1c7 100644 --- a/indra/newview/llskinningutil.cpp +++ b/indra/newview/llskinningutil.cpp @@ -35,7 +35,6 @@ #include "llrigginginfo.h" #define DEBUG_SKINNING LL_DEBUG -#define MAT_USE_SSE 1 void dump_avatar_and_skin_state(const std::string& reason, LLVOAvatar *avatar, const LLMeshSkinInfo *skin) { @@ -120,36 +119,26 @@ void LLSkinningUtil::scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin skin->mInvalidJointsScrubbed = true; } -#define MAT_USE_SSE 1 - void LLSkinningUtil::initSkinningMatrixPalette( - LLMatrix4* mat, + LLMatrix4a* mat, S32 count, const LLMeshSkinInfo* skin, LLVOAvatar *avatar) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + initJointNums(const_cast<LLMeshSkinInfo*>(skin), avatar); + + LLMatrix4a world[LL_CHARACTER_MAX_ANIMATED_JOINTS]; + for (U32 j = 0; j < count; ++j) { S32 joint_num = skin->mJointNums[j]; - LLJoint *joint = NULL; - if (joint_num >= 0 && joint_num < LL_CHARACTER_MAX_ANIMATED_JOINTS) - { - joint = avatar->getJoint(joint_num); - } - llassert(joint); + LLJoint *joint = avatar->getJoint(joint_num); + if (joint) { -#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 + world[j] = joint->getWorldMatrix4a(); } else { @@ -159,16 +148,27 @@ void LLSkinningUtil::initSkinningMatrixPalette( // 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; + 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; #endif dump_avatar_and_skin_state("initSkinningMatrixPalette joint not found", avatar, skin); } } + + //NOTE: pointer striders used here as a micro-optimization over vector/array lookups + const LLMatrix4a* invBind = &(skin->mInvBindMatrix[0]); + const LLMatrix4a* w = world; + LLMatrix4a* m = mat; + LLMatrix4a* end = m + count; + + while (m < end) + { + matMulUnsafe(*(invBind++), *(w++), *(m++)); + } } void LLSkinningUtil::checkSkinWeights(LLVector4a* weights, U32 num_vertices, const LLMeshSkinInfo* skin) @@ -212,7 +212,7 @@ void LLSkinningUtil::scrubSkinWeights(LLVector4a* weights, U32 num_vertices, con void LLSkinningUtil::getPerVertexSkinMatrix( F32* weights, - LLMatrix4a* mat, + const LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints) @@ -270,6 +270,7 @@ void LLSkinningUtil::initJointNums(LLMeshSkinInfo* skin, LLVOAvatar *avatar) { if (!skin->mJointNumsInitialized) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; for (U32 j = 0; j < skin->mJointNames.size(); ++j) { #if DEBUG_SKINNING @@ -357,13 +358,11 @@ void LLSkinningUtil::updateRiggingInfo(const LLMeshSkinInfo* skin, LLVOAvatar *a rig_info_tab[joint_num].setIsRiggedTo(true); // FIXME could precompute these matMuls. - LLMatrix4a bind_shape; - LLMatrix4a inv_bind; + const LLMatrix4a& bind_shape = skin->mBindShapeMatrix; + const LLMatrix4a& inv_bind = skin->mInvBindMatrix[joint_index]; LLMatrix4a mat; LLVector4a pos_joint_space; - bind_shape.loadu(skin->mBindShapeMatrix); - inv_bind.loadu(skin->mInvBindMatrix[joint_index]); matMul(bind_shape, inv_bind, mat); mat.affineTransform(pos, pos_joint_space); @@ -426,3 +425,4 @@ LLQuaternion LLSkinningUtil::getUnscaledQuaternion(const LLMatrix4& mat4) bind_rot.normalize(); return bind_rot; } + diff --git a/indra/newview/llskinningutil.h b/indra/newview/llskinningutil.h index efe7c85997..807418f983 100644 --- a/indra/newview/llskinningutil.h +++ b/indra/newview/llskinningutil.h @@ -42,10 +42,10 @@ namespace LLSkinningUtil S32 getMaxJointCount(); U32 getMeshJointCount(const LLMeshSkinInfo *skin); void scrubInvalidJoints(LLVOAvatar *avatar, LLMeshSkinInfo* skin); - 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 getPerVertexSkinMatrix(F32* weights, const LLMatrix4a* mat, bool handle_bad_scale, LLMatrix4a& final_mat, U32 max_joints); LL_FORCE_INLINE void getPerVertexSkinMatrixWithIndices( F32* weights, diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index efa4a7fd66..5c648c11e1 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -51,13 +51,9 @@ #include "llphysicsshapebuilderutil.h" #include "llvoavatar.h" #include "llvolumemgr.h" -#include "lltextureatlas.h" #include "llviewershadermgr.h" #include "llcontrolavatar.h" -static LLTrace::BlockTimerStatHandle FTM_FRUSTUM_CULL("Frustum Culling"); -static LLTrace::BlockTimerStatHandle FTM_CULL_REBOUND("Cull Rebound Partition"); - extern bool gShiftFrame; static U32 sZombieGroups = 0; @@ -131,129 +127,6 @@ LLSpatialGroup::~LLSpatialGroup() sNodeCount--; clearDrawMap(); - clearAtlasList() ; -} - -BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp) -{ - S8 type = atlasp->getComponents() - 1 ; - for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter) - { - if(atlasp == *iter) - { - return TRUE ; - } - } - return FALSE ; -} - -void LLSpatialGroup::addAtlas(LLTextureAtlas* atlasp, S8 recursive_level) -{ - if(!hasAtlas(atlasp)) - { - mAtlasList[atlasp->getComponents() - 1].push_back(atlasp) ; - atlasp->addSpatialGroup(this) ; - } - - --recursive_level; - if(recursive_level)//levels propagating up. - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - parent->addAtlas(atlasp, recursive_level) ; - } - } -} - -void LLSpatialGroup::removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group, S8 recursive_level) -{ - mAtlasList[atlasp->getComponents() - 1].remove(atlasp) ; - if(remove_group) - { - atlasp->removeSpatialGroup(this) ; - } - - --recursive_level; - if(recursive_level)//levels propagating up. - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - parent->removeAtlas(atlasp, recursive_level) ; - } - } -} - -void LLSpatialGroup::clearAtlasList() -{ - std::list<LLTextureAtlas*>::iterator iter ; - for(S8 i = 0 ; i < 4 ; i++) - { - if(mAtlasList[i].size() > 0) - { - for(iter = mAtlasList[i].begin(); iter != mAtlasList[i].end() ; ++iter) - { - ((LLTextureAtlas*)*iter)->removeSpatialGroup(this) ; - } - mAtlasList[i].clear() ; - } - } -} - -LLTextureAtlas* LLSpatialGroup::getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level) -{ - S8 type = ncomponents - 1 ; - if(mAtlasList[type].size() > 0) - { - for(std::list<LLTextureAtlas*>::iterator iter = mAtlasList[type].begin(); iter != mAtlasList[type].end() ; ++iter) - { - if(!((LLTextureAtlas*)*iter)->isFull(to_be_reserved)) - { - return *iter ; - } - } - } - - --recursive_level; - if(recursive_level) - { - LLSpatialGroup* parent = getParent() ; - if(parent) - { - return parent->getAtlas(ncomponents, to_be_reserved, recursive_level) ; - } - } - return NULL ; -} - -void LLSpatialGroup::setCurUpdatingSlot(LLTextureAtlasSlot* slotp) -{ - mCurUpdatingSlotp = slotp; - - //if(!hasAtlas(mCurUpdatingSlotp->getAtlas())) - //{ - // addAtlas(mCurUpdatingSlotp->getAtlas()) ; - //} -} - -LLTextureAtlasSlot* LLSpatialGroup::getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level) -{ - if(gFrameCount && mCurUpdatingTime == gFrameCount && mCurUpdatingTexture == imagep) - { - return mCurUpdatingSlotp ; - } - - //--recursive_level ; - //if(recursive_level) - //{ - // LLSpatialGroup* parent = getParent() ; - // if(parent) - // { - // return parent->getCurUpdatingSlot(imagep, recursive_level) ; - // } - //} - return NULL ; } void LLSpatialGroup::clearDrawMap() @@ -345,6 +218,7 @@ void LLSpatialGroup::validateDrawMap() BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate) { + LL_PROFILE_ZONE_SCOPED; drawablep->updateSpatialExtents(); OctreeNode* parent = mOctreeNode->getOctParent(); @@ -409,11 +283,6 @@ void LLSpatialGroup::rebuildMesh() } } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_VBO("VBO Rebuilt"); -static LLTrace::BlockTimerStatHandle FTM_ADD_GEOMETRY_COUNT("Add Geometry"); -static LLTrace::BlockTimerStatHandle FTM_CREATE_VB("Create VB"); -static LLTrace::BlockTimerStatHandle FTM_GET_GEOMETRY("Get Geometry"); - void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) { if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY)) @@ -427,7 +296,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) group->mLastUpdateViewAngle = group->mViewAngle; } - LL_RECORD_BLOCK_TIME(FTM_REBUILD_VBO); + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL; group->clearDrawMap(); @@ -435,15 +304,12 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) U32 index_count = 0; U32 vertex_count = 0; - { - LL_RECORD_BLOCK_TIME(FTM_ADD_GEOMETRY_COUNT); - addGeometryCount(group, vertex_count, index_count); - } - + addGeometryCount(group, vertex_count, index_count); + if (vertex_count > 0 && index_count > 0) { //create vertex buffer containing volume geometry for this node { - LL_RECORD_BLOCK_TIME(FTM_CREATE_VB); + group->mBuilt = 1.f; if (group->mVertexBuffer.isNull() || !group->mVertexBuffer->isWriteable() || @@ -458,7 +324,6 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) group->mVertexBuffer = NULL; group->mBufferMap.clear(); } - stop_glerror(); } else { @@ -471,13 +336,11 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) group->mVertexBuffer = NULL; group->mBufferMap.clear(); } - stop_glerror(); } } if (group->mVertexBuffer) { - LL_RECORD_BLOCK_TIME(FTM_GET_GEOMETRY); getGeometry(group); } } @@ -503,7 +366,9 @@ LLSpatialGroup* LLSpatialGroup::getParent() } BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree) - { +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL + if(!drawablep) { return FALSE; @@ -591,6 +456,8 @@ public: void LLSpatialGroup::setState(U32 state, S32 mode) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL + llassert(state <= LLSpatialGroup::STATE_MASK); if (mode > STATE_MODE_SINGLE) @@ -638,6 +505,8 @@ public: void LLSpatialGroup::clearState(U32 state, S32 mode) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL + llassert(state <= LLSpatialGroup::STATE_MASK); if (mode > STATE_MODE_SINGLE) @@ -673,11 +542,7 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) : LLO mDistance(0.f), mDepth(0.f), mLastUpdateDistance(-1.f), - mLastUpdateTime(gFrameTimeSeconds), - mAtlasList(4), - mCurUpdatingTime(0), - mCurUpdatingSlotp(NULL), - mCurUpdatingTexture (NULL) + mLastUpdateTime(gFrameTimeSeconds) { ll_assert_aligned(this,16); @@ -724,6 +589,8 @@ void LLSpatialGroup::updateDistance(LLCamera &camera) F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL + LLVector4a eye; LLVector4a origin; origin.load3(camera.getOrigin().mV); @@ -781,9 +648,11 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera) dist = eye.getLength3().getF32(); } +#if !LL_RELEASE LL_DEBUGS("RiggedBox") << "calcDistance, group " << group << " camera " << origin << " obj bounds " << group->mObjectBounds[0] << ", " << group->mObjectBounds[1] << " dist " << dist << " radius " << group->mRadius << LL_ENDL; +#endif if (dist < 16.f) { @@ -815,6 +684,8 @@ F32 LLSpatialGroup::getUpdateUrgency() const BOOL LLSpatialGroup::changeLOD() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL + if (hasState(ALPHA_DIRTY | OBJECT_DIRTY)) { //a rebuild is going to happen, update distance and LoD @@ -907,6 +778,8 @@ void LLSpatialGroup::handleDestruction(const TreeNode* node) void LLSpatialGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* child) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL + if (child->getListenerCount() == 0) { new LLSpatialGroup(child, getSpatialPartition()); @@ -983,6 +856,7 @@ LLSpatialPartition::~LLSpatialPartition() LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) { + LL_PROFILE_ZONE_SCOPED; drawablep->updateSpatialExtents(); //keep drawable from being garbage collected @@ -1008,6 +882,7 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible) BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp) { + LL_PROFILE_ZONE_SCOPED; if (!curp->removeObject(drawablep)) { OCT_ERRS << "Failed to remove drawable from octree!" << LL_ENDL; @@ -1024,6 +899,7 @@ BOOL LLSpatialPartition::remove(LLDrawable *drawablep, LLSpatialGroup *curp) void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate) { + LL_PROFILE_ZONE_SCOPED; // sanity check submitted by open source user bushing Spatula // who was seeing crashing here. (See VWR-424 reported by Bunny Mayne) if (!drawablep) @@ -1477,12 +1353,12 @@ void LLSpatialPartition::resetVertexBuffers() BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL; LLVector4a visMina, visMaxa; visMina.load3(visMin.mV); visMaxa.load3(visMax.mV); { - LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND); LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); } @@ -1504,11 +1380,11 @@ BOOL LLSpatialPartition::visibleObjectsInFrustum(LLCamera& camera) S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* results, BOOL for_select) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL; #if LL_OCTREE_PARANOIA_CHECK ((LLSpatialGroup*)mOctree->getListener(0))->checkStates(); #endif { - LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND); LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); } @@ -1525,37 +1401,32 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector<LLDrawable *>* result S32 LLSpatialPartition::cull(LLCamera &camera, bool do_occlusion) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL; #if LL_OCTREE_PARANOIA_CHECK ((LLSpatialGroup*)mOctree->getListener(0))->checkStates(); #endif - { - LL_RECORD_BLOCK_TIME(FTM_CULL_REBOUND); - LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); - group->rebound(); - } + LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); + group->rebound(); #if LL_OCTREE_PARANOIA_CHECK ((LLSpatialGroup*)mOctree->getListener(0))->validate(); #endif - if (LLPipeline::sShadowRender) - { - LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL); - LLOctreeCullShadow culler(&camera); - culler.traverse(mOctree); - } - else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) - { - LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL); - LLOctreeCullNoFarClip culler(&camera); - culler.traverse(mOctree); - } - else - { - LL_RECORD_BLOCK_TIME(FTM_FRUSTUM_CULL); - LLOctreeCull culler(&camera); - culler.traverse(mOctree); - } + if (LLPipeline::sShadowRender) + { + LLOctreeCullShadow culler(&camera); + culler.traverse(mOctree); + } + else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) + { + LLOctreeCullNoFarClip culler(&camera); + culler.traverse(mOctree); + } + else + { + LLOctreeCull culler(&camera); + culler.traverse(mOctree); + } return 0; } @@ -1728,10 +1599,14 @@ void renderOctree(LLSpatialGroup* group) gGL.flush(); glLineWidth(1.f); gGL.flush(); + + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + for (LLSpatialGroup::element_iter i = group->getDataBegin(); i != group->getDataEnd(); ++i) { LLDrawable* drawable = (LLDrawable*)(*i)->getDrawable(); - if(!drawable) + if(!drawable || drawable->getNumFaces() == 0) { continue; } @@ -1742,6 +1617,27 @@ void renderOctree(LLSpatialGroup* group) gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]); } + LLFace* face = drawable->getFace(0); + bool rigged = face->isState(LLFace::RIGGED); + gDebugProgram.bind(rigged); + + gGL.diffuseColor4f(1, 0, 0, 1); + + if (rigged) + { + gGL.pushMatrix(); + gGL.loadMatrix(gGLModelView); + if (lastAvatar != face->mAvatar || + lastMeshId != face->mSkinInfo->mHash) + { + if (!LLRenderPass::uploadMatrixPalette(face->mAvatar, face->mSkinInfo)) + { + continue; + } + lastAvatar = face->mAvatar; + lastMeshId = face->mSkinInfo->mHash; + } + } for (S32 j = 0; j < drawable->getNumFaces(); j++) { LLFace* face = drawable->getFace(j); @@ -1760,19 +1656,25 @@ void renderOctree(LLSpatialGroup* group) continue; } - face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX); + face->getVertexBuffer()->setBuffer(LLVertexBuffer::MAP_VERTEX | (rigged ? LLVertexBuffer::MAP_WEIGHT4 : 0)); //drawBox((face->mExtents[0] + face->mExtents[1])*0.5f, // (face->mExtents[1]-face->mExtents[0])*0.5f); face->getVertexBuffer()->draw(LLRender::TRIANGLES, face->getIndicesCount(), face->getIndicesStart()); } } + if (rigged) + { + gGL.popMatrix(); + } + if (!group->getSpatialPartition()->isBridge()) { gGL.popMatrix(); } } glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + gDebugProgram.bind(); // make sure non-rigged variant is bound gGL.diffuseColor4f(1,1,1,1); } } @@ -2374,7 +2276,12 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo if (!decomp->mBaseHullMesh.empty()) { gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions); + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + gGL.diffuseColor4fv(line_color.mV); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } else { @@ -2394,13 +2301,11 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color) { gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); - LLGLEnable offset(GL_POLYGON_OFFSET_LINE); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - glPolygonOffset(3.f, 3.f); glLineWidth(3.f); gGL.diffuseColor4fv(line_color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions); glLineWidth(1.f); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } @@ -2455,6 +2360,9 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) gGL.pushMatrix(); gGL.multMatrix((F32*) volume->getRelativeXform().mMatrix); + LLGLEnable(GL_POLYGON_OFFSET_LINE); + glPolygonOffset(3.f, 3.f); + if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH) { LLUUID mesh_id = volume->getVolume()->getParams().getSculptID(); @@ -2482,12 +2390,12 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) { //decomp has physics mesh, render that mesh gGL.diffuseColor4fv(color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); gGL.diffuseColor4fv(line_color.mV); - LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals); - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } else { //no mesh or decomposition, render base hull @@ -2613,9 +2521,9 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) gGL.diffuseColor4fv(line_color.mV); LLVertexBuffer::unbind(); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); - - LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); + llassert(LLGLSLShader::sCurBoundShader != 0); + + LLVertexBuffer::drawElements(LLRender::TRIANGLES, phys_volume->mHullPoints, NULL, phys_volume->mNumHullIndices, phys_volume->mHullIndices); gGL.diffuseColor4fv(color.mV); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); @@ -2695,16 +2603,22 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume) if (phys_volume->mHullPoints && phys_volume->mHullIndices) { glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); - llassert(!LLGLSLShader::sNoFixedFunction || LLGLSLShader::sCurBoundShader != 0); + llassert(LLGLSLShader::sCurBoundShader != 0); LLVertexBuffer::unbind(); glVertexPointer(3, GL_FLOAT, 16, phys_volume->mHullPoints); gGL.diffuseColor4fv(line_color.mV); gGL.syncMatrices(); - glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); + { + LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x20FF20 ) + glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); + } gGL.diffuseColor4fv(color.mV); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); - glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); + { + LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x40FF40 ) + glDrawElements(GL_TRIANGLES, phys_volume->mNumHullIndices, GL_UNSIGNED_SHORT, phys_volume->mHullIndices); + } } else { @@ -2896,8 +2810,27 @@ void renderBatchSize(LLDrawInfo* params) { LLGLEnable offset(GL_POLYGON_OFFSET_FILL); glPolygonOffset(-1.f, 1.f); - gGL.diffuseColor4ubv((GLubyte*) &(params->mDebugColor)); - pushVerts(params, LLVertexBuffer::MAP_VERTEX); + LLGLSLShader* old_shader = LLGLSLShader::sCurBoundShaderPtr; + U32 mask = LLVertexBuffer::MAP_VERTEX; + bool bind = false; + if (params->mAvatar) + { + gGL.pushMatrix(); + gGL.loadMatrix(gGLModelView); + bind = true; + old_shader->mRiggedVariant->bind(); + LLRenderPass::uploadMatrixPalette(*params); + mask |= LLVertexBuffer::MAP_WEIGHT4; + } + + gGL.diffuseColor4ubv((GLubyte*)&(params->mDebugColor)); + pushVerts(params, mask); + + if (bind) + { + gGL.popMatrix(); + old_shader->bind(); + } } void renderShadowFrusta(LLDrawInfo* params) @@ -3222,6 +3155,7 @@ void renderRaycast(LLDrawable* drawablep) gGL.diffuseColor4f(0,1,1,0.5f); glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions); gGL.syncMatrices(); + LL_PROFILER_GPU_ZONEC( "gl.DrawElements", 0x60FF60 ); glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices); } @@ -3774,10 +3708,7 @@ void LLSpatialPartition::renderDebug() return; } - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.bind(); - } + gDebugProgram.bind(); if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) { @@ -3826,10 +3757,7 @@ void LLSpatialPartition::renderDebug() glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } } - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.unbind(); - } + gDebugProgram.unbind(); } void LLSpatialGroup::drawObjectBox(LLColor4 col) @@ -4023,8 +3951,7 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, LLViewerTexture* texture, LLVertexBuffer* buffer, bool selected, BOOL fullbright, U8 bump, BOOL particle, F32 part_size) -: LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16>("LLDrawInfo"), - mVertexBuffer(buffer), +: mVertexBuffer(buffer), mTexture(texture), mTextureMatrix(NULL), mModelMatrix(NULL), @@ -4054,7 +3981,8 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, { mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); - mDebugColor = (rand() << 16) + rand(); + mDebugColor = (rand() << 16) + rand(); + ((U8*)&mDebugColor)[3] = 200; } LLDrawInfo::~LLDrawInfo() @@ -4080,6 +4008,11 @@ void LLDrawInfo::validate() mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset); } +U64 LLDrawInfo::getSkinHash() +{ + return mSkinInfo ? mSkinInfo->mHash : 0; +} + LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage) { return new LLVertexBuffer(type_mask, usage); @@ -4089,6 +4022,7 @@ LLCullResult::LLCullResult() { mVisibleGroupsAllocated = 0; mAlphaGroupsAllocated = 0; + mRiggedAlphaGroupsAllocated = 0; mOcclusionGroupsAllocated = 0; mDrawableGroupsAllocated = 0; mVisibleListAllocated = 0; @@ -4100,6 +4034,9 @@ LLCullResult::LLCullResult() mAlphaGroups.clear(); mAlphaGroups.push_back(NULL); mAlphaGroupsEnd = &mAlphaGroups[0]; + mRiggedAlphaGroups.clear(); + mRiggedAlphaGroups.push_back(NULL); + mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0]; mOcclusionGroups.clear(); mOcclusionGroups.push_back(NULL); mOcclusionGroupsEnd = &mOcclusionGroups[0]; @@ -4140,6 +4077,9 @@ void LLCullResult::clear() mAlphaGroupsSize = 0; mAlphaGroupsEnd = &mAlphaGroups[0]; + mRiggedAlphaGroupsSize = 0; + mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0]; + mOcclusionGroupsSize = 0; mOcclusionGroupsEnd = &mOcclusionGroups[0]; @@ -4184,6 +4124,16 @@ LLCullResult::sg_iterator LLCullResult::endAlphaGroups() return mAlphaGroupsEnd; } +LLCullResult::sg_iterator LLCullResult::beginRiggedAlphaGroups() +{ + return &mRiggedAlphaGroups[0]; +} + +LLCullResult::sg_iterator LLCullResult::endRiggedAlphaGroups() +{ + return mRiggedAlphaGroupsEnd; +} + LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups() { return &mOcclusionGroups[0]; @@ -4262,6 +4212,20 @@ void LLCullResult::pushAlphaGroup(LLSpatialGroup* group) mAlphaGroupsEnd = &mAlphaGroups[mAlphaGroupsSize]; } +void LLCullResult::pushRiggedAlphaGroup(LLSpatialGroup* group) +{ + if (mRiggedAlphaGroupsSize < mRiggedAlphaGroupsAllocated) + { + mRiggedAlphaGroups[mRiggedAlphaGroupsSize] = group; + } + else + { + pushBack(mRiggedAlphaGroups, mRiggedAlphaGroupsAllocated, group); + } + ++mRiggedAlphaGroupsSize; + mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[mRiggedAlphaGroupsSize]; +} + void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group) { if (mOcclusionGroupsSize < mOcclusionGroupsAllocated) diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index 919f386d29..acfcd63686 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -40,7 +40,10 @@ #include "llface.h" #include "llviewercamera.h" #include "llvector4a.h" +#include "llvoavatar.h" + #include <queue> +#include <unordered_map> #define SG_STATE_INHERIT_MASK (OCCLUDED) #define SG_INITIAL_STATE_MASK (DIRTY | GEOM_DIRTY) @@ -49,20 +52,18 @@ class LLViewerOctreePartition; class LLSpatialPartition; class LLSpatialBridge; class LLSpatialGroup; -class LLTextureAtlas; -class LLTextureAtlasSlot; class LLViewerRegion; void pushVerts(LLFace* face, U32 mask); -class LLDrawInfo : public LLRefCount, public LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16> +class LLDrawInfo : public LLRefCount { + LL_ALIGN_NEW; protected: ~LLDrawInfo(); public: LLDrawInfo(const LLDrawInfo& rhs) - : LLTrace::MemTrackableNonVirtual<LLDrawInfo, 16>("LLDrawInfo") { *this = rhs; } @@ -81,12 +82,19 @@ public: void validate(); + // return mSkinHash->mHash, or 0 if mSkinHash is null + U64 getSkinHash(); + LLVector4a mExtents[2]; LLPointer<LLVertexBuffer> mVertexBuffer; LLPointer<LLViewerTexture> mTexture; std::vector<LLPointer<LLViewerTexture> > mTextureList; + // virtual size of mTexture and mTextureList textures + // used to update the decode priority of textures in this DrawInfo + std::vector<F32> mTextureListVSize; + S32 mDebugColor; const LLMatrix4* mTextureMatrix; const LLMatrix4* mModelMatrix; @@ -119,6 +127,8 @@ public: F32 mAlphaMaskCutoff; U8 mDiffuseAlphaMode; bool mSelected; + LLPointer<LLVOAvatar> mAvatar = nullptr; + LLMeshSkinInfo* mSkinInfo = nullptr; struct CompareTexture @@ -216,10 +226,10 @@ public: typedef std::vector<LLPointer<LLSpatialGroup> > sg_vector_t; typedef std::vector<LLPointer<LLSpatialBridge> > bridge_list_t; typedef std::vector<LLPointer<LLDrawInfo> > drawmap_elem_t; - typedef std::map<U32, drawmap_elem_t > draw_map_t; + typedef std::unordered_map<U32, drawmap_elem_t > draw_map_t; typedef std::vector<LLPointer<LLVertexBuffer> > buffer_list_t; - typedef std::map<LLFace*, buffer_list_t> buffer_texture_map_t; - typedef std::map<U32, buffer_texture_map_t> buffer_map_t; + typedef std::unordered_map<LLFace*, buffer_list_t> buffer_texture_map_t; + typedef std::unordered_map<U32, buffer_texture_map_t> buffer_map_t; struct CompareDistanceGreater { @@ -298,49 +308,15 @@ public: virtual void handleDestruction(const TreeNode* node); virtual void handleChildAddition(const OctreeNode* parent, OctreeNode* child); -//------------------- -//for atlas use -//------------------- - //atlas - void setCurUpdatingTime(U32 t) {mCurUpdatingTime = t ;} - U32 getCurUpdatingTime() const { return mCurUpdatingTime ;} - - void setCurUpdatingSlot(LLTextureAtlasSlot* slotp) ; - LLTextureAtlasSlot* getCurUpdatingSlot(LLViewerTexture* imagep, S8 recursive_level = 3) ; - - void setCurUpdatingTexture(LLViewerTexture* tex){ mCurUpdatingTexture = tex ;} - LLViewerTexture* getCurUpdatingTexture() const { return mCurUpdatingTexture ;} - - BOOL hasAtlas(LLTextureAtlas* atlasp) ; - LLTextureAtlas* getAtlas(S8 ncomponents, S8 to_be_reserved, S8 recursive_level = 3) ; - void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ; - void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ; - void clearAtlasList() ; - public: - LL_ALIGN_16(LLVector4a mViewAngle); LL_ALIGN_16(LLVector4a mLastUpdateViewAngle); F32 mObjectBoxSize; //cached mObjectBounds[1].getLength3() - -private: - U32 mCurUpdatingTime ; - //do not make the below two to use LLPointer - //because mCurUpdatingTime invalidates them automatically. - LLTextureAtlasSlot* mCurUpdatingSlotp ; - LLViewerTexture* mCurUpdatingTexture ; - - std::vector< std::list<LLTextureAtlas*> > mAtlasList ; -//------------------- -//end for atlas use -//------------------- protected: virtual ~LLSpatialGroup(); - static S32 sLODSeed; - public: bridge_list_t mBridgeList; buffer_map_t mBufferMap; //used by volume buffers to attempt to reuse vertex buffers @@ -465,8 +441,11 @@ public: virtual void cleanupReferences(); virtual LLSpatialPartition* asPartition() { return this; } + //transform agent space camera into this Spatial Bridge's coordinate frame virtual LLCamera transformCamera(LLCamera& camera); - + + //transform agent space bounding box into this Spatial Bridge's coordinate frame + void transformExtents(const LLVector4a* src, LLVector4a* dst); LLDrawable* mDrawable; }; @@ -493,6 +472,9 @@ public: sg_iterator beginAlphaGroups(); sg_iterator endAlphaGroups(); + sg_iterator beginRiggedAlphaGroups(); + sg_iterator endRiggedAlphaGroups(); + bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; } sg_iterator beginOcclusionGroups(); sg_iterator endOcclusionGroups(); @@ -511,6 +493,7 @@ public: void pushVisibleGroup(LLSpatialGroup* group); void pushAlphaGroup(LLSpatialGroup* group); + void pushRiggedAlphaGroup(LLSpatialGroup* group); void pushOcclusionGroup(LLSpatialGroup* group); void pushDrawableGroup(LLSpatialGroup* group); void pushDrawable(LLDrawable* drawable); @@ -519,6 +502,7 @@ public: U32 getVisibleGroupsSize() { return mVisibleGroupsSize; } U32 getAlphaGroupsSize() { return mAlphaGroupsSize; } + U32 getRiggedAlphaGroupsSize() { return mRiggedAlphaGroupsSize; } U32 getDrawableGroupsSize() { return mDrawableGroupsSize; } U32 getVisibleListSize() { return mVisibleListSize; } U32 getVisibleBridgeSize() { return mVisibleBridgeSize; } @@ -532,6 +516,7 @@ private: U32 mVisibleGroupsSize; U32 mAlphaGroupsSize; + U32 mRiggedAlphaGroupsSize; U32 mOcclusionGroupsSize; U32 mDrawableGroupsSize; U32 mVisibleListSize; @@ -539,6 +524,7 @@ private: U32 mVisibleGroupsAllocated; U32 mAlphaGroupsAllocated; + U32 mRiggedAlphaGroupsAllocated; U32 mOcclusionGroupsAllocated; U32 mDrawableGroupsAllocated; U32 mVisibleListAllocated; @@ -550,6 +536,8 @@ private: sg_iterator mVisibleGroupsEnd; sg_list_t mAlphaGroups; sg_iterator mAlphaGroupsEnd; + sg_list_t mRiggedAlphaGroups; + sg_iterator mRiggedAlphaGroupsEnd; sg_list_t mOcclusionGroups; sg_iterator mOcclusionGroupsEnd; sg_list_t mDrawableGroups; @@ -646,7 +634,8 @@ class LLVolumeGeometryManager: public LLGeometryManager virtual void rebuildGeom(LLSpatialGroup* group); virtual void rebuildMesh(LLSpatialGroup* group); virtual void getGeometry(LLSpatialGroup* group); - U32 genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL no_materials = FALSE); + virtual void addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count); + U32 genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL rigged = FALSE); void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type); private: @@ -654,13 +643,13 @@ private: void freeFaces(); static int32_t sInstanceCount; - static LLFace** sFullbrightFaces; - static LLFace** sBumpFaces; - static LLFace** sSimpleFaces; - static LLFace** sNormFaces; - static LLFace** sSpecFaces; - static LLFace** sNormSpecFaces; - static LLFace** sAlphaFaces; + static LLFace** sFullbrightFaces[2]; + static LLFace** sBumpFaces[2]; + static LLFace** sSimpleFaces[2]; + static LLFace** sNormFaces[2]; + static LLFace** sSpecFaces[2]; + static LLFace** sNormSpecFaces[2]; + static LLFace** sAlphaFaces[2]; }; //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index cdf8a12acf..5df8cd9cb0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -35,6 +35,7 @@ #else # include <sys/stat.h> // mkdir() #endif +#include <memory> // std::unique_ptr #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" @@ -178,7 +179,6 @@ #include "pipeline.h" #include "llappviewer.h" #include "llfasttimerview.h" -#include "lltelemetry.h" #include "llfloatermap.h" #include "llweb.h" #include "llvoiceclient.h" @@ -205,6 +205,9 @@ #include "llstacktrace.h" +#include "threadpool.h" + + #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -252,9 +255,9 @@ static bool mBenefitsSuccessfullyInit = false; const F32 STATE_AGENT_WAIT_TIMEOUT = 240; //seconds -boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState")); -boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener()); -boost::scoped_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap); +std::unique_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState")); +std::unique_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener()); +std::unique_ptr<LLViewerStats::PhaseMap> LLStartUp::sPhases(new LLViewerStats::PhaseMap); // // local function declaration @@ -307,6 +310,12 @@ void update_texture_fetch() LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread gTextureList.updateImages(0.10f); + + if (LLImageGLThread::sEnabled) + { + std::shared_ptr<LL::WorkQueue> main_queue = LL::WorkQueue::getInstance("mainloop"); + main_queue->runFor(std::chrono::milliseconds(1)); + } } void set_flags_and_update_appearance() @@ -529,8 +538,6 @@ bool idle_startup() } #if LL_WINDOWS - LLPROFILE_STARTUP(); - // On the windows dev builds, unpackaged, the message.xml file will // be located in indra/build-vc**/newview/<config>/app_settings. std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml"); @@ -1488,6 +1495,9 @@ bool idle_startup() gAgentCamera.resetCamera(); display_startup(); + // start up the ThreadPool we'll use for textures et al. + LLAppViewer::instance()->initGeneralThread(); + // Initialize global class data needed for surfaces (i.e. textures) LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL; // Initialize all of the viewer object classes for the first time (doing things like texture fetches. @@ -1502,7 +1512,11 @@ bool idle_startup() display_startup(); LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL; - // For all images pre-loaded into viewer cache, decode them. + // For all images pre-loaded into viewer cache, init + // priorities and fetching using decodeAllImages. + // Most of the fetching and decoding likely to be done + // by update_texture_fetch() later, while viewer waits. + // // Need to do this AFTER we init the sky const S32 DECODE_TIME_SEC = 2; for (int i = 0; i < DECODE_TIME_SEC; i++) @@ -2827,7 +2841,7 @@ void reset_login() gAgentWearables.cleanup(); gAgentCamera.cleanup(); gAgent.cleanup(); - LLWorld::getInstance()->destroyClass(); + LLWorld::getInstance()->resetClass(); if ( gViewerWindow ) { // Hide menus and normal buttons diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index 116aeb36a7..fe8e215f76 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -27,7 +27,7 @@ #ifndef LL_LLSTARTUP_H #define LL_LLSTARTUP_H -#include <boost/scoped_ptr.hpp> +#include <memory> // unique_ptr class LLViewerTexture ; class LLEventPump; @@ -130,9 +130,9 @@ private: static std::string startupStateToString(EStartupState state); static EStartupState gStartupState; // Do not set directly, use LLStartup::setStartupState - static boost::scoped_ptr<LLEventPump> sStateWatcher; - static boost::scoped_ptr<LLStartupListener> sListener; - static boost::scoped_ptr<LLViewerStats::PhaseMap> sPhases; + static std::unique_ptr<LLEventPump> sStateWatcher; + static std::unique_ptr<LLStartupListener> sListener; + static std::unique_ptr<LLViewerStats::PhaseMap> sPhases; }; diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index cb356726e6..ea36e1d7be 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -1214,6 +1214,7 @@ F32 LLSurface::getWaterHeight() const BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y, const F32 width, const F32 height) { + LL_PROFILE_ZONE_SCOPED if (!getWaterTexture()) { return FALSE; diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 5e056944e9..aeefcd6fb8 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -728,6 +728,7 @@ BOOL LLSurfacePatch::updateTexture() void LLSurfacePatch::updateGL() { + LL_PROFILE_ZONE_SCOPED F32 meters_per_grid = getSurface()->getMetersPerGrid(); F32 grids_per_patch_edge = (F32)getSurface()->getGridsPerPatchEdge(); diff --git a/indra/newview/lltelemetry.cpp b/indra/newview/lltelemetry.cpp deleted file mode 100644 index 0c63e2fede..0000000000 --- a/indra/newview/lltelemetry.cpp +++ /dev/null @@ -1,145 +0,0 @@ - /** - * @file lltelemetry.cpp - * @brief Wrapper for Rad Game Tools Telemetry - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, 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$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "lltelemetry.h" - -#if LLPROFILE_USE_RAD_TELEMETRY_PROFILER - #if LL_WINDOWS - #include "llwin32headers.h" - - // build-vc120-64\packages\lib\release - // build-vc150-64\packages\lib\release - #ifdef _MSC_VER - #pragma comment(lib,"rad_tm_win64.lib") - #else - #pragma message "NOTE: Rad GameTools Telemetry requested but non-MSVC compiler not yet supported on Windows" - #endif - #endif // LL_WINDOWS - - #if LL_DARWIN - #pragma message "NOTE: Rad Game Tools Telemetry requested but not yet supported on Darwin" - #endif - - #if LL_LINUX - #pragma message "NOTE: Rad Game Tools Telemetry requested but not yet supported on Linux" - #endif - -// -// local consts -// -static const tm_int32 TELEMETRY_BUFFER_SIZE = 8 * 1024 * 1024; - -// -// local globals -// -static char *gTelemetryBufferPtr = NULL; // Telemetry - -static const char *tm_status[ TMERR_INIT_NETWORKING_FAILED + 1 ] = -{ - "Telemetry pass: connected" // TM_OK - , "Telemetry FAIL: disabled via #define NTELEMETRY" // TMERR_DISABLED - , "Telemetry FAIL: invalid paramater" // TMERR_INVALID_PARAM - , "Telemetry FAIL: DLL not found" // TMERR_NULL_API - , "Telemetry FAIL: out of resources" // TMERR_OUT_OF_RESOURCES - , "Telemetry FAIL: tmInitialize() not called" // TMERR_UNINITIALIZED - , "Telemetry FAIL: bad hostname" // TMERR_BAD_HOSTNAME - , "Telemetry FAIL: couldn't connect to server" // TMERR_COULD_NOT_CONNECT - , "Telemetry FAIL: unknown network error" // TMERR_UNKNOWN_NETWORK - , "Telemetry FAIL: tmShutdown() already called" // TMERR_ALREADY_SHUTDOWN - , "Telemetry FAIL: memory buffer too small" // TMERR_ARENA_TOO_SMALL - , "Telemetry FAIL: server handshake error" // TMERR_BAD_HANDSHAKE - , "Telemetry FAIL: unaligned parameters" // TMERR_UNALIGNED - , "Telemetry FAIL: network not initialized" // TMERR_NETWORK_NOT_INITIALIZED -- WSAStartup not called before tmOpen() - , "Telemetry FAIL: bad version" // TMERR_BAD_VERSION - , "Telemetry FAIL: timer too large" // TMERR_BAD_TIMER - , "Telemetry FAIL: tmOpen() already called" // TMERR_ALREADY_OPENED - , "Telemetry FAIL: tmInitialize() already called" // TMERR_ALREADY_INITIALIZED - , "Telemetry FAIL: could't open file" // TMERR_FILE_OPEN_FAILED - , "Telemetry FAIL: tmOpen() failed networking" // TMERR_INIT_NETWORKING_FAILED -}; - -// -// exported functionality -// - -void telemetry_shutdown() -{ - #if LL_WINDOWS - if (gTelemetryBufferPtr) - { - tmClose(0); - tmShutdown(); - - delete[] gTelemetryBufferPtr; - gTelemetryBufferPtr = NULL; - } - #endif -} - -void telemetry_startup() -{ - #if LL_WINDOWS - tmLoadLibrary(TM_RELEASE); // Loads .dll - - gTelemetryBufferPtr = new char[ TELEMETRY_BUFFER_SIZE ]; - tmInitialize(TELEMETRY_BUFFER_SIZE, gTelemetryBufferPtr); - - tm_error telemetry_status = tmOpen( - 0, // unused - "SecondLife", // app name - __DATE__ " " __TIME__, // build identifier - "localhost", // server name (or filename) - TMCT_TCP, // connection type (or TMCT_FILE) - 4719, // port - TMOF_INIT_NETWORKING, // open flags - 250 ); // timeout ms - - if (telemetry_status == TMERR_UNKNOWN) - { - LL_ERRS() << "Telemetry FAIL: unknown error" << LL_ENDL; - } - else if (telemetry_status && (telemetry_status <= TMERR_INIT_NETWORKING_FAILED)) - { - LL_INFOS() << tm_status[ telemetry_status ] << LL_ENDL; - free(gTelemetryBufferPtr); - gTelemetryBufferPtr = NULL; - } - #endif // LL_WINDOWS -} - -// Called after we render a frame -void telemetry_update() -{ - #if LL_WINDOWS - if (gTelemetryBufferPtr) - { - tmTick(0); - } - #endif -} -#endif // LLPROFILE_USE_RAD_TELEMETRY_PROFILER diff --git a/indra/newview/lltelemetry.h b/indra/newview/lltelemetry.h deleted file mode 100644 index a73e5fcfa2..0000000000 --- a/indra/newview/lltelemetry.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file lltelemetry.h - * @brief Wrapper for Rad Game Tools Telemetry - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, 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$ - */ - -/* -To use: - -1. Uncomment #define LLPROFILE_USE_RAD_TELEMETRY_PROFILER below - -2. Include this header file - #include "lltelemetry.h" - -3. Add zones to the functions you wish to profile - void onFoo() - { - LLPROFILE_ZONE("Foo"); - } -*/ -//#define LLPROFILE_USE_RAD_TELEMETRY_PROFILER 1 - -// Default NO local telemetry profiling -#ifndef LLPROFILE_USE_RAD_TELEMETRY_PROFILER - #define LLPROFILE_USE_RAD_TELEMETRY_PROFILER 0 - #define LLPROFILE_SHUTDOWN( ...) {} - #define LLPROFILE_STARTUP( ...) {} - #define LLPROFILE_UPDATE( ...) {} - - #define LLPROFILE_AUTO_CPU_MARKER_COLOR(r, g, b) - #define LLPROFILE_ENTER(name) - #define LLPROFILE_ENTER_FORMAT(format, ...) - #define LLPROFILE_FUNCTION - #define LLPROFILE_LEAVE() - #define LLPROFILE_THREAD_NAME(name) - #define LLPROFILE_ZONE(name) - #define LLPROFILE_ZONE_FORMAT(format, ...) -#else - #include <rad_tm.h> - - #define LLPROFILE_SHUTDOWN telemetry_shutdown - #define LLPROFILE_STARTUP telemetry_startup - #define LLPROFILE_UPDATE telemetry_update - - #define LLPROFILE_AUTO_CPU_MARKER_COLOR(r, g, b) tmZoneColor(r, g, b) - #define LLPROFILE_ENTER(name) tmEnter(0, 0, name) - #define LLPROFILE_ENTER_FORMAT(format, ...) tmEnter(0, 0, format, __VA_ARGS__) - #define LLPROFILE_FUNCTION tmFunction(0, 0) - #define LLPROFILE_LEAVE() tmLeave(0) - #define LLPROFILE_THREAD_NAME(name) tmThreadName(0, 0, name) - #define LLPROFILE_ZONE(name) tmZone(0, 0, name) - #define LLPROFILE_ZONE_FORMAT(format, ...) tmZone(0, 0, format, __VA_ARGS__) -#endif // LLPROFILE_USE_RAD_TELEMETRY_PROFILER - -// -// exported functionality -// - -extern void telemetry_startup(); -extern void telemetry_shutdown(); -extern void telemetry_update(); // called after every frame update diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp index 3c3c1c96ef..3ece12931c 100644 --- a/indra/newview/llteleporthistory.cpp +++ b/indra/newview/llteleporthistory.cpp @@ -39,6 +39,11 @@ #include "llviewerregion.h" #include "llworldmap.h" #include "llagentui.h" +#include "llwindow.h" +#include "llviewerwindow.h" +#include "llavatarname.h" +#include "llavatarnamecache.h" + ////////////////////////////////////////////////////////////////////////////// // LLTeleportHistoryItem @@ -113,6 +118,20 @@ void LLTeleportHistory::handleLoginComplete() updateCurrentLocation(gAgent.getPositionGlobal()); } +static void on_avatar_name_update_title(const LLAvatarName& av_name) +{ + if (gAgent.getRegion() && gViewerWindow && gViewerWindow->getWindow()) + { + std::string region = gAgent.getRegion()->getName(); + std::string username = av_name.getUserName(); + + // this first pass simply displays username and region name + // but could easily be extended to include other details like + // X/Y/Z location within a region etc. + std::string new_title = STRINGIZE(username << " @ " << region); + gViewerWindow->getWindow()->setTitle(new_title); + } +} void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos) { @@ -174,6 +193,14 @@ void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos) if (!mGotInitialUpdate) mGotInitialUpdate = true; + // update Viewer window title with username and region name + // if we are in "non-interactive mode" (SL-15999) or the debug + // setting to allow it is enabled (may be useful in other situations) + if (gNonInteractive || gSavedSettings.getBOOL("UpdateAppWindowTitleBar")) + { + LLAvatarNameCache::get(gAgent.getID(), boost::bind(&on_avatar_name_update_title, _2)); + } + // Signal the interesting party that we've changed. onHistoryChanged(); } diff --git a/indra/newview/lltextureatlas.cpp b/indra/newview/lltextureatlas.cpp deleted file mode 100644 index 1c8e4f796e..0000000000 --- a/indra/newview/lltextureatlas.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/** - * @file lltextureatlas.cpp - * @brief LLTextureAtlas class implementation. - * - * $LicenseInfo:firstyear=2002&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$ - */ -#include "llviewerprecompiledheaders.h" -#include "linden_common.h" -#include "llerror.h" -#include "llimage.h" -#include "llmath.h" -#include "llgl.h" -#include "llrender.h" -#include "lltextureatlas.h" - -//------------------- -S16 LLTextureAtlas::sMaxSubTextureSize = 64 ; -S16 LLTextureAtlas::sSlotSize = 32 ; - -#ifndef DEBUG_ATLAS -#define DEBUG_ATLAS 0 -#endif - -#ifndef DEBUG_USAGE_BITS -#define DEBUG_USAGE_BITS 0 -#endif -//************************************************************************************************************** -LLTextureAtlas::LLTextureAtlas(U8 ncomponents, S16 atlas_dim) : - LLViewerTexture(atlas_dim * sSlotSize, atlas_dim * sSlotSize, ncomponents, TRUE), - mAtlasDim(atlas_dim), - mNumSlotsReserved(0), - mMaxSlotsInAtlas(atlas_dim * atlas_dim) -{ - generateEmptyUsageBits() ; - - //generate an empty texture - generateGLTexture() ; - LLPointer<LLImageRaw> image_raw = new LLImageRaw(mFullWidth, mFullHeight, mComponents); - createGLTexture(0, image_raw, 0); - image_raw = NULL; -} - -LLTextureAtlas::~LLTextureAtlas() -{ - if(mSpatialGroupList.size() > 0) - { - LL_ERRS() << "Not clean up the spatial groups!" << LL_ENDL ; - } - releaseUsageBits() ; -} - -//virtual -S8 LLTextureAtlas::getType() const -{ - return 0; //LLViewerTexture::ATLAS_TEXTURE ; -} - -void LLTextureAtlas::getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yoffset) -{ - xoffset = (F32)col / mAtlasDim ; - yoffset = (F32)row / mAtlasDim ; -} - -void LLTextureAtlas::getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale) -{ - xscale = (F32)w / (mAtlasDim * sSlotSize) ; - yscale = (F32)h / (mAtlasDim * sSlotSize) ; -} - -//insert a texture piece into the atlas -LLGLuint LLTextureAtlas::insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row) -{ - if(!getTexName()) - { - return 0 ; - } - - S32 w = raw_image->getWidth() ; - S32 h = raw_image->getHeight() ; - if(w < 8 || w > sMaxSubTextureSize || h < 8 || h > sMaxSubTextureSize) - { - //size overflow - return 0 ; - } - - BOOL res = gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, getTexName()); - if (!res) - { - LL_ERRS() << "bindTexture failed" << LL_ENDL; - } - - GLint xoffset = sSlotSize * slot_col ; - GLint yoffset = sSlotSize * slot_row ; - - if(!source_gl_tex->preAddToAtlas(discard_level, raw_image)) - { - return 0 ; - } - - glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h, - mGLTexturep->getPrimaryFormat(), mGLTexturep->getFormatType(), raw_image->getData()); - - source_gl_tex->postAddToAtlas() ; - return getTexName(); -} - -//release a sub-texture slot from the atlas -void LLTextureAtlas::releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width) -{ - unmarkUsageBits(slot_width, slot_col, slot_row) ; - mNumSlotsReserved -= slot_width * slot_width ; -} - -BOOL LLTextureAtlas::isEmpty() const -{ - return !mNumSlotsReserved ; -} - -BOOL LLTextureAtlas::isFull(S8 to_be_reserved) const -{ - return mNumSlotsReserved + to_be_reserved > mMaxSlotsInAtlas ; -} -F32 LLTextureAtlas::getFullness() const -{ - return (F32)mNumSlotsReserved / mMaxSlotsInAtlas ; -} - -void LLTextureAtlas::addSpatialGroup(LLSpatialGroup* groupp) -{ - if(groupp && !hasSpatialGroup(groupp)) - { - mSpatialGroupList.push_back(groupp); - } -} - -void LLTextureAtlas::removeSpatialGroup(LLSpatialGroup* groupp) -{ - if(groupp) - { - mSpatialGroupList.remove(groupp); - } -} - -void LLTextureAtlas::clearSpatialGroup() -{ - mSpatialGroupList.clear(); -} -void LLTextureAtlas::removeLastSpatialGroup() -{ - mSpatialGroupList.pop_back() ; -} - -LLSpatialGroup* LLTextureAtlas::getLastSpatialGroup() -{ - if(mSpatialGroupList.size() > 0) - { - return mSpatialGroupList.back() ; - } - return NULL ; -} - -BOOL LLTextureAtlas::hasSpatialGroup(LLSpatialGroup* groupp) -{ - for(std::list<LLSpatialGroup*>::iterator iter = mSpatialGroupList.begin(); iter != mSpatialGroupList.end() ; ++iter) - { - if(*iter == groupp) - { - return TRUE ; - } - } - return FALSE ; -} - -//-------------------------------------------------------------------------------------- -//private -void LLTextureAtlas::generateEmptyUsageBits() -{ - S32 col_len = (mAtlasDim + 7) >> 3 ; - mUsageBits = new U8*[mAtlasDim] ; - *mUsageBits = new U8[mAtlasDim * col_len] ; - - mUsageBits[0] = *mUsageBits ; - for(S32 i = 1 ; i < mAtlasDim ; i++) - { - mUsageBits[i] = mUsageBits[i-1] + col_len ; - - for(S32 j = 0 ; j < col_len ; j++) - { - //init by 0 for all bits. - mUsageBits[i][j] = 0 ; - } - } - - //do not forget mUsageBits[0]! - for(S32 j = 0 ; j < col_len ; j++) - { - //init by 0 for all bits. - mUsageBits[0][j] = 0 ; - } - - mTestBits = NULL ; -#if DEBUG_USAGE_BITS - //------------ - //test - mTestBits = new U8*[mAtlasDim] ; - *mTestBits = new U8[mAtlasDim * mAtlasDim] ; - mTestBits[0] = *mTestBits ; - for(S32 i = 1 ; i < mAtlasDim ; i++) - { - mTestBits[i] = mTestBits[i-1] + mAtlasDim ; - - for(S32 j = 0 ; j < mAtlasDim ; j++) - { - //init by 0 for all bits. - mTestBits[i][j] = 0 ; - } - } - - for(S32 j = 0 ; j < mAtlasDim ; j++) - { - //init by 0 for all bits. - mTestBits[0][j] = 0 ; - } -#endif -} - -void LLTextureAtlas::releaseUsageBits() -{ - if(mUsageBits) - { - delete[] *mUsageBits ; - delete[] mUsageBits ; - } - mUsageBits = NULL ; - - //test - if( mTestBits) - { - delete[] *mTestBits; - delete[] mTestBits; - } - mTestBits = NULL ; -} - -void LLTextureAtlas::markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row) -{ - S16 x = col >> 3 ; - - for(S8 i = 0 ; i < bits_len ; i++) - { - mUsageBits[row + i][x] |= mask ; - } - -#if DEBUG_USAGE_BITS - //test - for(S8 i = row ; i < row + bits_len ; i++) - { - for(S8 j = col ; j < col + bits_len ; j++) - { - mTestBits[i][j] = 1 ; - } - } -#endif -} - -void LLTextureAtlas::unmarkUsageBits(S8 bits_len, S16 col, S16 row) -{ - S16 x = col >> 3 ; - U8 mask = 1 ; - for(S8 i = 1 ; i < bits_len ; i++) - { - mask |= (1 << i) ; - } - mask <<= (col & 7) ; - mask = ~mask ; - - for(S8 i = 0 ; i < bits_len ; i++) - { - mUsageBits[row + i][x] &= mask ; - } - -#if DEBUG_USAGE_BITS - //test - for(S8 i = row ; i < row + bits_len ; i++) - { - for(S8 j = col ; j < col + bits_len ; j++) - { - mTestBits[i][j] = 0 ; - } - } -#endif -} - -//return true if any of bits in the range marked. -BOOL LLTextureAtlas::areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row) -{ - BOOL ret = FALSE ; - S16 x = col >> 3 ; - - for(S8 i = 0 ; i < bits_len ; i++) - { - if(mUsageBits[row + i][x] & mask) - { - ret = TRUE ; - break ; - //return TRUE ; - } - } - -#if DEBUG_USAGE_BITS - //test - BOOL ret2 = FALSE ; - for(S8 i = row ; i < row + bits_len ; i++) - { - for(S8 j = col ; j < col + bits_len ; j++) - { - if(mTestBits[i][j]) - { - ret2 = TRUE ; - } - } - } - - if(ret != ret2) - { - LL_ERRS() << "bits map corrupted." << LL_ENDL ; - } -#endif - return ret ;//FALSE ; -} - -//---------------------------------------------------------------------- -// -//index order: Z order, i.e.: -// |-----|-----|-----|-----| -// | 10 | 11 | 14 | 15 | -// |-----|-----|-----|-----| -// | 8 | 9 | 12 | 13 | -// |-----|-----|-----|-----| -// | 2 | 3 | 6 | 7 | -// |-----|-----|-----|-----| -// | 0 | 1 | 4 | 5 | -// |-----|-----|-----|-----| -void LLTextureAtlas::getPositionFromIndex(S16 index, S16& col, S16& row) -{ - col = 0 ; - row = 0 ; - - S16 index_copy = index ; - for(S16 i = 0 ; index_copy && i < 16 ; i += 2) - { - col |= ((index & (1 << i)) >> i) << (i >> 1) ; - row |= ((index & (1 << (i + 1))) >> (i + 1)) << (i >> 1) ; - index_copy >>= 2 ; - } -} -void LLTextureAtlas::getIndexFromPosition(S16 col, S16 row, S16& index) -{ - index = 0 ; - S16 col_copy = col ; - S16 row_copy = row ; - for(S16 i = 0 ; (col_copy || row_copy) && i < 16 ; i++) - { - index |= ((col & 1 << i) << i) | ((row & 1 << i) << ( i + 1)) ; - col_copy >>= 1 ; - row_copy >>= 1 ; - } -} -//---------------------------------------------------------------------- -//return TRUE if succeeds. -BOOL LLTextureAtlas::getNextAvailableSlot(S8 bits_len, S16& col, S16& row) -{ - S16 index_step = bits_len * bits_len ; - - U8 mask = 1 ; - for(S8 i = 1 ; i < bits_len ; i++) - { - mask |= (1 << i) ; - } - - U8 cur_mask ; - for(S16 index = 0 ; index < mMaxSlotsInAtlas ; index += index_step) - { - getPositionFromIndex(index, col, row) ; - - cur_mask = mask << (col & 7) ; - if(!areUsageBitsMarked(bits_len, cur_mask, col, row)) - { - markUsageBits(bits_len, cur_mask, col, row) ; - mNumSlotsReserved += bits_len * bits_len ; - - return TRUE ; - } - } - - return FALSE ; -} diff --git a/indra/newview/lltextureatlas.h b/indra/newview/lltextureatlas.h deleted file mode 100644 index 6b36eb7fe4..0000000000 --- a/indra/newview/lltextureatlas.h +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @file lltextureatlas.h - * @brief LLTextureAtlas base class. - * - * $LicenseInfo:firstyear=2002&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_TEXTUREATLAS_H -#define LL_TEXTUREATLAS_H - -#include "llviewertexture.h" -class LLSpatialGroup ; - -class LLTextureAtlas : public LLViewerTexture -{ -protected: - /*virtual*/ ~LLTextureAtlas() ; - -public: - LLTextureAtlas(U8 ncomponents, S16 atlas_dim = 16) ; - - /*virtual*/ S8 getType() const; - - LLGLuint insertSubTexture(LLImageGL* source_gl_tex, S32 discard_level, const LLImageRaw* raw_image, S16 slot_col, S16 slot_row) ; - void releaseSlot(S16 slot_col, S16 slot_row, S8 slot_width); - - BOOL getNextAvailableSlot(S8 bits_len, S16& col, S16& row) ; - void getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yOffset) ; - void getTexCoordScale(S32 w, S32 h, F32& xscale, F32& yscale) ; - - BOOL isEmpty() const ; - BOOL isFull(S8 to_be_reserved = 1) const ; - F32 getFullness() const ; - - void addSpatialGroup(LLSpatialGroup* groupp) ; - void removeSpatialGroup(LLSpatialGroup* groupp) ; - LLSpatialGroup* getLastSpatialGroup() ; - void removeLastSpatialGroup() ; - BOOL hasSpatialGroup(LLSpatialGroup* groupp) ; - void clearSpatialGroup() ; - std::list<LLSpatialGroup*>* getSpatialGroupList() {return &mSpatialGroupList;} -private: - void generateEmptyUsageBits() ; - void releaseUsageBits() ; - - void markUsageBits(S8 bits_len, U8 mask, S16 col, S16 row) ; - void unmarkUsageBits(S8 bits_len, S16 col, S16 row) ; - - void getPositionFromIndex(S16 index, S16& col, S16& row) ; - void getIndexFromPosition(S16 col, S16 row, S16& index) ; - BOOL areUsageBitsMarked(S8 bits_len, U8 mask, S16 col, S16 row) ; - -private: - S16 mAtlasDim ; //number of slots per edge, i.e, there are "mAtlasDim * mAtlasDim" total slots in the atlas. - S16 mNumSlotsReserved ; - S16 mMaxSlotsInAtlas ; - U8 **mUsageBits ; - std::list<LLSpatialGroup*> mSpatialGroupList ; - -public: - //debug use only - U8 **mTestBits ; - -public: - static S16 sMaxSubTextureSize ; - static S16 sSlotSize ; -}; - -#endif - diff --git a/indra/newview/lltextureatlasmanager.cpp b/indra/newview/lltextureatlasmanager.cpp deleted file mode 100644 index ca9d6da4db..0000000000 --- a/indra/newview/lltextureatlasmanager.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/** - * @file lltextureatlasmanager.cpp - * @brief LLTextureAtlasManager class implementation. - * - * $LicenseInfo:firstyear=2002&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$ - */ -#include "llviewerprecompiledheaders.h" -#include "linden_common.h" -#include "llerror.h" -#include "llmath.h" -#include "lltextureatlas.h" -#include "lltextureatlasmanager.h" -#include "llspatialpartition.h" - -const S8 MAX_NUM_EMPTY_ATLAS = 2 ; -const F32 MIN_ATLAS_FULLNESS = 0.6f ; - -//********************************************************************************************* -//implementation of class LLTextureAtlasInfo -//********************************************************************************************* -LLTextureAtlasSlot::LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) : - mAtlasp(atlasp), - mGroupp(groupp), - mCol(col), - mRow(row), - mReservedSlotWidth(slot_width), - mValid(FALSE), - mUpdatedTime(0), - mTexCoordOffset(xoffset, yoffset), - mTexCoordScale(1.f, 1.f) -{ - llassert_always(mAtlasp || mGroupp || mReservedSlotWidth) ; -} - -LLTextureAtlasSlot::~LLTextureAtlasSlot() -{ - if(mAtlasp) - { - mAtlasp->releaseSlot(mCol, mRow, mReservedSlotWidth) ; - if(mAtlasp->isEmpty()) - { - LLTextureAtlasManager::getInstance()->releaseAtlas(mAtlasp) ; - } - mAtlasp = NULL ; - } -} - -//void LLTextureAtlasSlot::setAtlas(LLTextureAtlas* atlasp) -//{ -// mAtlasp = atlasp ; -//} -//void LLTextureAtlasSlot::setSlotPos(S16 col, S16 row) -//{ -// mCol = col ; -// mRow = row ; -//} -//void LLTextureAtlasSlot::setSlotWidth(S8 width) -//{ -// //slot is a square with each edge length a power-of-two number -// mReservedSlotWidth = width ; -//} -//void LLTextureAtlasSlot::setTexCoordOffset(F32 xoffset, F32 yoffset) -//{ -// mTexCoordOffset.mV[0] = xoffset ; -// mTexCoordOffset.mV[1] = yoffset ; -//} - -void LLTextureAtlasSlot::setSpatialGroup(LLSpatialGroup* groupp) -{ - mGroupp = groupp ; -} -void LLTextureAtlasSlot::setTexCoordScale(F32 xscale, F32 yscale) -{ - mTexCoordScale.mV[0] = xscale ; - mTexCoordScale.mV[1] = yscale ; -} -//********************************************************************************************* -//END of implementation of class LLTextureAtlasInfo -//********************************************************************************************* - -//********************************************************************************************* -//implementation of class LLTextureAtlasManager -//********************************************************************************************* -LLTextureAtlasManager::LLTextureAtlasManager() : - mAtlasMap(4), - mEmptyAtlasMap(4) -{ -} - -LLTextureAtlasManager::~LLTextureAtlasManager() -{ - for(S32 i = 0 ; i < 4 ; i++) - { - for(ll_texture_atlas_list_t::iterator j = mAtlasMap[i].begin() ; j != mAtlasMap[i].end() ; ++j) - { - *j = NULL ; - } - for(ll_texture_atlas_list_t::iterator j = mEmptyAtlasMap[i].begin() ; j != mEmptyAtlasMap[i].end() ; ++j) - { - *j = NULL ; - } - - mAtlasMap[i].clear() ; - mEmptyAtlasMap[i].clear() ; - } - mAtlasMap.clear() ; - mEmptyAtlasMap.clear() ; -} - -//return TRUE if qualified -BOOL LLTextureAtlasManager::canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) -{ - if(ncomponents < 1 || ncomponents > 4) - { - return FALSE ; - } - //only support GL_TEXTURE_2D - if(GL_TEXTURE_2D != target) - { - return FALSE ; - } - //real image size overflows - if(w < 8 || w > LLTextureAtlas::sMaxSubTextureSize || h < 8 || h > LLTextureAtlas::sMaxSubTextureSize) - { - return FALSE ; - } - - //if non-power-of-two number - if((w & (w - 1)) || (h & (h - 1))) - { - return FALSE ; - } - - return TRUE ; -} - -void LLTextureAtlasManager::releaseAtlas(LLTextureAtlas* atlasp) -{ - LLSpatialGroup* groupp = atlasp->getLastSpatialGroup() ; - while(groupp) - { - groupp->removeAtlas(atlasp, FALSE) ; - atlasp->removeLastSpatialGroup() ; - - groupp = atlasp->getLastSpatialGroup() ; - } - - S8 type = atlasp->getComponents() - 1 ; - //insert to the empty list - if(mEmptyAtlasMap[type].size() < MAX_NUM_EMPTY_ATLAS) - { - mEmptyAtlasMap[type].push_back(atlasp) ; - } - - //delete the atlasp - mAtlasMap[type].remove(atlasp) ; -} - -// -//this function reserves an appropriate slot from atlas pool for an image. -//return non-NULL if succeeds. -//Note: -//1, this function does not check if the image this slot assigned for qualifies for atlas or not, -// call LLTextureAtlasManager::canAddToAtlas(...) to do the check before calling this function. -//2, this function also dose not check if the image is already in atlas. It always assigns a new slot anyway. -//3, this function tries to group sub-textures from same spatial group into ONE atlas to improve render batching. -// -LLPointer<LLTextureAtlasSlot> LLTextureAtlasManager::reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, - LLSpatialGroup* groupp, LLViewerTexture* imagep) -{ - if(!groupp) - { - //do not insert to atlas if does not have a group. - return NULL ; - } - - //bits_len must <= 8 and is a power of two number, i.e.: must be one of these numbers: 1, 2, 4, 8. - if(sub_texture_size > LLTextureAtlas::sMaxSubTextureSize) - { - sub_texture_size = LLTextureAtlas::sMaxSubTextureSize ; - } - S8 bits_len = sub_texture_size / LLTextureAtlas::sSlotSize ; - if(bits_len < 1) - { - bits_len = 1 ; - } - - S16 col = -1, row = -1; - S8 total_bits = bits_len * bits_len ; - - //insert to the atlas reserved by the same spatial group - LLPointer<LLTextureAtlas> atlasp = groupp->getAtlas(ncomponents, total_bits) ; - if(atlasp.notNull()) - { - if(!atlasp->getNextAvailableSlot(bits_len, col, row)) - { - //failed - atlasp = NULL ; - } - } - - //search an atlas to fit for 'size' - if(!atlasp) - { - S8 atlas_index = ncomponents - 1 ; - ll_texture_atlas_list_t::iterator iter = mAtlasMap[atlas_index].begin() ; - for(; iter != mAtlasMap[atlas_index].end(); ++iter) - { - LLTextureAtlas* cur = (LLTextureAtlas*)*iter ; - if(cur->getFullness() < MIN_ATLAS_FULLNESS)//this atlas is empty enough for this group to insert more sub-textures later if necessary. - { - if(cur->getNextAvailableSlot(bits_len, col, row)) - { - atlasp = cur ; - groupp->addAtlas(atlasp) ; - break ; - } - } - } - } - - //create a new atlas if necessary - if(!atlasp) - { - if(mEmptyAtlasMap[ncomponents - 1].size() > 0) - { - //there is an empty one - atlasp = mEmptyAtlasMap[ncomponents - 1].back() ; - mEmptyAtlasMap[ncomponents - 1].pop_back() ; - } - else - { - atlasp = new LLTextureAtlas(ncomponents, 16) ; - } - mAtlasMap[ncomponents - 1].push_back(atlasp) ; - atlasp->getNextAvailableSlot(bits_len, col, row) ; - groupp->addAtlas(atlasp) ; - } - - F32 xoffset, yoffset ; - atlasp->getTexCoordOffset(col, row, xoffset, yoffset) ; - LLPointer<LLTextureAtlasSlot> slot_infop = new LLTextureAtlasSlot(atlasp, groupp, col, row, xoffset, yoffset, bits_len) ; - - return slot_infop ; -} - -//********************************************************************************************* -//END of implementation of class LLTextureAtlasManager -//********************************************************************************************* diff --git a/indra/newview/lltextureatlasmanager.h b/indra/newview/lltextureatlasmanager.h deleted file mode 100644 index 1b8df708c6..0000000000 --- a/indra/newview/lltextureatlasmanager.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @file lltextureatlasmanager.h - * @brief LLTextureAtlasManager base class. - * - * $LicenseInfo:firstyear=2002&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_TEXTUREATLASMANAGER_H -#define LL_TEXTUREATLASMANAGER_H - -#include "llmemory.h" - -class LLSpatialGroup ; -class LLViewerTexture ; - -//just use it as a structure. -class LLTextureAtlasSlot : public LLRefCount -{ -public: - LLTextureAtlasSlot(LLTextureAtlas* atlasp, LLSpatialGroup* groupp, S16 col, S16 row, F32 xoffset, F32 yoffset, S8 slot_width) ; - -protected: - virtual ~LLTextureAtlasSlot(); - -public: - - // - //do not allow to change those values - // - //void setAtlas(LLTextureAtlas* atlasp) ; - //void setSlotPos(S16 col, S16 row) ; - //void setSlotWidth(S8 width) ; - //void setTexCoordOffset(F32 xoffser, F32 yoffset) ; - // - - void setSpatialGroup(LLSpatialGroup* groupp) ; - void setTexCoordScale(F32 xscale, F32 yscale) ; - void setValid() {mValid = TRUE ;} - - LLTextureAtlas* getAtlas()const {return mAtlasp;} - LLSpatialGroup* getSpatialGroup() const {return mGroupp ;} - S16 getSlotCol()const {return mCol;} - S16 getSlotRow()const {return mRow;} - S8 getSlotWidth()const{return mReservedSlotWidth;} - BOOL isValid()const { return mValid;} - const LLVector2* getTexCoordOffset()const {return &mTexCoordOffset;} - const LLVector2* getTexCoordScale() const {return &mTexCoordScale;} - - void setUpdatedTime(U32 t) {mUpdatedTime = t;} - U32 getUpdatedTime()const {return mUpdatedTime;} - -private: - LLTextureAtlas* mAtlasp; - S16 mCol ;//col of the slot - S16 mRow ;//row of the slot - S8 mReservedSlotWidth ; //slot is a square with each edge length a power-of-two number - LLSpatialGroup* mGroupp ; - BOOL mValid ; - - LLVector2 mTexCoordOffset ; - LLVector2 mTexCoordScale ; - - U32 mUpdatedTime ; -} ; - -class LLTextureAtlasManager : public LLSingleton<LLTextureAtlasManager> -{ - LLSINGLETON(LLTextureAtlasManager); - ~LLTextureAtlasManager(); - typedef std::list<LLPointer<LLTextureAtlas> > ll_texture_atlas_list_t ; - -public: - - LLPointer<LLTextureAtlasSlot> reserveAtlasSlot(S32 sub_texture_size, S8 ncomponents, - LLSpatialGroup* groupp, LLViewerTexture* imagep) ; - void releaseAtlas(LLTextureAtlas* atlasp); - - BOOL canAddToAtlas(S32 w, S32 h, S8 ncomponents, LLGLenum target) ; - -private: - std::vector<ll_texture_atlas_list_t> mAtlasMap ; - std::vector<ll_texture_atlas_list_t> mEmptyAtlasMap ; //delay some empty atlases deletion to avoid possible creation of new atlas immediately. -}; - -#endif diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index e7b756bf4a..0edaf40c66 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -318,6 +318,7 @@ private: // Threads: Ttc virtual void completed(bool success) { + LL_PROFILE_ZONE_SCOPED; LLTextureFetchWorker* worker = mFetcher->getWorker(mID); if (worker) { @@ -342,6 +343,7 @@ private: // Threads: Ttc virtual void completed(bool success) { + LL_PROFILE_ZONE_SCOPED; LLTextureFetchWorker* worker = mFetcher->getWorker(mID); if (worker) { @@ -366,6 +368,7 @@ private: // Threads: Tid virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) { + LL_PROFILE_ZONE_SCOPED; LLTextureFetchWorker* worker = mFetcher->getWorker(mID); if (worker) { @@ -1153,6 +1156,11 @@ void LLTextureFetchWorker::startWork(S32 param) // Threads: Ttf bool LLTextureFetchWorker::doWork(S32 param) { + LL_PROFILE_ZONE_SCOPED; + if (gNonInteractive) + { + return true; + } static const LLCore::HttpStatus http_not_found(HTTP_NOT_FOUND); // 404 static const LLCore::HttpStatus http_service_unavail(HTTP_SERVICE_UNAVAILABLE); // 503 static const LLCore::HttpStatus http_not_sat(HTTP_REQUESTED_RANGE_NOT_SATISFIABLE); // 416; diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 7a0f69fed5..b74577315e 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -549,9 +549,11 @@ void LLGLTexMemBar::draw() U32 texFetchLatMed = U32(recording.getMean(LLTextureFetch::sTexFetchLatency).value() * 1000.0f); U32 texFetchLatMax = U32(recording.getMax(LLTextureFetch::sTexFetchLatency).value() * 1000.0f); - text = llformat("GL Tot: %d/%d MB Bound: %4d/%4d MB FBO: %d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB", + text = llformat("GL Tot: %d/%d MB GL Free: %d Sys Free: %d MB Bound: %4d/%4d MB FBO: %d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB", total_mem.value(), max_total_mem.value(), + LLImageGLThread::getFreeVRAMMegabytes(), + LLMemory::getAvailableMemKB()/1024, bound_mem.value(), max_bound_mem.value(), LLRenderTarget::sBytesAllocated/(1024*1024), diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp index 100d5ee713..d43da93c61 100644 --- a/indra/newview/lltoastpanel.cpp +++ b/indra/newview/lltoastpanel.cpp @@ -114,7 +114,8 @@ void LLToastPanel::snapToMessageHeight(LLTextBase* message, S32 maxLineCount) LLToastPanel* LLToastPanel::buidPanelFromNotification( const LLNotificationPtr& notification) { - LLToastPanel* res = NULL; + LL_PROFILE_ZONE_SCOPED + LLToastPanel* res = NULL; //process tip toast panels if ("notifytip" == notification->getType()) diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index 7ab079c74d..897f8c1e5f 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -542,8 +542,8 @@ void LLToolGrabBase::handleHoverActive(S32 x, S32 y, MASK mask) const F32 RADIANS_PER_PIXEL_X = 0.01f; const F32 RADIANS_PER_PIXEL_Y = 0.01f; - S32 dx = x - (gViewerWindow->getWorldViewWidthScaled() / 2); - S32 dy = y - (gViewerWindow->getWorldViewHeightScaled() / 2); + S32 dx = gViewerWindow->getCurrentMouseDX(); + S32 dy = gViewerWindow->getCurrentMouseDY(); if (dx != 0 || dy != 0) { diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 06a2caf75b..d99c0ba2a6 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -195,10 +195,7 @@ BOOL LLVisualParamHint::render() gGL.pushMatrix(); gGL.loadIdentity(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); LLGLSUIDefault gls_ui; //LLGLState::verify(TRUE); @@ -242,17 +239,16 @@ BOOL LLVisualParamHint::render() LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); - if (gAgentAvatarp->mDrawable.notNull() && - gAgentAvatarp->mDrawable->getFace(0)) - { - LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)gAgentAvatarp->mDrawable->getFace(0)->getPool(); - LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); - gGL.setAlphaRejectSettings(LLRender::CF_ALWAYS); - gGL.setSceneBlendType(LLRender::BT_REPLACE); - avatarPoolp->renderAvatars(gAgentAvatarp); // renders only one avatar - gGL.setSceneBlendType(LLRender::BT_ALPHA); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - } + if (gAgentAvatarp->mDrawable.notNull()) + { + LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE); + gGL.flush(); + gGL.setSceneBlendType(LLRender::BT_REPLACE); + gPipeline.generateImpostor(gAgentAvatarp, true); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + gGL.flush(); + } + gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight); LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr; diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index 728d0c9417..ab4ad5817b 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -109,7 +109,16 @@ void LLTracker::stopTracking(bool clear_ui) // static virtual void LLTracker::drawHUDArrow() { - if (!gSavedSettings.getBOOL("RenderTrackerBeacon")) return; + if (!LLWorld::instanceExists()) + { + return; + } + + static LLCachedControl<bool> render_beacon(gSavedSettings, "RenderTrackerBeacon", true); + if (!render_beacon) + { + return; + } if (gViewerWindow->getProgressView()->getVisible()) return; diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 27a87ee1a0..5d8e80cc41 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -81,9 +81,6 @@ glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height return glh::matrix4f(m); } -// Build time optimization, generate this once in .cpp file -template class LLViewerCamera* LLSingleton<class LLViewerCamera>::getInstance(); - LLViewerCamera::LLViewerCamera() : LLCamera() { calcProjection(getFar()); diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h index fb07a3fb2d..549778a841 100644 --- a/indra/newview/llviewercamera.h +++ b/indra/newview/llviewercamera.h @@ -38,25 +38,11 @@ class LLViewerObject; const BOOL FOR_SELECTION = TRUE; const BOOL NOT_FOR_SELECTION = FALSE; -// Build time optimization, generate this once in .cpp file -#ifndef LLVIEWERCAMERA_CPP -extern template class LLViewerCamera* LLSingleton<class LLViewerCamera>::getInstance(); -#endif - -LL_ALIGN_PREFIX(16) -class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera> +class alignas(16) LLViewerCamera : public LLCamera, public LLSimpleton<LLViewerCamera> { - LLSINGLETON(LLViewerCamera); + LL_ALIGN_NEW public: - void* operator new(size_t size) - { - return ll_aligned_malloc_16(size); - } - - void operator delete(void* ptr) - { - ll_aligned_free_16(ptr); - } + LLViewerCamera(); typedef enum { @@ -141,7 +127,7 @@ protected: S16 mZoomSubregion; public: -} LL_ALIGN_POSTFIX(16); +}; #endif // LL_LLVIEWERCAMERA_H diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index bc425123e1..4618871630 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -107,10 +107,14 @@ static bool handleRenderAvatarMouselookChanged(const LLSD& newvalue) static bool handleRenderFarClipChanged(const LLSD& newvalue) { - F32 draw_distance = (F32) newvalue.asReal(); + if (LLStartUp::getStartupState() >= STATE_STARTED) + { + F32 draw_distance = (F32)newvalue.asReal(); gAgentCamera.mDrawDistance = draw_distance; LLWorld::getInstance()->setLandFarClip(draw_distance); return true; + } + return false; } static bool handleTerrainDetailChanged(const LLSD& newvalue) @@ -162,17 +166,6 @@ static bool handleSetShaderChanged(const LLSD& newvalue) return true; } -static bool handleAvatarVPChanged(const LLSD& newvalue) -{ - LLRenderTarget::sUseFBO = newvalue.asBoolean() - && gSavedSettings.getBOOL("RenderObjectBump") - && gSavedSettings.getBOOL("RenderTransparentWater") - && gSavedSettings.getBOOL("RenderDeferred"); - - handleSetShaderChanged(LLSD()); - return true; -} - static bool handleRenderPerfTestChanged(const LLSD& newvalue) { bool status = !newvalue.asBoolean(); @@ -212,10 +205,6 @@ static bool handleRenderPerfTestChanged(const LLSD& newvalue) bool handleRenderTransparentWaterChanged(const LLSD& newvalue) { - LLRenderTarget::sUseFBO = newvalue.asBoolean() - && gSavedSettings.getBOOL("RenderObjectBump") - && gSavedSettings.getBOOL("RenderAvatarVP") - && gSavedSettings.getBOOL("RenderDeferred"); if (gPipeline.isInit()) { gPipeline.updateRenderTransparentWater(); @@ -269,6 +258,13 @@ static bool handleAnisotropicChanged(const LLSD& newvalue) return true; } +static bool handleVSyncChanged(const LLSD& newvalue) +{ + gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean()); + + return true; +} + static bool handleVolumeLODChanged(const LLSD& newvalue) { LLVOVolume::sLODFactor = llclamp((F32) newvalue.asReal(), 0.01f, MAX_LOD_FACTOR); @@ -391,7 +387,7 @@ static bool handleJoystickChanged(const LLSD& newvalue) static bool handleUseOcclusionChanged(const LLSD& newvalue) { - LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery && LLGLSLShader::sNoFixedFunction + LLPipeline::sUseOcclusion = (newvalue.asBoolean() && gGLManager.mHasOcclusionQuery && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && !gUseWireframe) ? 2 : 0; return true; } @@ -468,10 +464,7 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue) // static bool handleRenderBumpChanged(const LLSD& newval) { - LLRenderTarget::sUseFBO = newval.asBoolean() - && gSavedSettings.getBOOL("RenderTransparentWater") - && gSavedSettings.getBOOL("RenderAvatarVP") - && gSavedSettings.getBOOL("RenderDeferred"); + LLRenderTarget::sUseFBO = newval.asBoolean() && gSavedSettings.getBOOL("RenderDeferred"); if (gPipeline.isInit()) { gPipeline.updateRenderBump(); @@ -665,7 +658,6 @@ void settings_setup_listeners() gSavedSettings.getControl("OctreeAttachmentSizeFactor")->getSignal()->connect(boost::bind(&handleRepartition, _2)); gSavedSettings.getControl("RenderMaxTextureIndex")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); gSavedSettings.getControl("RenderUseTriStrips")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); - gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleAvatarVPChanged, _2)); gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleWindowResized, _2)); gSavedSettings.getControl("RenderDepthOfField")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); @@ -696,6 +688,7 @@ void settings_setup_listeners() gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleRenderBumpChanged, _2)); gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderVSyncEnable")->getSignal()->connect(boost::bind(&handleVSyncChanged, _2)); gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _2)); gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2)); diff --git a/indra/newview/llviewercontrollistener.cpp b/indra/newview/llviewercontrollistener.cpp index 3443bb644a..8820f9ec56 100644 --- a/indra/newview/llviewercontrollistener.cpp +++ b/indra/newview/llviewercontrollistener.cpp @@ -127,7 +127,7 @@ struct Info LLEventAPI::Response response; std::string groupname; - LLControlGroup* group; + LLControlGroup::ptr_t group; std::string key; LLControlVariable* control; }; @@ -187,7 +187,7 @@ void LLViewerControlListener::groups(LLSD const & request) struct CollectVars: public LLControlGroup::ApplyFunctor { - CollectVars(LLControlGroup* g): + CollectVars(LLControlGroup::ptr_t g): mGroup(g) {} @@ -200,7 +200,7 @@ struct CollectVars: public LLControlGroup::ApplyFunctor ("comment", control->getComment())); } - LLControlGroup* mGroup; + LLControlGroup::ptr_t mGroup; LLSD vars; }; @@ -210,7 +210,7 @@ void LLViewerControlListener::vars(LLSD const & request) // control name. Response response(LLSD(), request); std::string groupname(request["group"]); - LLControlGroup* group(LLControlGroup::getInstance(groupname)); + auto group(LLControlGroup::getInstance(groupname)); if (! group) { return response.error(STRINGIZE("Unrecognized group '" << groupname << "'")); diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 109dc93261..6a2b06d9b5 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -124,7 +124,8 @@ void display_startup() if ( !gViewerWindow || !gViewerWindow->getActive() || !gViewerWindow->getWindow()->getVisible() - || gViewerWindow->getWindow()->getMinimized() ) + || gViewerWindow->getWindow()->getMinimized() + || gNonInteractive) { return; } @@ -165,8 +166,6 @@ void display_startup() if (gViewerWindow) gViewerWindow->setup2DRender(); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - gGL.color4f(1,1,1,1); if (gViewerWindow) gViewerWindow->draw(); @@ -208,9 +207,11 @@ void display_update_camera() // Write some stats to LL_INFOS() void display_stats() { + LL_PROFILE_ZONE_SCOPED F32 fps_log_freq = gSavedSettings.getF32("FPSLogFrequency"); if (fps_log_freq > 0.f && gRecentFPSTime.getElapsedTimeF32() >= fps_log_freq) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - FPS"); F32 fps = gRecentFrameCount / fps_log_freq; LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL; gRecentFrameCount = 0; @@ -219,6 +220,7 @@ void display_stats() F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency"); if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Memory"); gMemoryAllocated = U64Bytes(LLMemory::getCurrentRSS()); U32Megabytes memory = gMemoryAllocated; LL_INFOS() << "MEMORY: " << memory << LL_ENDL; @@ -228,6 +230,7 @@ void display_stats() F32 asset_storage_log_freq = gSavedSettings.getF32("AssetStorageLogFrequency"); if (asset_storage_log_freq > 0.f && gAssetStorageLogTime.getElapsedTimeF32() >= asset_storage_log_freq) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DS - Asset Storage"); gAssetStorageLogTime.reset(); gAssetStorage->logAssetStorageInfo(); } @@ -309,7 +312,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // Attempting to draw into a minimized window causes a GL error. JC if ( !gViewerWindow->getActive() || !gViewerWindow->getWindow()->getVisible() - || gViewerWindow->getWindow()->getMinimized() ) + || gViewerWindow->getWindow()->getMinimized() + || gNonInteractive) { // Clean up memory the pools may have allocated if (rebuild) @@ -572,8 +576,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // LLAppViewer::instance()->pingMainloopTimeout("Display:Camera"); - LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield); - LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE); + if (LLViewerCamera::instanceExists()) + { + LLViewerCamera::getInstance()->setZoomParameters(zoom_factor, subfield); + LLViewerCamera::getInstance()->setNear(MIN_NEAR_PLANE); + } ////////////////////////// // @@ -630,6 +637,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (!gDisconnected) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 1"); LLAppViewer::instance()->pingMainloopTimeout("Display:Update"); if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { //don't draw hud objects in this frame @@ -641,9 +649,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES); } - //upkeep gl name pools - LLGLNamePool::upkeepPools(); - stop_glerror(); display_update_camera(); stop_glerror(); @@ -675,21 +680,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) stop_glerror(); - S32 water_clip = 0; - if ((LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) && - (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER) || - gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_VOIDWATER))) - { - if (LLViewerCamera::getInstance()->cameraUnderWater()) - { - water_clip = -1; - } - else - { - water_clip = 1; - } - } - LLAppViewer::instance()->pingMainloopTimeout("Display:Cull"); //Increment drawable frame counter @@ -707,21 +697,20 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); static LLCullResult result; LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater(); - gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip); + gPipeline.updateCull(*LLViewerCamera::getInstance(), result); stop_glerror(); LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); - + LLAppViewer::instance()->pingMainloopTimeout("Display:Swap"); { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 2") if (gResizeScreenTexture) { gResizeScreenTexture = FALSE; @@ -733,7 +722,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); if (!for_snapshot) { @@ -747,7 +735,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); glh::matrix4f proj = get_current_projection(); glh::matrix4f mod = get_current_modelview(); @@ -766,17 +753,16 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); } glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); } LLGLState::checkStates(); - LLGLState::checkClientArrays(); //if (!for_snapshot) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 3") LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery"); gPipeline.generateWaterReflection(*LLViewerCamera::getInstance()); gPipeline.generateHighlight(*LLViewerCamera::getInstance()); @@ -784,7 +770,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) } LLGLState::checkStates(); - LLGLState::checkClientArrays(); ////////////////////////////////////// // @@ -800,13 +785,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_CLASS); - LLTrace::CountStatHandle<>* velocity_stat = LLViewerCamera::getVelocityStat(); - LLTrace::CountStatHandle<>* angular_velocity_stat = LLViewerCamera::getAngularVelocityStat(); - LLViewerTexture::updateClass(LLTrace::get_frame_recording().getPeriodMeanPerSec(*velocity_stat), - LLTrace::get_frame_recording().getPeriodMeanPerSec(*angular_velocity_stat)); + LLViewerTexture::updateClass(); } - + LLImageGLThread::updateClass(); + { LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_BUMP); gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. @@ -825,10 +808,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLImageGL::deleteDeadTextures(); stop_glerror(); }*/ - } + } LLGLState::checkStates(); - LLGLState::checkClientArrays(); /////////////////////////////////// // @@ -840,6 +822,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort"); { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 4") LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; gPipeline.stateSort(*LLViewerCamera::getInstance(), result); stop_glerror(); @@ -859,13 +842,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLSceneMonitor::getInstance()->fetchQueryResult(); LLGLState::checkStates(); - LLGLState::checkClientArrays(); LLPipeline::sUseOcclusion = occlusion; { LLAppViewer::instance()->pingMainloopTimeout("Display:Sky"); - LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY); + LL_PROFILE_ZONE_NAMED_CATEGORY_ENVIRONMENT("update sky"); //LL_RECORD_BLOCK_TIME(FTM_UPDATE_SKY); gSky.updateSky(); } @@ -918,7 +900,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE; LLGLState::checkStates(); - LLGLState::checkClientArrays(); stop_glerror(); @@ -948,9 +929,10 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) && !gRestoreGL) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("display - 5") LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; - if (gSavedSettings.getBOOL("RenderDepthPrePass") && LLGLSLShader::sNoFixedFunction) + if (gSavedSettings.getBOOL("RenderDepthPrePass")) { gGL.setColorMask(false, false); @@ -1259,7 +1241,7 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); LLGLState::checkStates(); @@ -1274,7 +1256,6 @@ void render_ui(F32 zoom_factor, int subfield) if(LLSceneMonitor::getInstance()->needsUpdate()) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_SCENE_MON); gGL.pushMatrix(); gViewerWindow->setup2DRender(); LLSceneMonitor::getInstance()->compare(); @@ -1282,55 +1263,61 @@ void render_ui(F32 zoom_factor, int subfield) gGL.popMatrix(); } - // Finalize scene - gPipeline.renderFinalize(); - - LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD); - render_hud_elements(); - render_hud_attachments(); + // Finalize scene + gPipeline.renderFinalize(); - LLGLSDefault gls_default; - LLGLSUIDefault gls_ui; { - gPipeline.disableLights(); - } + // SL-15709 + // NOTE: Tracy only allows one ZoneScoped per function. + // Solutions are: + // 1. Use a new scope + // 2. Use named zones + // 3. Use transient zones + LL_PROFILE_ZONE_NAMED_CATEGORY_UI("HUD"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_HUD); + render_hud_elements(); + render_hud_attachments(); + + LLGLSDefault gls_default; + LLGLSUIDefault gls_ui; + { + gPipeline.disableLights(); + } - { - gGL.color4f(1,1,1,1); - if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { - if (!gDisconnected) + gGL.color4f(1,1,1,1); + if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D); - render_ui_3d(); + if (!gDisconnected) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 3D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_3D); + render_ui_3d(); + LLGLState::checkStates(); + } + else + { + render_disconnected_background(); + } + + LL_PROFILE_ZONE_NAMED_CATEGORY_UI("UI 2D"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D); + render_ui_2d(); LLGLState::checkStates(); } - else - { - render_disconnected_background(); - } + gGL.flush(); - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_2D); - render_ui_2d(); - LLGLState::checkStates(); - } - gGL.flush(); - - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI_DEBUG_TEXT); gViewerWindow->setup2DRender(); gViewerWindow->updateDebugText(); gViewerWindow->drawDebugText(); + + LLVertexBuffer::unbind(); } - LLVertexBuffer::unbind(); - } + if (!gSnapshot) + { + set_current_modelview(saved_view); + gGL.popMatrix(); + } - if (!gSnapshot) - { - set_current_modelview(saved_view); - gGL.popMatrix(); - } + } // Tracy integration } static LLTrace::BlockTimerStatHandle FTM_SWAP("Swap"); @@ -1435,10 +1422,7 @@ void render_ui_3d() stop_glerror(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); // Coordinate axes if (gSavedSettings.getBOOL("ShowAxes")) @@ -1478,7 +1462,6 @@ void render_ui_2d() } stop_glerror(); - //gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); // render outline for HUD if (isAgentAvatarValid() && gAgentCamera.mHUDCurZoom < 0.98f) @@ -1568,10 +1551,7 @@ void render_ui_2d() void render_disconnected_background() { - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); gGL.color4f(1,1,1,1); if (!gDisconnectedImagep && gDisconnected) @@ -1643,11 +1623,7 @@ void render_disconnected_background() } gGL.flush(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } - + gUIProgram.unbind(); } void display_cleanup() diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 62d73063aa..dd03d6cfdd 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -193,6 +193,10 @@ LLFloaterOpenHandler gFloaterOpenHandler; void LLViewerFloaterReg::registerFloaters() { + if (gNonInteractive) + { + return; + } // *NOTE: Please keep these alphabetized for easier merges LLFloaterAboutUtil::registerFloater(); diff --git a/indra/newview/llviewerjointattachment.cpp b/indra/newview/llviewerjointattachment.cpp index 8a597ed7e6..fd314ed3dc 100644 --- a/indra/newview/llviewerjointattachment.cpp +++ b/indra/newview/llviewerjointattachment.cpp @@ -121,8 +121,7 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object) object->mDrawable->mXform.setRotation(current_rot); gPipeline.markMoved(object->mDrawable); gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD - object->mDrawable->setState(LLDrawable::USE_BACKLIGHT); - + if(mIsHUDAttachment) { for (S32 face_num = 0; face_num < object->mDrawable->getNumFaces(); face_num++) @@ -142,7 +141,6 @@ void LLViewerJointAttachment::setupDrawable(LLViewerObject *object) LLViewerObject* childp = *iter; if (childp && childp->mDrawable.notNull()) { - childp->mDrawable->setState(LLDrawable::USE_BACKLIGHT); gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD gPipeline.markMoved(childp->mDrawable); @@ -256,7 +254,6 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) object->mDrawable->mXform.setRotation(cur_rotation); gPipeline.markMoved(object->mDrawable, TRUE); gPipeline.markTextured(object->mDrawable); // face may need to change draw pool to/from POOL_HUD - object->mDrawable->clearState(LLDrawable::USE_BACKLIGHT); if (mIsHUDAttachment) { @@ -278,7 +275,6 @@ void LLViewerJointAttachment::removeObject(LLViewerObject *object) LLViewerObject* childp = *iter; if (childp && childp->mDrawable.notNull()) { - childp->mDrawable->clearState(LLDrawable::USE_BACKLIGHT); gPipeline.markTextured(childp->mDrawable); // face may need to change draw pool to/from POOL_HUD if (mIsHUDAttachment) { diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index 63ad708e59..f3b0e82b3a 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -225,7 +225,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) if (!mValid || !mMesh || !mFace || !mVisible || !mFace->getVertexBuffer() || mMesh->getNumFaces() == 0 || - (LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShaderPtr == NULL)) + LLGLSLShader::sCurBoundShaderPtr == NULL) { return 0; } @@ -246,7 +246,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) stop_glerror(); - LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), (mFace->getPool()->getShaderLevel() > 0 || LLGLSLShader::sNoFixedFunction) ? 0.f : mShiny); + LLGLSSpecular specular(LLColor4(1.f,1.f,1.f,1.f), 0.f); //---------------------------------------------------------------- // setup current texture @@ -265,7 +265,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) else { gGL.diffuseColor4f(0.7f, 0.6f, 0.3f, 1.f); - gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR); } } else if( !is_dummy && layerset ) @@ -328,11 +327,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) triangle_count += count; - if (mTestImageName) - { - gGL.getTexUnit(diffuse_channel)->setTextureBlendType(LLTexUnit::TB_MULT); - } - return triangle_count; } @@ -362,7 +356,6 @@ void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 //----------------------------------------------------------------------------- // updateFaceData() //----------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_AVATAR_FACE("Avatar Face"); void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update) { @@ -383,9 +376,8 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w // since mMesh is being copied into mVertexBuffer every frame return; } - - - LL_RECORD_BLOCK_TIME(FTM_AVATAR_FACE); + + LL_PROFILE_ZONE_SCOPED; LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 29c926ca64..812f804ea9 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -39,6 +39,7 @@ #include "llfilepicker.h" #include "llfloaterwebcontent.h" // for handling window close requests and geometry change requests in media browser windows. #include "llfocusmgr.h" +#include "llimagegl.h" #include "llkeyboard.h" #include "lllogininstance.h" #include "llmarketplacefunctions.h" @@ -606,6 +607,7 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE("Update Media"); static LLTrace::BlockTimerStatHandle FTM_MEDIA_SPARE_IDLE("Spare Idle"); static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_INTEREST("Update/Interest"); +static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_VOLUME("Update/Volume"); static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT("Media Sort"); static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT2("Media Sort 2"); static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc"); @@ -620,11 +622,18 @@ void LLViewerMedia::onIdle(void *dummy_arg) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMedia::updateMedia(void *dummy_arg) { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE); // Enable/disable the plugin read thread LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); + // SL-16418 We can't call LLViewerMediaImpl->update() if we are in the state of shutting down. + if(LLApp::isExiting()) + { + setAllMediaEnabled(false); + return; + } + // HACK: we always try to keep a spare running webkit plugin around to improve launch times. // 2017-04-19 Removed CP - this doesn't appear to buy us much and consumes a lot of resources so // removing it for now. @@ -637,7 +646,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg) impl_list::iterator end = sViewerMediaImplList.end(); { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST); + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media update interest"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_INTEREST); for(; iter != end;) { LLViewerMediaImpl* pimpl = *iter++; @@ -649,12 +658,12 @@ void LLViewerMedia::updateMedia(void *dummy_arg) // Let the spare media source actually launch if(mSpareBrowserMediaSource) { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE); + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media spare idle"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SPARE_IDLE); mSpareBrowserMediaSource->idle(); } { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT); + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media sort"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT); // Sort the static instance list using our interest criteria sViewerMediaImplList.sort(priorityComparitor); } @@ -686,7 +695,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg) // If max_normal + max_low is less than max_instances, things will tend to get unloaded instead of being set to slideshow. { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC); + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media misc"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_MISC); for(; iter != end; iter++) { LLViewerMediaImpl* pimpl = *iter; @@ -871,7 +880,7 @@ void LLViewerMedia::updateMedia(void *dummy_arg) } else { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2); + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media sort2"); // LL_RECORD_BLOCK_TIME(FTM_MEDIA_SORT2); // Use a distance-based sort for proximity values. std::stable_sort(proximity_order.begin(), proximity_order.end(), proximity_comparitor); } @@ -1187,7 +1196,7 @@ LLCore::HttpHeaders::ptr_t LLViewerMedia::getHttpHeaders() ///////////////////////////////////////////////////////////////////////////////////////// void LLViewerMedia::setOpenIDCookie(const std::string& url) { - if(!mOpenIDCookie.empty()) + if(!gNonInteractive && !mOpenIDCookie.empty()) { std::string profileUrl = getProfileURL(""); @@ -1561,6 +1570,8 @@ LLViewerMediaImpl::LLViewerMediaImpl( const LLUUID& texture_id, media_tex->setMediaImpl(); } + mMainQueue = LL::WorkQueue::getInstance("mainloop"); + mTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader. } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1647,11 +1658,13 @@ void LLViewerMediaImpl::destroyMediaSource() cancelMimeTypeProbe(); + mLock.lock(); // Delay tear-down while bg thread is updating if(mMediaSource) { mMediaSource->setDeleteOK(true) ; mMediaSource = NULL; // shared pointer } + mLock.unlock(); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1664,6 +1677,11 @@ void LLViewerMediaImpl::setMediaType(const std::string& media_type) /*static*/ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height, F64 zoom_factor, const std::string target, bool clean_browser) { + if (gNonInteractive) + { + return NULL; + } + std::string plugin_basename = LLMIMETypes::implType(media_type); LLPluginClassMedia* media_source = NULL; @@ -2055,6 +2073,7 @@ void LLViewerMediaImpl::setMute(bool mute) ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::updateVolume() { + LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_VOLUME); if(mMediaSource) { // always scale the volume by the global media volume @@ -2766,200 +2785,272 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage"); void LLViewerMediaImpl::update() { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE); - if(mMediaSource == NULL) - { - if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) - { - // This media source should not be loaded. - } - else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) - { - // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE); + if(mMediaSource == NULL) + { + if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED) + { + // This media source should not be loaded. + } + else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW) + { + // Don't load new instances that are at PRIORITY_SLIDESHOW or below. They're just kept around to preserve state. + } else if (!mMimeProbe.expired()) - { - // this media source is doing a MIME type probe -- don't try loading it again. - } - else - { - // This media may need to be loaded. - if(sMediaCreateTimer.hasExpired()) - { - LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; - createMediaSource(); - sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); - } - else - { - LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; - } - } - } - else - { - updateVolume(); + { + // this media source is doing a MIME type probe -- don't try loading it again. + } + else + { + // This media may need to be loaded. + if(sMediaCreateTimer.hasExpired()) + { + LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL; + createMediaSource(); + sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY); + } + else + { + LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL; + } + } + } + else + { + updateVolume(); - // TODO: this is updated every frame - is this bad? - // Removing this as part of the post viewer64 media update - // Removed as not implemented in CEF embedded browser - // See MAINT-8194 for a more fuller description - // updateJavascriptObject(); - } + // TODO: this is updated every frame - is this bad? + // Removing this as part of the post viewer64 media update + // Removed as not implemented in CEF embedded browser + // See MAINT-8194 for a more fuller description + // updateJavascriptObject(); + } - if(mMediaSource == NULL) - { - return; - } + if(mMediaSource == NULL) + { + return; + } - // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. - setNavigateSuspended(true); + // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. + setNavigateSuspended(true); - mMediaSource->idle(); + mMediaSource->idle(); - setNavigateSuspended(false); + setNavigateSuspended(false); - if(mMediaSource == NULL) - { - return; - } + if(mMediaSource == NULL) + { + return; + } - if(mMediaSource->isPluginExited()) - { - resetPreviousMediaState(); - destroyMediaSource(); - return; - } + if(mMediaSource->isPluginExited()) + { + resetPreviousMediaState(); + destroyMediaSource(); + return; + } - if(!mMediaSource->textureValid()) - { - return; - } + if(!mMediaSource->textureValid()) + { + return; + } - if(mSuspendUpdates || !mVisible) - { - return; - } + if(mSuspendUpdates || !mVisible) + { + return; + } - LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); + + LLViewerMediaTexture* media_tex; + U8* data; + S32 data_width; + S32 data_height; + S32 x_pos; + S32 y_pos; + S32 width; + S32 height; + + if (preMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height)) + { + // Push update to worker thread + auto main_queue = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr; + if (main_queue) + { + mTextureUpdatePending = true; + ref(); // protect texture from deletion while active on bg queue + media_tex->ref(); + main_queue->postTo( + mTexUpdateQueue, // Worker thread queue + [=]() // work done on update worker thread + { +#if LL_IMAGEGL_THREAD_CHECK + media_tex->getGLTexture()->mActiveThread = LLThread::currentID(); +#endif + doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, true); + }, + [=]() // callback to main thread + { +#if LL_IMAGEGL_THREAD_CHECK + media_tex->getGLTexture()->mActiveThread = LLThread::currentID(); +#endif + mTextureUpdatePending = false; + media_tex->unref(); + unref(); + }); + } + else + { + doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, false); // otherwise, update on main thread + } + } +} - if(placeholder_image) - { - LLRect dirty_rect; +bool LLViewerMediaImpl::preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; - // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. - placeholder_image->setPlaying(TRUE); + bool retval = false; - if(mMediaSource->getDirty(&dirty_rect)) - { - // Constrain the dirty rect to be inside the texture - S32 x_pos = llmax(dirty_rect.mLeft, 0); - S32 y_pos = llmax(dirty_rect.mBottom, 0); - S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; - S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; + if (!mTextureUpdatePending) + { + media_tex = updateMediaImage(); - if(width > 0 && height > 0) - { + if (media_tex && mMediaSource) + { + LLRect dirty_rect; + S32 media_width = mMediaSource->getTextureWidth(); + S32 media_height = mMediaSource->getTextureHeight(); + //S32 media_depth = mMediaSource->getTextureDepth(); - U8* data = NULL; - { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA); - data = mMediaSource->getBitsData(); - } + // Since we're updating this texture, we know it's playing. Tell the texture to do its replacement magic so it gets rendered. + media_tex->setPlaying(TRUE); - if(data != NULL) - { - // Offset the pixels pointer to match x_pos and y_pos - data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); - data += ( y_pos * mMediaSource->getTextureDepth() ); + if (mMediaSource->getDirty(&dirty_rect)) + { + // Constrain the dirty rect to be inside the texture + x_pos = llmax(dirty_rect.mLeft, 0); + y_pos = llmax(dirty_rect.mBottom, 0); + width = llmin(dirty_rect.mRight, media_width) - x_pos; + height = llmin(dirty_rect.mTop, media_height) - y_pos; - { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE); - placeholder_image->setSubImage( - data, - mMediaSource->getBitsWidth(), - mMediaSource->getBitsHeight(), - x_pos, - y_pos, - width, - height); - } - } + if (width > 0 && height > 0) + { + data = mMediaSource->getBitsData(); + data_width = mMediaSource->getWidth(); + data_height = mMediaSource->getHeight(); + + if (data != NULL) + { + // data is ready to be copied to GL + retval = true; + } + } - } + mMediaSource->resetDirty(); + } + } + } - mMediaSource->resetDirty(); - } - } + return retval; } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; + mLock.lock(); // don't allow media source tear-down during update + + // wrap "data" in an LLImageRaw but do NOT make a copy + LLPointer<LLImageRaw> raw = new LLImageRaw(data, media_tex->getWidth(), media_tex->getHeight(), media_tex->getComponents(), true); + + // Allocate GL texture based on LLImageRaw but do NOT copy to GL + LLGLuint tex_name = 0; + media_tex->createGLTexture(0, raw, 0, TRUE, LLGLTexture::OTHER, true, &tex_name); + + // copy just the subimage covered by the image raw to GL + media_tex->setSubImage(data, data_width, data_height, x_pos, y_pos, width, height, tex_name); + + if (sync) + { + media_tex->getGLTexture()->syncToMainThread(tex_name); + } + else + { + media_tex->getGLTexture()->syncTexName(tex_name); + } + + // release the data pointer before freeing raw so LLImageRaw destructor doesn't + // free memory at data pointer + raw->releaseData(); + + mLock.unlock(); +} ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::updateImagesMediaStreams() { } - ////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() +LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage() { - if(mTextureId.isNull()) - { - // The code that created this instance will read from the plugin's bits. - return NULL; - } - - LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); - - if (mNeedsNewTexture - || placeholder_image->getUseMipMaps() - || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) - || (placeholder_image->getHeight() != mMediaSource->getTextureHeight()) - || (mTextureUsedWidth != mMediaSource->getWidth()) - || (mTextureUsedHeight != mMediaSource->getHeight()) - ) - { - LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; - LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; - - int texture_width = mMediaSource->getTextureWidth(); - int texture_height = mMediaSource->getTextureHeight(); - int texture_depth = mMediaSource->getTextureDepth(); - - // MEDIAOPT: check to see if size actually changed before doing work - placeholder_image->destroyGLTexture(); - // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? - placeholder_image->reinit(FALSE); // probably not needed - - // MEDIAOPT: seems insane that we actually have to make an imageraw then - // immediately discard it - LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth); - // Clear the texture to the background color, ignoring alpha. - // convert background color channels from [0.0, 1.0] to [0, 255]; - raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); - int discard_level = 0; - - // ask media source for correct GL image format constants - placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), - mMediaSource->getTextureFormatPrimary(), - mMediaSource->getTextureFormatType(), - mMediaSource->getTextureFormatSwapBytes()); - - placeholder_image->createGLTexture(discard_level, raw); - - // MEDIAOPT: set this dynamically on play/stop - // FIXME -// placeholder_image->mIsMediaTexture = true; - mNeedsNewTexture = false; - - // If the amount of the texture being drawn by the media goes down in either width or height, - // recreate the texture to avoid leaving parts of the old image behind. - mTextureUsedWidth = mMediaSource->getWidth(); - mTextureUsedHeight = mMediaSource->getHeight(); - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; + if (!mMediaSource) + { + return nullptr; // not ready for updating + } - return placeholder_image; + llassert(!mTextureId.isNull()); + LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId ); + + if ( mNeedsNewTexture + || media_tex->getUseMipMaps() + || (media_tex->getWidth() != mMediaSource->getTextureWidth()) + || (media_tex->getHeight() != mMediaSource->getTextureHeight()) + || (mTextureUsedWidth != mMediaSource->getWidth()) + || (mTextureUsedHeight != mMediaSource->getHeight()) + ) + { + LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL; + LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL; + + int texture_width = mMediaSource->getTextureWidth(); + int texture_height = mMediaSource->getTextureHeight(); + int texture_depth = mMediaSource->getTextureDepth(); + + // MEDIAOPT: check to see if size actually changed before doing work + media_tex->destroyGLTexture(); + // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? + media_tex->reinit(FALSE); // probably not needed + + // MEDIAOPT: seems insane that we actually have to make an imageraw then + // immediately discard it + LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth); + // Clear the texture to the background color, ignoring alpha. + // convert background color channels from [0.0, 1.0] to [0, 255]; + raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff); + + // ask media source for correct GL image format constants + media_tex->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + mMediaSource->getTextureFormatSwapBytes()); + + int discard_level = 0; + media_tex->createGLTexture(discard_level, raw); + + // MEDIAOPT: set this dynamically on play/stop + // FIXME +// media_tex->mIsMediaTexture = true; + mNeedsNewTexture = false; + + // If the amount of the texture being drawn by the media goes down in either width or height, + // recreate the texture to avoid leaving parts of the old image behind. + mTextureUsedWidth = mMediaSource->getWidth(); + mTextureUsedHeight = mMediaSource->getHeight(); + } + return media_tex; } @@ -3459,7 +3550,7 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_CALCULATE_INTEREST("Calculate Int void LLViewerMediaImpl::calculateInterest() { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST); + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_CALCULATE_INTEREST); LLViewerMediaTexture* texture = LLViewerTextureManager::findMediaTexture( mTextureId ); if(texture != NULL) diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 71cec5125d..806692929a 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -197,7 +197,7 @@ public: U8 media_loop); ~LLViewerMediaImpl(); - + // Override inherited version from LLViewerMediaEventEmitter virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event); @@ -266,6 +266,8 @@ public: void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y); void update(); + bool preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height); + void doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync); void updateImagesMediaStreams(); LLUUID getMediaTextureID() const; @@ -427,6 +429,7 @@ private: private: // a single media url with some data and an impl. boost::shared_ptr<LLPluginClassMedia> mMediaSource; + LLMutex mLock; F64 mZoomFactor; LLUUID mTextureId; bool mMovieImageHasMips; @@ -446,6 +449,7 @@ private: S32 mTextureUsedWidth; S32 mTextureUsedHeight; bool mSuspendUpdates; + bool mTextureUpdatePending = false; bool mVisible; ECursorType mLastSetCursor; EMediaNavState mMediaNavState; @@ -479,7 +483,7 @@ private: LLNotificationPtr mNotification; bool mCleanBrowser; // force the creation of a clean browsing target with full options enabled static std::vector<std::string> sMimeTypesFailed; - + LLPointer<LLImageRaw> mRawImage; //backing buffer for texture updates private: BOOL mIsUpdated ; std::list< LLVOVolume* > mObjectList ; @@ -489,7 +493,10 @@ private: bool mCanceling; private: - LLViewerMediaTexture *updatePlaceholderImage(); + LLViewerMediaTexture *updateMediaImage(); + LL::WorkQueue::weak_t mMainQueue; + LL::WorkQueue::weak_t mTexUpdateQueue; + }; #endif // LLVIEWERMEDIA_H diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 4ca449b6ac..e3de4267dc 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -8412,6 +8412,7 @@ class LLViewHighlightTransparent : public view_listener_t bool handleEvent(const LLSD& userdata) { LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; + gPipeline.resetVertexBuffers(); return true; } }; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 10ffbc7fa7..a886303563 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -2219,11 +2219,9 @@ protected: } }; -static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMPROVED_IM("Process IM"); - void process_improved_im(LLMessageSystem *msg, void **user_data) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMPROVED_IM); + LL_PROFILE_ZONE_SCOPED; LLUUID from_id; BOOL from_group; @@ -2423,6 +2421,10 @@ void translateFailure(LLChat chat, LLSD toastArgs, int status, const std::string void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) { + if (gNonInteractive) + { + return; + } LLChat chat; std::string mesg; std::string from_name; @@ -3263,10 +3265,9 @@ const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f; // ~= 2.5 degrees -- if its less th const F32 MAX_HEAD_ROT_QDOT = 0.99999f; // ~= 0.5 degrees -- if its greater than this then no need to update head_rot // between these values we delay the updates (but no more than one second) -static LLTrace::BlockTimerStatHandle FTM_AGENT_UPDATE_SEND("Send Message"); - void send_agent_update(BOOL force_send, BOOL send_reliable) { + LL_PROFILE_ZONE_SCOPED; if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE) { // We don't care if they want to send an agent update, they're not allowed to until the simulator @@ -3447,7 +3448,6 @@ void send_agent_update(BOOL force_send, BOOL send_reliable) } */ - LL_RECORD_BLOCK_TIME(FTM_AGENT_UPDATE_SEND); // Build the message msg->newMessageFast(_PREHASH_AgentUpdate); msg->nextBlockFast(_PREHASH_AgentData); @@ -3697,11 +3697,9 @@ void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_ } } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Kill Objects"); - void process_kill_object(LLMessageSystem *mesgsys, void **user_data) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_OBJECTS); + LL_PROFILE_ZONE_SCOPED; LLUUID id; @@ -3989,8 +3987,8 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) F32 stat_value; msg->getU32("Stat", "StatID", stat_id, i); msg->getF32("Stat", "StatValue", stat_value, i); - LLStatViewer::SimMeasurementSampler* measurementp = LLStatViewer::SimMeasurementSampler::getInstance((ESimStatID)stat_id); - + auto measurementp = LLStatViewer::SimMeasurementSampler::getInstance((ESimStatID)stat_id); + if (measurementp ) { measurementp->sample(stat_value); diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 4c476e89ce..a95636ff23 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -107,6 +107,7 @@ #include "llcleanup.h" #include "llcallstack.h" #include "llmeshrepository.h" +#include "llgl.h" //#define DEBUG_UPDATE_TYPE @@ -145,21 +146,35 @@ const S32 MAX_OBJECT_BINARY_DATA_SIZE = 60 + 16; const F64 INVENTORY_UPDATE_WAIT_TIME_DESYNC = 5; // seconds const F64 INVENTORY_UPDATE_WAIT_TIME_OUTDATED = 1; -static LLTrace::BlockTimerStatHandle FTM_CREATE_OBJECT("Create Object"); - // static LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, S32 flags) { + LL_PROFILE_ZONE_SCOPED; LL_DEBUGS("ObjectUpdate") << "creating " << id << LL_ENDL; dumpStack("ObjectUpdateStack"); LLViewerObject *res = NULL; - LL_RECORD_BLOCK_TIME(FTM_CREATE_OBJECT); - + + if (gNonInteractive + && pcode != LL_PCODE_LEGACY_AVATAR + && pcode != LL_VO_SURFACE_PATCH + && pcode != LL_VO_WATER + && pcode != LL_VO_VOID_WATER + && pcode != LL_VO_WL_SKY + && pcode != LL_VO_SKY + && pcode != LL_VO_GROUND + && pcode != LL_VO_PART_GROUP + ) + { + return res; + } switch (pcode) { case LL_PCODE_VOLUME: - res = new LLVOVolume(id, pcode, regionp); break; + { + res = new LLVOVolume(id, pcode, regionp); break; + break; + } case LL_PCODE_LEGACY_AVATAR: { if (id == gAgentID) @@ -235,8 +250,7 @@ LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pco } LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp, BOOL is_global) -: LLTrace::MemTrackable<LLViewerObject>("LLViewerObject"), - LLPrimitive(), +: LLPrimitive(), mChildList(), mID(id), mLocalID(0), @@ -2502,9 +2516,6 @@ void LLViewerObject::loadFlags(U32 flags) void LLViewerObject::idleUpdate(LLAgent &agent, const F64 &frame_time) { - //static LLTrace::BlockTimerStatHandle ftm("Viewer Object"); - //LL_RECORD_BLOCK_TIME(ftm); - if (!mDead) { if (!mStatic && sVelocityInterpolate && !isSelected()) diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 250c4ac328..bef8e3e7e3 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -110,8 +110,7 @@ struct PotentialReturnableObject class LLViewerObject : public LLPrimitive, public LLRefCount, - public LLGLUpdate, - public LLTrace::MemTrackable<LLViewerObject> + public LLGLUpdate { protected: virtual ~LLViewerObject(); // use unref() diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index 63e48d1dd0..0e585f13fc 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -80,6 +80,7 @@ #include "llfloaterperms.h" #include "llvocache.h" #include "llcorehttputil.h" +#include "llstartup.h" #include <algorithm> #include <iterator> @@ -168,6 +169,8 @@ U64 LLViewerObjectList::getIndex(const U32 local_id, BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + if(objectp && objectp->getRegion()) { U32 local_id = objectp->mLocalID; @@ -303,9 +306,11 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_OBJECTS("Process Objects"); LLViewerObject* LLViewerObjectList::processObjectUpdateFromCache(LLVOCacheEntry* entry, LLViewerRegion* regionp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + LLDataPacker *cached_dpp = entry->getDP(); - if (!cached_dpp) + if (!cached_dpp || gNonInteractive) { return NULL; //nothing cached. } @@ -844,10 +849,10 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) LLVOAvatar::cullAvatarsByPixelArea(); } -static LLTrace::BlockTimerStatHandle FTM_IDLE_COPY("Idle Copy"); - void LLViewerObjectList::update(LLAgent &agent) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + // Update globals LLViewerObject::setVelocityInterpolate( gSavedSettings.getBOOL("VelocityInterpolate") ); LLViewerObject::setPingInterpolate( gSavedSettings.getBOOL("PingInterpolate") ); @@ -899,8 +904,6 @@ void LLViewerObjectList::update(LLAgent &agent) U32 idle_count = 0; { - LL_RECORD_BLOCK_TIME(FTM_IDLE_COPY); - for (std::vector<LLPointer<LLViewerObject> >::iterator active_iter = mActiveObjects.begin(); active_iter != mActiveObjects.end(); active_iter++) { @@ -1293,6 +1296,8 @@ void LLViewerObjectList::clearDebugText() void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + bool new_dead_object = true; if (mDeadObjects.find(objectp->mID) != mDeadObjects.end()) { @@ -1343,11 +1348,9 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp) } } -static LLTrace::BlockTimerStatHandle FTM_REMOVE_DRAWABLE("Remove Drawable"); - void LLViewerObjectList::removeDrawable(LLDrawable* drawablep) { - LL_RECORD_BLOCK_TIME(FTM_REMOVE_DRAWABLE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; if (!drawablep) { @@ -1523,6 +1526,8 @@ void LLViewerObjectList::removeFromActiveList(LLViewerObject* objectp) void LLViewerObjectList::updateActive(LLViewerObject *objectp) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; + if (objectp->isDead()) { return; // We don't update dead objects! @@ -1634,12 +1639,9 @@ void LLViewerObjectList::onPhysicsFlagsFetchFailure(const LLUUID& object_id) mPendingPhysicsFlags.erase(object_id); } -static LLTrace::BlockTimerStatHandle FTM_SHIFT_OBJECTS("Shift Objects"); -static LLTrace::BlockTimerStatHandle FTM_PIPELINE_SHIFT("Pipeline Shift"); -static LLTrace::BlockTimerStatHandle FTM_REGION_SHIFT("Region Shift"); - void LLViewerObjectList::shiftObjects(const LLVector3 &offset) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; // This is called when we shift our origin when we cross region boundaries... // We need to update many object caches, I'll document this more as I dig through the code // cleaning things out... @@ -1649,7 +1651,6 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) return; } - LL_RECORD_BLOCK_TIME(FTM_SHIFT_OBJECTS); LLViewerObject *objectp; for (vobj_list_t::iterator iter = mObjects.begin(); iter != mObjects.end(); ++iter) @@ -1667,16 +1668,10 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) } } - { - LL_RECORD_BLOCK_TIME(FTM_PIPELINE_SHIFT); gPipeline.shiftObjects(offset); - } - - { - LL_RECORD_BLOCK_TIME(FTM_REGION_SHIFT); + LLWorld::getInstance()->shiftRegions(offset); } -} void LLViewerObjectList::repartitionObjects() { @@ -1843,6 +1838,8 @@ void LLViewerObjectList::renderObjectBounds(const LLVector3 ¢er) void LLViewerObjectList::generatePickList(LLCamera &camera) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + LLViewerObject *objectp; S32 i; // Reset all of the GL names to zero. @@ -2051,7 +2048,6 @@ LLViewerObject *LLViewerObjectList::createObjectFromCache(const LLPCode pcode, L LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id, const LLHost &sender) { - LLUUID fullid; if (uuid == LLUUID::null) { @@ -2104,6 +2100,8 @@ LLViewerObject *LLViewerObjectList::replaceObject(const LLUUID &id, const LLPCod S32 LLViewerObjectList::findReferences(LLDrawable *drawablep) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; + LLViewerObject *objectp; S32 num_refs = 0; @@ -2167,6 +2165,8 @@ void LLViewerObjectList::orphanize(LLViewerObject *childp, U32 parent_id, U32 ip void LLViewerObjectList::findOrphans(LLViewerObject* objectp, U32 ip, U32 port) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; + if (objectp->isDead()) { LL_WARNS() << "Trying to find orphans for dead obj " << objectp->mID diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp index 6365df09e1..5eda75753e 100644 --- a/indra/newview/llvieweroctree.cpp +++ b/indra/newview/llvieweroctree.cpp @@ -32,6 +32,7 @@ #include "llappviewer.h" #include "llglslshader.h" #include "llviewershadermgr.h" +#include "lldrawpoolwater.h" //----------------------------------------------------------------------------------- //static variables definitions @@ -231,8 +232,7 @@ S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LL //class LLViewerOctreeEntry definitions //----------------------------------------------------------------------------------- LLViewerOctreeEntry::LLViewerOctreeEntry() -: LLTrace::MemTrackable<LLViewerOctreeEntry, 16>("LLViewerOctreeEntry"), - mGroup(NULL), +: mGroup(NULL), mBinRadius(0.f), mBinIndex(-1), mVisible(0) @@ -458,8 +458,7 @@ LLViewerOctreeGroup::~LLViewerOctreeGroup() } LLViewerOctreeGroup::LLViewerOctreeGroup(OctreeNode* node) -: LLTrace::MemTrackable<LLViewerOctreeGroup, 16>("LLViewerOctreeGroup"), - mOctreeNode(node), +: mOctreeNode(node), mAnyVisible(0), mState(CLEAN) { @@ -517,6 +516,7 @@ bool LLViewerOctreeGroup::removeFromGroup(LLViewerOctreeEntry* entry) //virtual void LLViewerOctreeGroup::unbound() { + LL_PROFILE_ZONE_SCOPED; if (isDirty()) { return; @@ -545,6 +545,7 @@ void LLViewerOctreeGroup::unbound() //virtual void LLViewerOctreeGroup::rebound() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE; if (!isDirty()) { return; @@ -786,42 +787,39 @@ void LLViewerOctreeGroup::checkStates() //occulsion culling functions and classes //------------------------------------------------------------------------------------------- std::set<U32> LLOcclusionCullingGroup::sPendingQueries; -class LLOcclusionQueryPool : public LLGLNamePool -{ -public: - LLOcclusionQueryPool() - { - } -protected: +static std::queue<GLuint> sFreeQueries; - virtual GLuint allocateName() - { - GLuint ret = 0; +#define QUERY_POOL_SIZE 1024 - glGenQueriesARB(1, &ret); - - return ret; - } - - virtual void releaseName(GLuint name) - { -#if LL_TRACK_PENDING_OCCLUSION_QUERIES - LLOcclusionCullingGroup::sPendingQueries.erase(name); -#endif - glDeleteQueriesARB(1, &name); - } -}; - -static LLOcclusionQueryPool sQueryPool; U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName() { - return sQueryPool.allocate(); + LL_PROFILE_ZONE_SCOPED; + + if (sFreeQueries.empty()) + { + //seed 1024 query names into the free query pool + GLuint queries[1024]; + glGenQueriesARB(1024, queries); + for (int i = 0; i < 1024; ++i) + { + sFreeQueries.push(queries[i]); + } + } + + // pull from pool + GLuint ret = sFreeQueries.front(); + sFreeQueries.pop(); + return ret; } void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(GLuint name) { - sQueryPool.release(name); + if (name != 0) + { + LL_PROFILE_ZONE_SCOPED; + sFreeQueries.push(name); + } } //===================================== @@ -932,47 +930,53 @@ void LLOcclusionCullingGroup::releaseOcclusionQueryObjectNames() } } -void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode) -{ - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialSetOcclusionStateDiff setter(state); - setter.traverse(mOctreeNode); - } - else if (mode == STATE_MODE_BRANCH) - { - LLSpatialSetOcclusionState setter(state); - setter.traverse(mOctreeNode); - } - else - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionState[i] |= state; - - if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) - { - releaseOcclusionQueryObjectName(mOcclusionQuery[i]); - mOcclusionQuery[i] = 0; - } - } - } - } - else - { - if (state & OCCLUDED) - { - add(sNumObjectsOccluded, 1); - } - mOcclusionState[LLViewerCamera::sCurCameraID] |= state; - if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; - } - } +void LLOcclusionCullingGroup::setOcclusionState(U32 state, S32 mode /* = STATE_MODE_SINGLE */ ) +{ + switch (mode) + { + case STATE_MODE_SINGLE: + if (state & OCCLUDED) + { + add(sNumObjectsOccluded, 1); + } + mOcclusionState[LLViewerCamera::sCurCameraID] |= state; + if ((state & DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) + { + releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; + } + break; + + case STATE_MODE_DIFF: + { + LLSpatialSetOcclusionStateDiff setter(state); + setter.traverse(mOctreeNode); + } + break; + + case STATE_MODE_BRANCH: + { + LLSpatialSetOcclusionState setter(state); + setter.traverse(mOctreeNode); + } + break; + + case STATE_MODE_ALL_CAMERAS: + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) + { + mOcclusionState[i] |= state; + + if ((state & DISCARD_QUERY) && mOcclusionQuery[i]) + { + releaseOcclusionQueryObjectName(mOcclusionQuery[i]); + mOcclusionQuery[i] = 0; + } + } + break; + + default: + break; + } } class LLSpatialClearOcclusionState : public OctreeTraveler @@ -1007,43 +1011,47 @@ public: } }; -void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode) -{ - if (mode > STATE_MODE_SINGLE) - { - if (mode == STATE_MODE_DIFF) - { - LLSpatialClearOcclusionStateDiff clearer(state); - clearer.traverse(mOctreeNode); - } - else if (mode == STATE_MODE_BRANCH) - { - LLSpatialClearOcclusionState clearer(state); - clearer.traverse(mOctreeNode); - } - else - { - for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) - { - mOcclusionState[i] &= ~state; - } - } - } - else - { - if (state & OCCLUDED) - { - add(sNumObjectsUnoccluded, 1); - } - mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state; - } +void LLOcclusionCullingGroup::clearOcclusionState(U32 state, S32 mode /* = STATE_MODE_SINGLE */) +{ + switch (mode) + { + case STATE_MODE_SINGLE: + if (state & OCCLUDED) + { + add(sNumObjectsUnoccluded, 1); + } + mOcclusionState[LLViewerCamera::sCurCameraID] &= ~state; + break; + + case STATE_MODE_DIFF: + { + LLSpatialClearOcclusionStateDiff clearer(state); + clearer.traverse(mOctreeNode); + } + break; + + case STATE_MODE_BRANCH: + { + LLSpatialClearOcclusionState clearer(state); + clearer.traverse(mOctreeNode); + } + break; + + case STATE_MODE_ALL_CAMERAS: + for (U32 i = 0; i < LLViewerCamera::NUM_CAMERAS; i++) + { + mOcclusionState[i] &= ~state; + } + break; + + default: + break; + } } -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_READBACK("Readback Occlusion"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_WAIT("Occlusion Wait"); - BOOL LLOcclusionCullingGroup::earlyFail(LLCamera* camera, const LLVector4a* bounds) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE; if (camera->getOrigin().isExactlyZero()) { return FALSE; @@ -1092,100 +1100,82 @@ U32 LLOcclusionCullingGroup::getLastOcclusionIssuedTime() void LLOcclusionCullingGroup::checkOcclusion() { - if (LLPipeline::sUseOcclusion > 1) - { - LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_READBACK); - LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent(); - if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED)) - { //if the parent has been marked as occluded, the child is implicitly occluded - clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); - } - else if (isOcclusionState(QUERY_PENDING)) - { //otherwise, if a query is pending, read it back - - GLuint available = 0; - if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - - static LLCachedControl<bool> wait_for_query(gSavedSettings, "RenderSynchronousOcclusion", true); - - if (wait_for_query && mOcclusionIssued[LLViewerCamera::sCurCameraID] < gFrameCount) - { //query was issued last frame, wait until it's available - S32 max_loop = 1024; - LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_WAIT); - while (!available && max_loop-- > 0) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); - } - } - } - else - { - available = 1; - } - - if (available) - { //result is available, read it back, otherwise wait until next frame - GLuint res = 1; - if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { - glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &res); + if (LLPipeline::sUseOcclusion < 2) return; // 0 - NoOcclusion, 1 = ReadOnly, 2 = ModifyOcclusionState TODO: DJH 11-2021 ENUM this + + LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE; + LLOcclusionCullingGroup* parent = (LLOcclusionCullingGroup*)getParent(); + if (parent && parent->isOcclusionState(LLOcclusionCullingGroup::OCCLUDED)) + { //if the parent has been marked as occluded, the child is implicitly occluded + clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); + return; + } + + if (mOcclusionQuery[LLViewerCamera::sCurCameraID] && isOcclusionState(QUERY_PENDING)) + { + if (isOcclusionState(DISCARD_QUERY)) + { // delete the query to avoid holding onto hundreds of pending queries + releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; + // mark non-occluded + clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); + clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); + } + else + { + GLuint available; + { + LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("co - query available"); + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_AVAILABLE_ARB, &available); + } + + if (available) + { + GLuint query_result; // Will be # samples drawn, or a boolean depending on mHasOcclusionQuery2 (both are type GLuint) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("co - query result"); + glGetQueryObjectuivARB(mOcclusionQuery[LLViewerCamera::sCurCameraID], GL_QUERY_RESULT_ARB, &query_result); + } #if LL_TRACK_PENDING_OCCLUSION_QUERIES - sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + sPendingQueries.erase(mOcclusionQuery[LLViewerCamera::sCurCameraID]); #endif - } - else if (mOcclusionQuery[LLViewerCamera::sCurCameraID]) - { //delete the query to avoid holding onto hundreds of pending queries - releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]); - mOcclusionQuery[LLViewerCamera::sCurCameraID] = 0; - } - - if (isOcclusionState(DISCARD_QUERY)) - { - res = 2; - } - if (res > 0) - { - assert_states_valid(this); - clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - else - { - assert_states_valid(this); - - setOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); - - assert_states_valid(this); - } - - clearOcclusionState(QUERY_PENDING | DISCARD_QUERY); - } - } - else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLOcclusionCullingGroup::OCCLUDED)) - { //check occlusion has been issued for occluded node that has not had a query issued - assert_states_valid(this); - clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); - assert_states_valid(this); - } - } +#if 0 // (12/2021) occasional false-negative occlusion tests produce water reflection errors, SL-16461 + // If/when water occlusion queries become 100% reliable, re-enable this optimization + + if (LLPipeline::RENDER_TYPE_WATER == mSpatialPartition->mDrawableType) + { + // Note any unoccluded water, for deciding on reflection/distortion passes + // (If occlusion is disabled, these are set within LLDrawPoolWater::render) + if (query_result > 0) + { + LLDrawPoolWater::sNeedsReflectionUpdate = TRUE; + LLDrawPoolWater::sNeedsDistortionUpdate = TRUE; + } + } +#endif + if (query_result > 0) + { + clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); + } + else + { + setOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); + } + clearOcclusionState(QUERY_PENDING); + } + } + } + else if (mSpatialPartition->isOcclusionEnabled() && isOcclusionState(LLOcclusionCullingGroup::OCCLUDED)) + { //check occlusion has been issued for occluded node that has not had a query issued + assert_states_valid(this); + clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); + assert_states_valid(this); + } } -static LLTrace::BlockTimerStatHandle FTM_PUSH_OCCLUSION_VERTS("Push Occlusion"); -static LLTrace::BlockTimerStatHandle FTM_SET_OCCLUSION_STATE("Occlusion State"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_EARLY_FAIL("Occlusion Early Fail"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_ALLOCATE("Allocate"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_BUILD("Build"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_BEGIN_QUERY("Begin Query"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_END_QUERY("End Query"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_SET_BUFFER("Set Buffer"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_DRAW_WATER("Draw Water"); -static LLTrace::BlockTimerStatHandle FTM_OCCLUSION_DRAW("Draw"); - void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* shift) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_OCTREE; if (mSpatialPartition->isOcclusionEnabled() && LLPipeline::sUseOcclusion > 1) { //move mBounds to the agent space if necessary @@ -1198,7 +1188,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh } F32 OCCLUSION_FUDGE_Z = SG_OCCLUSION_FUDGE; //<-- #Solution #2 - if (LLDrawPool::POOL_WATER == mSpatialPartition->mDrawableType) + if (LLPipeline::RENDER_TYPE_VOIDWATER == mSpatialPartition->mDrawableType) { OCCLUSION_FUDGE_Z = 1.; } @@ -1206,7 +1196,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh // Don't cull hole/edge water, unless we have the GL_ARB_depth_clamp extension if (earlyFail(camera, bounds)) { - LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_EARLY_FAIL); + LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - early fail"); setOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY); assert_states_valid(this); clearOcclusionState(LLOcclusionCullingGroup::OCCLUDED, LLOcclusionCullingGroup::STATE_MODE_DIFF); @@ -1217,11 +1207,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh if (!isOcclusionState(QUERY_PENDING) || isOcclusionState(DISCARD_QUERY)) { { //no query pending, or previous query to be discarded - LL_RECORD_BLOCK_TIME(FTM_RENDER_OCCLUSION); + LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - render"); if (!mOcclusionQuery[LLViewerCamera::sCurCameraID]) { - LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_ALLOCATE); mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName(); } @@ -1229,8 +1218,8 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh // behind the far clip plane, and in the case of edge water to avoid // it being culled while still visible. bool const use_depth_clamp = gGLManager.mHasDepthClamp && - (mSpatialPartition->mDrawableType == LLDrawPool::POOL_WATER || - mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER); + (mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_WATER || + mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_VOIDWATER); LLGLEnable clamp(use_depth_clamp ? GL_DEPTH_CLAMP : 0); @@ -1246,15 +1235,19 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh add(sOcclusionQueries, 1); { - LL_RECORD_BLOCK_TIME(FTM_PUSH_OCCLUSION_VERTS); + LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - push"); //store which frame this query was issued on mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount; - { - LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_BEGIN_QUERY); - glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); - } + { + LL_PROFILE_ZONE_NAMED("glBeginQuery"); + + //get an occlusion query that hasn't been used in awhile + releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]); + mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName(); + glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]); + } LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr; llassert(shader); @@ -1264,9 +1257,9 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh bounds[1][1]+SG_OCCLUSION_FUDGE, bounds[1][2]+OCCLUSION_FUDGE_Z); - if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLDrawPool::POOL_VOIDWATER) + if (!use_depth_clamp && mSpatialPartition->mDrawableType == LLPipeline::RENDER_TYPE_VOIDWATER) { - LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW_WATER); + LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - draw water"); LLGLSquashToFarClip squash; if (camera->getOrigin().isExactlyZero()) @@ -1281,7 +1274,7 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh } else { - LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_DRAW); + LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - draw"); if (camera->getOrigin().isExactlyZero()) { //origin is invalid, draw entire box gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, 0); @@ -1292,17 +1285,16 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh gPipeline.mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, bounds[0])); } } - - - { - LL_RECORD_BLOCK_TIME(FTM_OCCLUSION_END_QUERY); - glEndQueryARB(mode); - } + + { + LL_PROFILE_ZONE_NAMED("glEndQuery"); + glEndQueryARB(mode); + } } } { - LL_RECORD_BLOCK_TIME(FTM_SET_OCCLUSION_STATE); + LL_PROFILE_ZONE_NAMED_CATEGORY_OCTREE("doOcclusion - set state"); setOcclusionState(LLOcclusionCullingGroup::QUERY_PENDING); clearOcclusionState(LLOcclusionCullingGroup::DISCARD_QUERY); } diff --git a/indra/newview/llvieweroctree.h b/indra/newview/llvieweroctree.h index 219ec7e8da..11ba7e4f1e 100644 --- a/indra/newview/llvieweroctree.h +++ b/indra/newview/llvieweroctree.h @@ -71,8 +71,9 @@ S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVe //defines data needed for octree of an entry //LL_ALIGN_PREFIX(16) -class LLViewerOctreeEntry : public LLRefCount, public LLTrace::MemTrackable<LLViewerOctreeEntry, 16> +class LLViewerOctreeEntry : public LLRefCount { + LL_ALIGN_NEW friend class LLViewerOctreeEntryData; public: @@ -178,8 +179,9 @@ protected: //defines an octree group for an octree node, which contains multiple entries. //LL_ALIGN_PREFIX(16) class LLViewerOctreeGroup -: public LLOctreeListener<LLViewerOctreeEntry>, public LLTrace::MemTrackable<LLViewerOctreeGroup, 16> +: public LLOctreeListener<LLViewerOctreeEntry> { + LL_ALIGN_NEW friend class LLViewerOctreeCull; protected: virtual ~LLViewerOctreeGroup(); @@ -201,7 +203,6 @@ public: LLViewerOctreeGroup(OctreeNode* node); LLViewerOctreeGroup(const LLViewerOctreeGroup& rhs) - : LLTrace::MemTrackable<LLViewerOctreeGroup, 16>("LLViewerOctreeGroup") { *this = rhs; } diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 56370df751..e69b0347f8 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -878,7 +878,7 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const void LLViewerParcelMgr::render() { - if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection")) + if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected) { // Rendering is done in agent-coordinates, so need to supply // an appropriate offset to the render code. diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 7c3dd00e1a..02f7bbeed8 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -847,6 +847,7 @@ void LLViewerParcelOverlay::setDirty() void LLViewerParcelOverlay::updateGL() { + LL_PROFILE_ZONE_SCOPED updateOverlayTexture(); } diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index 2fb760ed17..67ad72e997 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -266,7 +266,14 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) return; } - regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton! + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; @@ -314,6 +321,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) regionp = NULL; impl = NULL; + world_inst = NULL; result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); if (STATE_WORLD_INIT > LLStartUp::getStartupState()) @@ -327,7 +335,14 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle) return; } - regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + world_inst = LLWorld::getInstance(); + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; @@ -411,7 +426,14 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) // This loop is used for retrying a capabilities request. do { - regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton! + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { LL_WARNS("AppInit", "Capabilities") << "Attempting to get capabilities for region that no longer exists!" << LL_ENDL; @@ -434,6 +456,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) LL_INFOS("AppInit", "Capabilities") << "Requesting second Seed from " << url << " for region " << regionp->getRegionID() << LL_ENDL; regionp = NULL; + world_inst = NULL; result = httpAdapter->postAndSuspend(httpRequest, url, capabilityNames); LLSD httpResults = result["http_result"]; @@ -449,7 +472,14 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCompleteCoro(U64 regionHandle) break; } - regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + world_inst = LLWorld::getInstance(); + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Received capabilities, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { LL_WARNS("AppInit", "Capabilities") << "Received capabilities for region that no longer exists!" << LL_ENDL; @@ -533,7 +563,14 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region break; } - regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton! + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to request Sim Feature, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to request Sim Feature for region that no longer exists!" << LL_ENDL; @@ -541,6 +578,7 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region } regionp = NULL; + world_inst = NULL; LLSD result = httpAdapter->getAndSuspend(httpRequest, url); LLSD httpResults = result["http_result"]; @@ -559,7 +597,14 @@ void LLViewerRegionImpl::requestSimulatorFeatureCoro(std::string url, U64 region // remove the http_result from the llsd result.erase("http_result"); - regionp = LLWorld::getInstance()->getRegionFromHandle(regionHandle); + world_inst = LLWorld::getInstance(); + if (!world_inst) + { + LL_WARNS("AppInit", "Capabilities") << "Attempting to request Sim Feature, but world no longer exists!" << LL_ENDL; + return; + } + + regionp = world_inst->getRegionFromHandle(regionHandle); if (!regionp) //region was removed { LL_WARNS("AppInit", "SimulatorFeatures") << "Attempting to set Sim Feature for region that no longer exists!" << LL_ENDL; @@ -2092,7 +2137,14 @@ public: const LLSD& input) const { LLHost host(input["sender"].asString()); - LLViewerRegion* region = LLWorld::getInstance()->getRegion(host); + + LLWorld *world_inst = LLWorld::getInstance(); // Not a singleton! + if (!world_inst) + { + return; + } + + LLViewerRegion* region = world_inst->getRegion(host); if( !region ) { return; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 945b51d819..1cb2c6b9ee 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -77,6 +77,7 @@ LLGLSLShader gTransformTangentProgram; //utility shaders LLGLSLShader gOcclusionProgram; +LLGLSLShader gSkinnedOcclusionProgram; LLGLSLShader gOcclusionCubeProgram; LLGLSLShader gCustomAlphaProgram; LLGLSLShader gGlowCombineProgram; @@ -87,6 +88,7 @@ LLGLSLShader gTwoTextureCompareProgram; LLGLSLShader gOneTextureFilterProgram; LLGLSLShader gOneTextureNoColorProgram; LLGLSLShader gDebugProgram; +LLGLSLShader gSkinnedDebugProgram; LLGLSLShader gClipProgram; LLGLSLShader gDownsampleDepthProgram; LLGLSLShader gDownsampleDepthRectProgram; @@ -96,56 +98,50 @@ LLGLSLShader gBenchmarkProgram; //object shaders LLGLSLShader gObjectSimpleProgram; +LLGLSLShader gSkinnedObjectSimpleProgram; LLGLSLShader gObjectSimpleImpostorProgram; +LLGLSLShader gSkinnedObjectSimpleImpostorProgram; LLGLSLShader gObjectPreviewProgram; +LLGLSLShader gPhysicsPreviewProgram; LLGLSLShader gObjectSimpleWaterProgram; +LLGLSLShader gSkinnedObjectSimpleWaterProgram; LLGLSLShader gObjectSimpleAlphaMaskProgram; +LLGLSLShader gSkinnedObjectSimpleAlphaMaskProgram; LLGLSLShader gObjectSimpleWaterAlphaMaskProgram; +LLGLSLShader gSkinnedObjectSimpleWaterAlphaMaskProgram; LLGLSLShader gObjectFullbrightProgram; +LLGLSLShader gSkinnedObjectFullbrightProgram; LLGLSLShader gObjectFullbrightWaterProgram; +LLGLSLShader gSkinnedObjectFullbrightWaterProgram; LLGLSLShader gObjectEmissiveProgram; +LLGLSLShader gSkinnedObjectEmissiveProgram; LLGLSLShader gObjectEmissiveWaterProgram; +LLGLSLShader gSkinnedObjectEmissiveWaterProgram; LLGLSLShader gObjectFullbrightAlphaMaskProgram; +LLGLSLShader gSkinnedObjectFullbrightAlphaMaskProgram; LLGLSLShader gObjectFullbrightWaterAlphaMaskProgram; +LLGLSLShader gSkinnedObjectFullbrightWaterAlphaMaskProgram; LLGLSLShader gObjectFullbrightShinyProgram; +LLGLSLShader gSkinnedObjectFullbrightShinyProgram; LLGLSLShader gObjectFullbrightShinyWaterProgram; +LLGLSLShader gSkinnedObjectFullbrightShinyWaterProgram; LLGLSLShader gObjectShinyProgram; +LLGLSLShader gSkinnedObjectShinyProgram; LLGLSLShader gObjectShinyWaterProgram; +LLGLSLShader gSkinnedObjectShinyWaterProgram; LLGLSLShader gObjectBumpProgram; +LLGLSLShader gSkinnedObjectBumpProgram; LLGLSLShader gTreeProgram; LLGLSLShader gTreeWaterProgram; LLGLSLShader gObjectFullbrightNoColorProgram; LLGLSLShader gObjectFullbrightNoColorWaterProgram; -LLGLSLShader gObjectSimpleNonIndexedProgram; LLGLSLShader gObjectSimpleNonIndexedTexGenProgram; LLGLSLShader gObjectSimpleNonIndexedTexGenWaterProgram; -LLGLSLShader gObjectSimpleNonIndexedWaterProgram; LLGLSLShader gObjectAlphaMaskNonIndexedProgram; LLGLSLShader gObjectAlphaMaskNonIndexedWaterProgram; LLGLSLShader gObjectAlphaMaskNoColorProgram; LLGLSLShader gObjectAlphaMaskNoColorWaterProgram; -LLGLSLShader gObjectFullbrightNonIndexedProgram; -LLGLSLShader gObjectFullbrightNonIndexedWaterProgram; -LLGLSLShader gObjectEmissiveNonIndexedProgram; -LLGLSLShader gObjectEmissiveNonIndexedWaterProgram; -LLGLSLShader gObjectFullbrightShinyNonIndexedProgram; -LLGLSLShader gObjectFullbrightShinyNonIndexedWaterProgram; -LLGLSLShader gObjectShinyNonIndexedProgram; -LLGLSLShader gObjectShinyNonIndexedWaterProgram; - -//object hardware skinning shaders -LLGLSLShader gSkinnedObjectSimpleProgram; -LLGLSLShader gSkinnedObjectFullbrightProgram; -LLGLSLShader gSkinnedObjectEmissiveProgram; -LLGLSLShader gSkinnedObjectFullbrightShinyProgram; -LLGLSLShader gSkinnedObjectShinySimpleProgram; - -LLGLSLShader gSkinnedObjectSimpleWaterProgram; -LLGLSLShader gSkinnedObjectFullbrightWaterProgram; -LLGLSLShader gSkinnedObjectEmissiveWaterProgram; -LLGLSLShader gSkinnedObjectFullbrightShinyWaterProgram; -LLGLSLShader gSkinnedObjectShinySimpleWaterProgram; //environment shaders LLGLSLShader gTerrainProgram; @@ -156,6 +152,7 @@ LLGLSLShader gUnderWaterProgram; //interface shaders LLGLSLShader gHighlightProgram; +LLGLSLShader gSkinnedHighlightProgram; LLGLSLShader gHighlightNormalProgram; LLGLSLShader gHighlightSpecularProgram; @@ -191,17 +188,18 @@ LLGLSLShader gDeferredWaterProgram; LLGLSLShader gDeferredUnderWaterProgram; LLGLSLShader gDeferredDiffuseProgram; LLGLSLShader gDeferredDiffuseAlphaMaskProgram; +LLGLSLShader gDeferredSkinnedDiffuseAlphaMaskProgram; LLGLSLShader gDeferredNonIndexedDiffuseProgram; LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskProgram; LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram; LLGLSLShader gDeferredSkinnedDiffuseProgram; LLGLSLShader gDeferredSkinnedBumpProgram; -LLGLSLShader gDeferredSkinnedAlphaProgram; LLGLSLShader gDeferredBumpProgram; LLGLSLShader gDeferredTerrainProgram; LLGLSLShader gDeferredTerrainWaterProgram; LLGLSLShader gDeferredTreeProgram; LLGLSLShader gDeferredTreeShadowProgram; +LLGLSLShader gDeferredSkinnedTreeShadowProgram; LLGLSLShader gDeferredAvatarProgram; LLGLSLShader gDeferredAvatarAlphaProgram; LLGLSLShader gDeferredLightProgram; @@ -213,9 +211,12 @@ LLGLSLShader gDeferredBlurLightProgram; LLGLSLShader gDeferredSoftenProgram; LLGLSLShader gDeferredSoftenWaterProgram; LLGLSLShader gDeferredShadowProgram; +LLGLSLShader gDeferredSkinnedShadowProgram; LLGLSLShader gDeferredShadowCubeProgram; LLGLSLShader gDeferredShadowAlphaMaskProgram; +LLGLSLShader gDeferredSkinnedShadowAlphaMaskProgram; LLGLSLShader gDeferredShadowFullbrightAlphaMaskProgram; +LLGLSLShader gDeferredSkinnedShadowFullbrightAlphaMaskProgram; LLGLSLShader gDeferredAvatarShadowProgram; LLGLSLShader gDeferredAvatarAlphaShadowProgram; LLGLSLShader gDeferredAvatarAlphaMaskShadowProgram; @@ -223,14 +224,20 @@ LLGLSLShader gDeferredAttachmentShadowProgram; LLGLSLShader gDeferredAttachmentAlphaShadowProgram; LLGLSLShader gDeferredAttachmentAlphaMaskShadowProgram; LLGLSLShader gDeferredAlphaProgram; +LLGLSLShader gDeferredSkinnedAlphaProgram; LLGLSLShader gDeferredAlphaImpostorProgram; +LLGLSLShader gDeferredSkinnedAlphaImpostorProgram; LLGLSLShader gDeferredAlphaWaterProgram; +LLGLSLShader gDeferredSkinnedAlphaWaterProgram; LLGLSLShader gDeferredAvatarEyesProgram; LLGLSLShader gDeferredFullbrightProgram; LLGLSLShader gDeferredFullbrightAlphaMaskProgram; LLGLSLShader gDeferredFullbrightWaterProgram; +LLGLSLShader gDeferredSkinnedFullbrightWaterProgram; LLGLSLShader gDeferredFullbrightAlphaMaskWaterProgram; +LLGLSLShader gDeferredSkinnedFullbrightAlphaMaskWaterProgram; LLGLSLShader gDeferredEmissiveProgram; +LLGLSLShader gDeferredSkinnedEmissiveProgram; LLGLSLShader gDeferredPostProgram; LLGLSLShader gDeferredCoFProgram; LLGLSLShader gDeferredDoFCombineProgram; @@ -243,14 +250,31 @@ LLGLSLShader gDeferredWLSunProgram; LLGLSLShader gDeferredWLMoonProgram; LLGLSLShader gDeferredStarProgram; LLGLSLShader gDeferredFullbrightShinyProgram; -LLGLSLShader gDeferredSkinnedFullbrightShinyProgram; +LLGLSLShader gDeferredSkinnedFullbrightShinyProgram; LLGLSLShader gDeferredSkinnedFullbrightProgram; +LLGLSLShader gDeferredSkinnedFullbrightAlphaMaskProgram; LLGLSLShader gNormalMapGenProgram; // Deferred materials shaders LLGLSLShader gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2]; LLGLSLShader gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2]; +//helper for making a rigged variant of a given shader +bool make_rigged_variant(LLGLSLShader& shader, LLGLSLShader& riggedShader) +{ + riggedShader.mName = llformat("Skinned %s", shader.mName.c_str()); + riggedShader.mFeatures = shader.mFeatures; + riggedShader.mFeatures.hasObjectSkinning = true; + riggedShader.mDefines = shader.mDefines; // NOTE: Must come before addPermutation + riggedShader.addPermutation("HAS_SKIN", "1"); + riggedShader.mShaderFiles = shader.mShaderFiles; + riggedShader.mShaderLevel = shader.mShaderLevel; + riggedShader.mShaderGroup = shader.mShaderGroup; + + shader.mRiggedVariant = &riggedShader; + return riggedShader.createShader(NULL, NULL); +} + LLViewerShaderMgr::LLViewerShaderMgr() : mShaderLevel(SHADER_COUNT, 0), mMaxAvatarShaderLevel(0) @@ -263,75 +287,77 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gWLMoonProgram); mShaderList.push_back(&gAvatarProgram); mShaderList.push_back(&gObjectShinyProgram); - mShaderList.push_back(&gObjectShinyNonIndexedProgram); + mShaderList.push_back(&gSkinnedObjectShinyProgram); mShaderList.push_back(&gWaterProgram); mShaderList.push_back(&gWaterEdgeProgram); mShaderList.push_back(&gAvatarEyeballProgram); mShaderList.push_back(&gObjectSimpleProgram); + mShaderList.push_back(&gSkinnedObjectSimpleProgram); mShaderList.push_back(&gObjectSimpleImpostorProgram); + mShaderList.push_back(&gSkinnedObjectSimpleImpostorProgram); mShaderList.push_back(&gObjectPreviewProgram); mShaderList.push_back(&gImpostorProgram); mShaderList.push_back(&gObjectFullbrightNoColorProgram); mShaderList.push_back(&gObjectFullbrightNoColorWaterProgram); mShaderList.push_back(&gObjectSimpleAlphaMaskProgram); + mShaderList.push_back(&gSkinnedObjectSimpleAlphaMaskProgram); mShaderList.push_back(&gObjectBumpProgram); + mShaderList.push_back(&gSkinnedObjectBumpProgram); mShaderList.push_back(&gObjectEmissiveProgram); + mShaderList.push_back(&gSkinnedObjectEmissiveProgram); mShaderList.push_back(&gObjectEmissiveWaterProgram); + mShaderList.push_back(&gSkinnedObjectEmissiveWaterProgram); mShaderList.push_back(&gObjectFullbrightProgram); + mShaderList.push_back(&gSkinnedObjectFullbrightProgram); mShaderList.push_back(&gObjectFullbrightAlphaMaskProgram); + mShaderList.push_back(&gSkinnedObjectFullbrightAlphaMaskProgram); mShaderList.push_back(&gObjectFullbrightShinyProgram); + mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram); mShaderList.push_back(&gObjectFullbrightShinyWaterProgram); - mShaderList.push_back(&gObjectSimpleNonIndexedProgram); + mShaderList.push_back(&gSkinnedObjectFullbrightShinyWaterProgram); mShaderList.push_back(&gObjectSimpleNonIndexedTexGenProgram); mShaderList.push_back(&gObjectSimpleNonIndexedTexGenWaterProgram); - mShaderList.push_back(&gObjectSimpleNonIndexedWaterProgram); mShaderList.push_back(&gObjectAlphaMaskNonIndexedProgram); mShaderList.push_back(&gObjectAlphaMaskNonIndexedWaterProgram); mShaderList.push_back(&gObjectAlphaMaskNoColorProgram); mShaderList.push_back(&gObjectAlphaMaskNoColorWaterProgram); mShaderList.push_back(&gTreeProgram); mShaderList.push_back(&gTreeWaterProgram); - mShaderList.push_back(&gObjectFullbrightNonIndexedProgram); - mShaderList.push_back(&gObjectFullbrightNonIndexedWaterProgram); - mShaderList.push_back(&gObjectEmissiveNonIndexedProgram); - mShaderList.push_back(&gObjectEmissiveNonIndexedWaterProgram); - mShaderList.push_back(&gObjectFullbrightShinyNonIndexedProgram); - mShaderList.push_back(&gObjectFullbrightShinyNonIndexedWaterProgram); - mShaderList.push_back(&gSkinnedObjectSimpleProgram); - mShaderList.push_back(&gSkinnedObjectFullbrightProgram); - mShaderList.push_back(&gSkinnedObjectEmissiveProgram); - mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram); - mShaderList.push_back(&gSkinnedObjectShinySimpleProgram); - mShaderList.push_back(&gSkinnedObjectSimpleWaterProgram); - mShaderList.push_back(&gSkinnedObjectFullbrightWaterProgram); - mShaderList.push_back(&gSkinnedObjectEmissiveWaterProgram); - mShaderList.push_back(&gSkinnedObjectFullbrightShinyWaterProgram); - mShaderList.push_back(&gSkinnedObjectShinySimpleWaterProgram); mShaderList.push_back(&gTerrainProgram); mShaderList.push_back(&gTerrainWaterProgram); mShaderList.push_back(&gObjectSimpleWaterProgram); + mShaderList.push_back(&gSkinnedObjectSimpleWaterProgram); mShaderList.push_back(&gObjectFullbrightWaterProgram); + mShaderList.push_back(&gSkinnedObjectFullbrightWaterProgram); mShaderList.push_back(&gObjectSimpleWaterAlphaMaskProgram); + mShaderList.push_back(&gSkinnedObjectSimpleWaterAlphaMaskProgram); mShaderList.push_back(&gObjectFullbrightWaterAlphaMaskProgram); + mShaderList.push_back(&gSkinnedObjectFullbrightWaterAlphaMaskProgram); mShaderList.push_back(&gAvatarWaterProgram); mShaderList.push_back(&gObjectShinyWaterProgram); - mShaderList.push_back(&gObjectShinyNonIndexedWaterProgram); + mShaderList.push_back(&gSkinnedObjectShinyWaterProgram); mShaderList.push_back(&gUnderWaterProgram); mShaderList.push_back(&gDeferredSunProgram); mShaderList.push_back(&gDeferredSoftenProgram); mShaderList.push_back(&gDeferredSoftenWaterProgram); mShaderList.push_back(&gDeferredAlphaProgram); + mShaderList.push_back(&gDeferredSkinnedAlphaProgram); mShaderList.push_back(&gDeferredAlphaImpostorProgram); + mShaderList.push_back(&gDeferredSkinnedAlphaImpostorProgram); mShaderList.push_back(&gDeferredAlphaWaterProgram); - mShaderList.push_back(&gDeferredSkinnedAlphaProgram); + mShaderList.push_back(&gDeferredSkinnedAlphaWaterProgram); mShaderList.push_back(&gDeferredFullbrightProgram); mShaderList.push_back(&gDeferredFullbrightAlphaMaskProgram); mShaderList.push_back(&gDeferredFullbrightWaterProgram); - mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram); + mShaderList.push_back(&gDeferredSkinnedFullbrightWaterProgram); + mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram); + mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskWaterProgram); mShaderList.push_back(&gDeferredFullbrightShinyProgram); - mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram); + mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram); mShaderList.push_back(&gDeferredSkinnedFullbrightProgram); + mShaderList.push_back(&gDeferredSkinnedFullbrightAlphaMaskProgram); mShaderList.push_back(&gDeferredEmissiveProgram); + mShaderList.push_back(&gDeferredSkinnedEmissiveProgram); mShaderList.push_back(&gDeferredAvatarEyesProgram); mShaderList.push_back(&gDeferredWaterProgram); mShaderList.push_back(&gDeferredUnderWaterProgram); @@ -384,7 +410,7 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void) S32 LLViewerShaderMgr::getShaderLevel(S32 type) { - return LLPipeline::sDisableShaders ? 0 : mShaderLevel[type]; + return mShaderLevel[type]; } //============================================================================ @@ -400,15 +426,6 @@ void LLViewerShaderMgr::setShaders() return; } - if (!gGLManager.mHasShaderObjects - || !gGLManager.mHasVertexShader - || !gGLManager.mHasFragmentShader) - { - // Viewer will show 'hardware requirements' warning later - LL_INFOS("ShaderLoading") << "Shaders not supported" << LL_ENDL; - return; - } - static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); LLGLSLShader::sIndexedTextureChannels = llmax(llmin(gGLManager.mNumTextureImageUnits, (S32) max_texture_index), 1); @@ -433,7 +450,7 @@ void LLViewerShaderMgr::setShaders() initAttribsAndUniforms(); gPipeline.releaseGLBuffers(); - LLPipeline::sWaterReflections = gGLManager.mHasCubeMap; + LLPipeline::sWaterReflections = gGLManager.mHasCubeMap && LLPipeline::sRenderTransparentWater; LLPipeline::sRenderGlow = gSavedSettings.getBOOL("RenderGlow"); LLPipeline::updateRenderDeferred(); @@ -458,7 +475,6 @@ void LLViewerShaderMgr::setShaders() } mMaxAvatarShaderLevel = 0; - LLGLSLShader::sNoFixedFunction = false; LLVertexBuffer::unbind(); llassert((gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 10)); @@ -467,10 +483,7 @@ void LLViewerShaderMgr::setShaders() bool hasWindLightShaders = LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders"); S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); bool doingWindLight = hasWindLightShaders && gSavedSettings.getBOOL("WindLightUseAtmosShaders"); - bool useRenderDeferred = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred") && gSavedSettings.getBOOL("RenderAvatarVP"); - - //using shaders, disable fixed function - LLGLSLShader::sNoFixedFunction = true; + bool useRenderDeferred = doingWindLight && canRenderDeferred && gSavedSettings.getBOOL("RenderDeferred"); S32 light_class = 3; S32 interface_class = 2; @@ -543,192 +556,168 @@ void LLViewerShaderMgr::setShaders() } else { - LL_WARNS() << "Failed to load basic shaders." << LL_ENDL; + LL_ERRS() << "Unable to load basic shaders, verify graphics driver installed and current." << LL_ENDL; llassert(loaded); + reentrance = false; // For hygiene only, re-try probably helps nothing + return; } + gPipeline.mShadersLoaded = true; + + // Load all shaders to set max levels + loaded = loadShadersEnvironment(); + if (loaded) { - gPipeline.mVertexShadersEnabled = TRUE; - gPipeline.mVertexShadersLoaded = 1; - - // Load all shaders to set max levels - loaded = loadShadersEnvironment(); + LL_INFOS() << "Loaded environment shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load environment shaders." << LL_ENDL; + llassert(loaded); + } + if (loaded) + { + loaded = loadShadersWater(); if (loaded) { - LL_INFOS() << "Loaded environment shaders." << LL_ENDL; + LL_INFOS() << "Loaded water shaders." << LL_ENDL; } else { - LL_WARNS() << "Failed to load environment shaders." << LL_ENDL; + LL_WARNS() << "Failed to load water shaders." << LL_ENDL; llassert(loaded); } + } + if (loaded) + { + loaded = loadShadersWindLight(); if (loaded) { - loaded = loadShadersWater(); - if (loaded) - { - LL_INFOS() << "Loaded water shaders." << LL_ENDL; - } - else - { - LL_WARNS() << "Failed to load water shaders." << LL_ENDL; - llassert(loaded); - } + LL_INFOS() << "Loaded windlight shaders." << LL_ENDL; } - - if (loaded) + else { - loaded = loadShadersWindLight(); - if (loaded) - { - LL_INFOS() << "Loaded windlight shaders." << LL_ENDL; - } - else - { - LL_WARNS() << "Failed to load windlight shaders." << LL_ENDL; - llassert(loaded); - } + LL_WARNS() << "Failed to load windlight shaders." << LL_ENDL; + llassert(loaded); } + } + if (loaded) + { + loaded = loadShadersEffects(); if (loaded) { - loaded = loadShadersEffects(); - if (loaded) - { - LL_INFOS() << "Loaded effects shaders." << LL_ENDL; - } - else - { - LL_WARNS() << "Failed to load effects shaders." << LL_ENDL; - llassert(loaded); - } + LL_INFOS() << "Loaded effects shaders." << LL_ENDL; } - - if (loaded) + else { - loaded = loadShadersInterface(); - if (loaded) - { - LL_INFOS() << "Loaded interface shaders." << LL_ENDL; - } - else - { - LL_WARNS() << "Failed to load interface shaders." << LL_ENDL; - llassert(loaded); - } + LL_WARNS() << "Failed to load effects shaders." << LL_ENDL; + llassert(loaded); } + } + if (loaded) + { + loaded = loadShadersInterface(); if (loaded) - { - loaded = loadTransformShaders(); - if (loaded) - { - LL_INFOS() << "Loaded transform shaders." << LL_ENDL; - } - else - { - LL_WARNS() << "Failed to load transform shaders." << LL_ENDL; - llassert(loaded); - } + LL_INFOS() << "Loaded interface shaders." << LL_ENDL; } + else + { + LL_WARNS() << "Failed to load interface shaders." << LL_ENDL; + llassert(loaded); + } + } + + if (loaded) + { + loaded = loadTransformShaders(); if (loaded) { - // Load max avatar shaders to set the max level - mShaderLevel[SHADER_AVATAR] = 3; - mMaxAvatarShaderLevel = 3; + LL_INFOS() << "Loaded transform shaders." << LL_ENDL; + } + else + { + LL_WARNS() << "Failed to load transform shaders." << LL_ENDL; + llassert(loaded); + } + } + + if (loaded) + { + // Load max avatar shaders to set the max level + mShaderLevel[SHADER_AVATAR] = 3; + mMaxAvatarShaderLevel = 3; - if (gSavedSettings.getBOOL("RenderAvatarVP") && loadShadersObject()) - { //hardware skinning is enabled and rigged attachment shaders loaded correctly - BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); + if (loadShadersObject()) + { //hardware skinning is enabled and rigged attachment shaders loaded correctly + BOOL avatar_cloth = gSavedSettings.getBOOL("RenderAvatarCloth"); - // cloth is a class3 shader - S32 avatar_class = avatar_cloth ? 3 : 1; + // cloth is a class3 shader + S32 avatar_class = avatar_cloth ? 3 : 1; - // Set the actual level - mShaderLevel[SHADER_AVATAR] = avatar_class; + // Set the actual level + mShaderLevel[SHADER_AVATAR] = avatar_class; - loaded = loadShadersAvatar(); - llassert(loaded); + loaded = loadShadersAvatar(); + llassert(loaded); - if (mShaderLevel[SHADER_AVATAR] != avatar_class) + if (mShaderLevel[SHADER_AVATAR] != avatar_class) + { + if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3) { - if (mShaderLevel[SHADER_AVATAR] == 0) - { - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); - } - if(llmax(mShaderLevel[SHADER_AVATAR]-1,0) >= 3) - { - avatar_cloth = true; - } - else - { - avatar_cloth = false; - } - gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); + avatar_cloth = true; } - } - else - { //hardware skinning not possible, neither is deferred rendering - mShaderLevel[SHADER_AVATAR] = 0; - mShaderLevel[SHADER_DEFERRED] = 0; - - if (gSavedSettings.getBOOL("RenderAvatarVP")) + else { - gSavedSettings.setBOOL("RenderDeferred", FALSE); - gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); - gSavedSettings.setBOOL("RenderAvatarVP", FALSE); + avatar_cloth = false; } - - loadShadersAvatar(); // unloads - - loaded = loadShadersObject(); - llassert(loaded); + gSavedSettings.setBOOL("RenderAvatarCloth", avatar_cloth); } } + else + { //hardware skinning not possible, neither is deferred rendering + mShaderLevel[SHADER_AVATAR] = 0; + mShaderLevel[SHADER_DEFERRED] = 0; - if (!loaded) - { //some shader absolutely could not load, try to fall back to a simpler setting - if (gSavedSettings.getBOOL("WindLightUseAtmosShaders")) - { //disable windlight and try again - gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE); - LL_WARNS() << "Falling back to no windlight shaders." << LL_ENDL; - reentrance = false; - setShaders(); - return; - } - } + gSavedSettings.setBOOL("RenderDeferred", FALSE); + gSavedSettings.setBOOL("RenderAvatarCloth", FALSE); - llassert(loaded); + loadShadersAvatar(); // unloads + + loaded = loadShadersObject(); + llassert(loaded); + } + } - if (loaded && !loadShadersDeferred()) - { //everything else succeeded but deferred failed, disable deferred and try again - gSavedSettings.setBOOL("RenderDeferred", FALSE); - LL_WARNS() << "Falling back to no deferred shaders." << LL_ENDL; + if (!loaded) + { //some shader absolutely could not load, try to fall back to a simpler setting + if (gSavedSettings.getBOOL("WindLightUseAtmosShaders")) + { //disable windlight and try again + gSavedSettings.setBOOL("WindLightUseAtmosShaders", FALSE); + LL_WARNS() << "Falling back to no windlight shaders." << LL_ENDL; reentrance = false; setShaders(); return; } + } + + llassert(loaded); + + if (loaded && !loadShadersDeferred()) + { //everything else succeeded but deferred failed, disable deferred and try again + gSavedSettings.setBOOL("RenderDeferred", FALSE); + LL_WARNS() << "Falling back to no deferred shaders." << LL_ENDL; + reentrance = false; + setShaders(); + return; } - else - { - LLGLSLShader::sNoFixedFunction = false; - gPipeline.mVertexShadersEnabled = FALSE; - gPipeline.mVertexShadersLoaded = 0; - mShaderLevel[SHADER_LIGHTING] = 0; - mShaderLevel[SHADER_INTERFACE] = 0; - mShaderLevel[SHADER_ENVIRONMENT] = 0; - mShaderLevel[SHADER_WATER] = 0; - mShaderLevel[SHADER_OBJECT] = 0; - mShaderLevel[SHADER_EFFECT] = 0; - mShaderLevel[SHADER_WINDLIGHT] = 0; - mShaderLevel[SHADER_AVATAR] = 0; - } - + if (gViewerWindow) { gViewerWindow->setCursor(UI_CURSOR_ARROW); @@ -741,8 +730,10 @@ void LLViewerShaderMgr::setShaders() void LLViewerShaderMgr::unloadShaders() { gOcclusionProgram.unload(); + gSkinnedOcclusionProgram.unload(); gOcclusionCubeProgram.unload(); gDebugProgram.unload(); + gSkinnedDebugProgram.unload(); gClipProgram.unload(); gDownsampleDepthProgram.unload(); gDownsampleDepthRectProgram.unload(); @@ -764,58 +755,51 @@ void LLViewerShaderMgr::unloadShaders() gObjectFullbrightNoColorProgram.unload(); gObjectFullbrightNoColorWaterProgram.unload(); gObjectSimpleProgram.unload(); + gSkinnedObjectSimpleProgram.unload(); gObjectSimpleImpostorProgram.unload(); + gSkinnedObjectSimpleImpostorProgram.unload(); gObjectPreviewProgram.unload(); + gPhysicsPreviewProgram.unload(); gImpostorProgram.unload(); gObjectSimpleAlphaMaskProgram.unload(); + gSkinnedObjectSimpleAlphaMaskProgram.unload(); gObjectBumpProgram.unload(); + gSkinnedObjectBumpProgram.unload(); gObjectSimpleWaterProgram.unload(); + gSkinnedObjectSimpleWaterProgram.unload(); gObjectSimpleWaterAlphaMaskProgram.unload(); + gSkinnedObjectSimpleWaterAlphaMaskProgram.unload(); gObjectFullbrightProgram.unload(); + gSkinnedObjectFullbrightProgram.unload(); gObjectFullbrightWaterProgram.unload(); + gSkinnedObjectFullbrightWaterProgram.unload(); gObjectEmissiveProgram.unload(); + gSkinnedObjectEmissiveProgram.unload(); gObjectEmissiveWaterProgram.unload(); + gSkinnedObjectEmissiveWaterProgram.unload(); gObjectFullbrightAlphaMaskProgram.unload(); + gSkinnedObjectFullbrightAlphaMaskProgram.unload(); gObjectFullbrightWaterAlphaMaskProgram.unload(); + gSkinnedObjectFullbrightWaterAlphaMaskProgram.unload(); gObjectShinyProgram.unload(); + gSkinnedObjectShinyProgram.unload(); gObjectFullbrightShinyProgram.unload(); + gSkinnedObjectFullbrightShinyProgram.unload(); gObjectFullbrightShinyWaterProgram.unload(); + gSkinnedObjectFullbrightShinyWaterProgram.unload(); gObjectShinyWaterProgram.unload(); + gSkinnedObjectShinyWaterProgram.unload(); - gObjectSimpleNonIndexedProgram.unload(); gObjectSimpleNonIndexedTexGenProgram.unload(); gObjectSimpleNonIndexedTexGenWaterProgram.unload(); - gObjectSimpleNonIndexedWaterProgram.unload(); gObjectAlphaMaskNonIndexedProgram.unload(); gObjectAlphaMaskNonIndexedWaterProgram.unload(); gObjectAlphaMaskNoColorProgram.unload(); gObjectAlphaMaskNoColorWaterProgram.unload(); - gObjectFullbrightNonIndexedProgram.unload(); - gObjectFullbrightNonIndexedWaterProgram.unload(); - gObjectEmissiveNonIndexedProgram.unload(); - gObjectEmissiveNonIndexedWaterProgram.unload(); gTreeProgram.unload(); gTreeWaterProgram.unload(); - gObjectShinyNonIndexedProgram.unload(); - gObjectFullbrightShinyNonIndexedProgram.unload(); - gObjectFullbrightShinyNonIndexedWaterProgram.unload(); - gObjectShinyNonIndexedWaterProgram.unload(); - - gSkinnedObjectSimpleProgram.unload(); - gSkinnedObjectFullbrightProgram.unload(); - gSkinnedObjectEmissiveProgram.unload(); - gSkinnedObjectFullbrightShinyProgram.unload(); - gSkinnedObjectShinySimpleProgram.unload(); - - gSkinnedObjectSimpleWaterProgram.unload(); - gSkinnedObjectFullbrightWaterProgram.unload(); - gSkinnedObjectEmissiveWaterProgram.unload(); - gSkinnedObjectFullbrightShinyWaterProgram.unload(); - gSkinnedObjectShinySimpleWaterProgram.unload(); - - gWaterProgram.unload(); gWaterEdgeProgram.unload(); gUnderWaterProgram.unload(); @@ -828,6 +812,7 @@ void LLViewerShaderMgr::unloadShaders() gAvatarEyeballProgram.unload(); gAvatarPickProgram.unload(); gHighlightProgram.unload(); + gSkinnedHighlightProgram.unload(); gHighlightNormalProgram.unload(); gHighlightSpecularProgram.unload(); @@ -841,13 +826,13 @@ void LLViewerShaderMgr::unloadShaders() gDeferredDiffuseProgram.unload(); gDeferredDiffuseAlphaMaskProgram.unload(); + gDeferredSkinnedDiffuseAlphaMaskProgram.unload(); gDeferredNonIndexedDiffuseAlphaMaskProgram.unload(); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.unload(); gDeferredNonIndexedDiffuseProgram.unload(); gDeferredSkinnedDiffuseProgram.unload(); gDeferredSkinnedBumpProgram.unload(); - gDeferredSkinnedAlphaProgram.unload(); - + gTransformPositionProgram.unload(); gTransformTexCoordProgram.unload(); gTransformNormalProgram.unload(); @@ -864,7 +849,7 @@ void LLViewerShaderMgr::unloadShaders() mShaderLevel[SHADER_WINDLIGHT] = 0; mShaderLevel[SHADER_TRANSFORM] = 0; - gPipeline.mVertexShadersLoaded = 0; + gPipeline.mShadersLoaded = false; } BOOL LLViewerShaderMgr::loadBasicShaders() @@ -924,7 +909,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders() } shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl", 1 ) ); - boost::unordered_map<std::string, std::string> attribs; + std::unordered_map<std::string, std::string> attribs; attribs["MAX_JOINTS_PER_MESH_OBJECT"] = boost::lexical_cast<std::string>(LLSkinningUtil::getMaxJointCount()); @@ -1236,14 +1221,15 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredTreeProgram.unload(); gDeferredTreeShadowProgram.unload(); + gDeferredSkinnedTreeShadowProgram.unload(); gDeferredDiffuseProgram.unload(); gDeferredDiffuseAlphaMaskProgram.unload(); + gDeferredSkinnedDiffuseAlphaMaskProgram.unload(); gDeferredNonIndexedDiffuseAlphaMaskProgram.unload(); gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram.unload(); gDeferredNonIndexedDiffuseProgram.unload(); gDeferredSkinnedDiffuseProgram.unload(); gDeferredSkinnedBumpProgram.unload(); - gDeferredSkinnedAlphaProgram.unload(); gDeferredBumpProgram.unload(); gDeferredImpostorProgram.unload(); gDeferredTerrainProgram.unload(); @@ -1260,9 +1246,12 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredSoftenProgram.unload(); gDeferredSoftenWaterProgram.unload(); gDeferredShadowProgram.unload(); + gDeferredSkinnedShadowProgram.unload(); gDeferredShadowCubeProgram.unload(); gDeferredShadowAlphaMaskProgram.unload(); + gDeferredSkinnedShadowAlphaMaskProgram.unload(); gDeferredShadowFullbrightAlphaMaskProgram.unload(); + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.unload(); gDeferredAvatarShadowProgram.unload(); gDeferredAvatarAlphaShadowProgram.unload(); gDeferredAvatarAlphaMaskShadowProgram.unload(); @@ -1272,12 +1261,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredAvatarProgram.unload(); gDeferredAvatarAlphaProgram.unload(); gDeferredAlphaProgram.unload(); + gDeferredSkinnedAlphaProgram.unload(); gDeferredAlphaWaterProgram.unload(); + gDeferredSkinnedAlphaWaterProgram.unload(); gDeferredFullbrightProgram.unload(); gDeferredFullbrightAlphaMaskProgram.unload(); gDeferredFullbrightWaterProgram.unload(); + gDeferredSkinnedFullbrightWaterProgram.unload(); gDeferredFullbrightAlphaMaskWaterProgram.unload(); + gDeferredSkinnedFullbrightAlphaMaskWaterProgram.unload(); gDeferredEmissiveProgram.unload(); + gDeferredSkinnedEmissiveProgram.unload(); gDeferredAvatarEyesProgram.unload(); gDeferredPostProgram.unload(); gDeferredCoFProgram.unload(); @@ -1292,8 +1286,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredWLMoonProgram.unload(); gDeferredStarProgram.unload(); gDeferredFullbrightShinyProgram.unload(); - gDeferredSkinnedFullbrightShinyProgram.unload(); + gDeferredSkinnedFullbrightShinyProgram.unload(); gDeferredSkinnedFullbrightProgram.unload(); + gDeferredSkinnedFullbrightAlphaMaskProgram.unload(); gDeferredHighlightProgram.unload(); gDeferredHighlightNormalProgram.unload(); @@ -1350,7 +1345,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseIndexedF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredDiffuseProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredDiffuseProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDeferredDiffuseProgram, gDeferredSkinnedDiffuseProgram); + success = success && gDeferredDiffuseProgram.createShader(NULL, NULL); } if (success) @@ -1362,7 +1358,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredDiffuseAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/diffuseAlphaMaskIndexedF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredDiffuseAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredDiffuseAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredDiffuseAlphaMaskProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDeferredDiffuseAlphaMaskProgram, gDeferredSkinnedDiffuseAlphaMaskProgram); + success = success && gDeferredDiffuseAlphaMaskProgram.createShader(NULL, NULL); } if (success) @@ -1404,94 +1401,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { - gDeferredSkinnedDiffuseProgram.mName = "Deferred Skinned Diffuse Shader"; - gDeferredSkinnedDiffuseProgram.mFeatures.hasObjectSkinning = true; - gDeferredSkinnedDiffuseProgram.mFeatures.encodesNormal = true; - gDeferredSkinnedDiffuseProgram.mFeatures.hasSrgb = true; - gDeferredSkinnedDiffuseProgram.mShaderFiles.clear(); - gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSkinnedDiffuseProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredSkinnedDiffuseProgram.createShader(NULL, NULL); - llassert(success); - } - - if (success) - { - gDeferredSkinnedBumpProgram.mName = "Deferred Skinned Bump Shader"; - gDeferredSkinnedBumpProgram.mFeatures.hasObjectSkinning = true; - gDeferredSkinnedBumpProgram.mFeatures.encodesNormal = true; - gDeferredSkinnedBumpProgram.mShaderFiles.clear(); - gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSkinnedBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredSkinnedBumpProgram.createShader(NULL, NULL); - llassert(success); - } - - if (success) - { - gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader"; - gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true; - gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = false; - gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = false; - gDeferredSkinnedAlphaProgram.mFeatures.isAlphaLighting = true; - gDeferredSkinnedAlphaProgram.mFeatures.disableTextureIndex = true; - gDeferredSkinnedAlphaProgram.mFeatures.hasSrgb = true; - gDeferredSkinnedAlphaProgram.mFeatures.encodesNormal = true; - gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true; - gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true; - gDeferredSkinnedAlphaProgram.mFeatures.hasTransport = true; - gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true; - gDeferredSkinnedAlphaProgram.mFeatures.hasShadows = true; - - gDeferredSkinnedAlphaProgram.mShaderFiles.clear(); - gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSkinnedAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - - gDeferredSkinnedAlphaProgram.clearPermutations(); - gDeferredSkinnedAlphaProgram.addPermutation("USE_DIFFUSE_TEX", "1"); - gDeferredSkinnedAlphaProgram.addPermutation("HAS_SKIN", "1"); - gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1"); - - if (use_sun_shadow) - { - gDeferredSkinnedAlphaProgram.addPermutation("HAS_SHADOW", "1"); - } - - if (ambient_kill) - { - gDeferredSkinnedAlphaProgram.addPermutation("AMBIENT_KILL", "1"); - } - - if (sunlight_kill) - { - gDeferredSkinnedAlphaProgram.addPermutation("SUNLIGHT_KILL", "1"); - } - - if (local_light_kill) - { - gDeferredSkinnedAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); - } - - success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL); - llassert(success); - - // Hack to include uniforms for lighting without linking in lighting file - gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = true; - gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = true; - } - - if (success) - { gDeferredBumpProgram.mName = "Deferred Bump Shader"; gDeferredBumpProgram.mFeatures.encodesNormal = true; gDeferredBumpProgram.mShaderFiles.clear(); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredBumpProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredBumpProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDeferredBumpProgram, gDeferredSkinnedBumpProgram); + success = success && gDeferredBumpProgram.createShader(NULL, NULL); llassert(success); } @@ -1579,6 +1496,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredMaterialProgram[i].addPermutation("HAS_SKIN", "1"); gDeferredMaterialProgram[i].mFeatures.hasObjectSkinning = true; } + else + { + gDeferredMaterialProgram[i].mRiggedVariant = &gDeferredMaterialProgram[i + 0x10]; + } success = gDeferredMaterialProgram[i].createShader(NULL, NULL); llassert(success); @@ -1624,6 +1545,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN", "1"); } + else + { + gDeferredMaterialWaterProgram[i].mRiggedVariant = &(gDeferredMaterialWaterProgram[i + 0x10]); + } gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1"); if (ambient_kill) @@ -1700,10 +1625,25 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredTreeShadowProgram.mRiggedVariant = &gDeferredSkinnedTreeShadowProgram; success = gDeferredTreeShadowProgram.createShader(NULL, NULL); llassert(success); } + if (success) + { + gDeferredSkinnedTreeShadowProgram.mName = "Deferred Skinned Tree Shadow Shader"; + gDeferredSkinnedTreeShadowProgram.mShaderFiles.clear(); + gDeferredSkinnedTreeShadowProgram.mFeatures.isDeferred = true; + gDeferredSkinnedTreeShadowProgram.mFeatures.hasShadows = true; + gDeferredSkinnedTreeShadowProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedTreeShadowProgram.mShaderFiles.push_back(make_pair("deferred/treeShadowF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSkinnedTreeShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gDeferredSkinnedTreeShadowProgram.createShader(NULL, NULL); + llassert(success); + } + if (success) { gDeferredImpostorProgram.mName = "Deferred Impostor Shader"; @@ -1892,172 +1832,238 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { - gDeferredAlphaProgram.mName = "Deferred Alpha Shader"; - - gDeferredAlphaProgram.mFeatures.calculatesLighting = false; - gDeferredAlphaProgram.mFeatures.hasLighting = false; - gDeferredAlphaProgram.mFeatures.isAlphaLighting = true; - gDeferredAlphaProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels - gDeferredAlphaProgram.mFeatures.hasSrgb = true; - gDeferredAlphaProgram.mFeatures.encodesNormal = true; - gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true; - gDeferredAlphaProgram.mFeatures.hasAtmospherics = true; - gDeferredAlphaProgram.mFeatures.hasGamma = true; - gDeferredAlphaProgram.mFeatures.hasTransport = true; - gDeferredAlphaProgram.mFeatures.hasShadows = use_sun_shadow; - - if (mShaderLevel[SHADER_DEFERRED] < 1) + for (int i = 0; i < 2 && success; ++i) { - gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - } - else - { //shave off some texture units for shadow maps - gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); - } - - gDeferredAlphaProgram.mShaderFiles.clear(); - gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); - - gDeferredAlphaProgram.clearPermutations(); - gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1"); - gDeferredAlphaProgram.addPermutation("USE_INDEXED_TEX", "1"); - if (use_sun_shadow) - { - gDeferredAlphaProgram.addPermutation("HAS_SHADOW", "1"); - } + LLGLSLShader* shader = nullptr; + bool rigged = i == 1; + if (!rigged) + { + shader = &gDeferredAlphaProgram; + shader->mName = "Deferred Alpha Shader"; + shader->mRiggedVariant = &gDeferredSkinnedAlphaProgram; + } + else + { + shader = &gDeferredSkinnedAlphaProgram; + shader->mName = "Skinned Deferred Alpha Shader"; + shader->mFeatures.hasObjectSkinning = true; + } - if (ambient_kill) - { - gDeferredAlphaProgram.addPermutation("AMBIENT_KILL", "1"); - } + shader->mFeatures.calculatesLighting = false; + shader->mFeatures.hasLighting = false; + shader->mFeatures.isAlphaLighting = true; + shader->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels + shader->mFeatures.hasSrgb = true; + shader->mFeatures.encodesNormal = true; + shader->mFeatures.calculatesAtmospherics = true; + shader->mFeatures.hasAtmospherics = true; + shader->mFeatures.hasGamma = true; + shader->mFeatures.hasTransport = true; + shader->mFeatures.hasShadows = use_sun_shadow; + + if (mShaderLevel[SHADER_DEFERRED] < 1) + { + shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + } + else + { //shave off some texture units for shadow maps + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); + } - if (sunlight_kill) - { - gDeferredAlphaProgram.addPermutation("SUNLIGHT_KILL", "1"); - } + shader->mShaderFiles.clear(); + shader->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); + shader->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); - if (local_light_kill) - { - gDeferredAlphaProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); - } + shader->clearPermutations(); + shader->addPermutation("USE_VERTEX_COLOR", "1"); + shader->addPermutation("HAS_ALPHA_MASK", "1"); + shader->addPermutation("USE_INDEXED_TEX", "1"); + if (use_sun_shadow) + { + shader->addPermutation("HAS_SHADOW", "1"); + } - gDeferredAlphaProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + if (ambient_kill) + { + shader->addPermutation("AMBIENT_KILL", "1"); + } - success = gDeferredAlphaProgram.createShader(NULL, NULL); - llassert(success); + if (sunlight_kill) + { + shader->addPermutation("SUNLIGHT_KILL", "1"); + } - // Hack - gDeferredAlphaProgram.mFeatures.calculatesLighting = true; - gDeferredAlphaProgram.mFeatures.hasLighting = true; + if (local_light_kill) + { + shader->addPermutation("LOCAL_LIGHT_KILL", "1"); + } + + if (rigged) + { + shader->addPermutation("HAS_SKIN", "1"); + } + + shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + success = shader->createShader(NULL, NULL); + llassert(success); + + // Hack + shader->mFeatures.calculatesLighting = true; + shader->mFeatures.hasLighting = true; + } } if (success) { - gDeferredAlphaImpostorProgram.mName = "Deferred Alpha Impostor Shader"; + LLGLSLShader* shaders[] = { + &gDeferredAlphaImpostorProgram, + &gDeferredSkinnedAlphaImpostorProgram + }; -// Begin Hack - gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = false; - gDeferredAlphaImpostorProgram.mFeatures.hasLighting = false; + for (int i = 0; i < 2 && success; ++i) + { + bool rigged = i == 1; + LLGLSLShader* shader = shaders[i]; - gDeferredAlphaImpostorProgram.mFeatures.hasSrgb = true; - gDeferredAlphaImpostorProgram.mFeatures.isAlphaLighting = true; - gDeferredAlphaImpostorProgram.mFeatures.encodesNormal = true; - gDeferredAlphaImpostorProgram.mFeatures.hasShadows = use_sun_shadow; + shader->mName = rigged ? "Skinned Deferred Alpha Impostor Shader" : "Deferred Alpha Impostor Shader"; - if (mShaderLevel[SHADER_DEFERRED] < 1) - { - gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - } - else - { //shave off some texture units for shadow maps - gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); - } + // Begin Hack + shader->mFeatures.calculatesLighting = false; + shader->mFeatures.hasLighting = false; - gDeferredAlphaImpostorProgram.mShaderFiles.clear(); - gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); + shader->mFeatures.hasSrgb = true; + shader->mFeatures.isAlphaLighting = true; + shader->mFeatures.encodesNormal = true; + shader->mFeatures.hasShadows = use_sun_shadow; - gDeferredAlphaImpostorProgram.clearPermutations(); - gDeferredAlphaImpostorProgram.addPermutation("USE_INDEXED_TEX", "1"); - gDeferredAlphaImpostorProgram.addPermutation("FOR_IMPOSTOR", "1"); - gDeferredAlphaImpostorProgram.addPermutation("USE_VERTEX_COLOR", "1"); + if (mShaderLevel[SHADER_DEFERRED] < 1) + { + shader->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + } + else + { //shave off some texture units for shadow maps + shader->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); + } - if (use_sun_shadow) - { - gDeferredAlphaImpostorProgram.addPermutation("HAS_SHADOW", "1"); - } + shader->mShaderFiles.clear(); + shader->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); + shader->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredAlphaImpostorProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + shader->clearPermutations(); + shader->addPermutation("USE_INDEXED_TEX", "1"); + shader->addPermutation("FOR_IMPOSTOR", "1"); + shader->addPermutation("HAS_ALPHA_MASK", "1"); + shader->addPermutation("USE_VERTEX_COLOR", "1"); + if (rigged) + { + shader->mFeatures.hasObjectSkinning = true; + shader->addPermutation("HAS_SKIN", "1"); + } - success = gDeferredAlphaImpostorProgram.createShader(NULL, NULL); - llassert(success); + if (use_sun_shadow) + { + shader->addPermutation("HAS_SHADOW", "1"); + } + + shader->mRiggedVariant = &gDeferredSkinnedAlphaImpostorProgram; + shader->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + if (!rigged) + { + shader->mRiggedVariant = shaders[1]; + } + success = shader->createShader(NULL, NULL); + llassert(success); -// End Hack - gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = true; - gDeferredAlphaImpostorProgram.mFeatures.hasLighting = true; + // End Hack + shader->mFeatures.calculatesLighting = true; + shader->mFeatures.hasLighting = true; + } } - if (success) - { - gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader"; - gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = false; - gDeferredAlphaWaterProgram.mFeatures.hasLighting = false; - gDeferredAlphaWaterProgram.mFeatures.isAlphaLighting = true; - gDeferredAlphaWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels - gDeferredAlphaWaterProgram.mFeatures.hasWaterFog = true; - gDeferredAlphaWaterProgram.mFeatures.hasSrgb = true; - gDeferredAlphaWaterProgram.mFeatures.encodesNormal = true; - gDeferredAlphaWaterProgram.mFeatures.calculatesAtmospherics = true; - gDeferredAlphaWaterProgram.mFeatures.hasAtmospherics = true; - gDeferredAlphaWaterProgram.mFeatures.hasGamma = true; - gDeferredAlphaWaterProgram.mFeatures.hasTransport = true; - gDeferredAlphaWaterProgram.mFeatures.hasShadows = use_sun_shadow; - - if (mShaderLevel[SHADER_DEFERRED] < 1) - { - gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; - } - else - { //shave off some texture units for shadow maps - gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); - } - gDeferredAlphaWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gDeferredAlphaWaterProgram.mShaderFiles.clear(); - gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); - - gDeferredAlphaWaterProgram.clearPermutations(); - gDeferredAlphaWaterProgram.addPermutation("USE_INDEXED_TEX", "1"); - gDeferredAlphaWaterProgram.addPermutation("WATER_FOG", "1"); - gDeferredAlphaWaterProgram.addPermutation("USE_VERTEX_COLOR", "1"); - if (use_sun_shadow) - { - gDeferredAlphaWaterProgram.addPermutation("HAS_SHADOW", "1"); - } + if (success) + { + LLGLSLShader* shader[] = { + &gDeferredAlphaWaterProgram, + &gDeferredSkinnedAlphaWaterProgram + }; + + gDeferredAlphaWaterProgram.mRiggedVariant = &gDeferredSkinnedAlphaWaterProgram; + + gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader"; + gDeferredSkinnedAlphaWaterProgram.mName = "Deferred Skinned Alpha Underwater Shader"; - if (ambient_kill) + for (int i = 0; i < 2 && success; ++i) { - gDeferredAlphaWaterProgram.addPermutation("AMBIENT_KILL", "1"); - } + shader[i]->mFeatures.calculatesLighting = false; + shader[i]->mFeatures.hasLighting = false; + shader[i]->mFeatures.isAlphaLighting = true; + shader[i]->mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels + shader[i]->mFeatures.hasWaterFog = true; + shader[i]->mFeatures.hasSrgb = true; + shader[i]->mFeatures.encodesNormal = true; + shader[i]->mFeatures.calculatesAtmospherics = true; + shader[i]->mFeatures.hasAtmospherics = true; + shader[i]->mFeatures.hasGamma = true; + shader[i]->mFeatures.hasTransport = true; + shader[i]->mFeatures.hasShadows = use_sun_shadow; + + if (mShaderLevel[SHADER_DEFERRED] < 1) + { + shader[i]->mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + } + else + { //shave off some texture units for shadow maps + shader[i]->mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1); + } + shader[i]->mShaderGroup = LLGLSLShader::SG_WATER; + shader[i]->mShaderFiles.clear(); + shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB)); + shader[i]->mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB)); + + shader[i]->clearPermutations(); + shader[i]->addPermutation("USE_INDEXED_TEX", "1"); + shader[i]->addPermutation("WATER_FOG", "1"); + shader[i]->addPermutation("USE_VERTEX_COLOR", "1"); + shader[i]->addPermutation("HAS_ALPHA_MASK", "1"); + if (use_sun_shadow) + { + shader[i]->addPermutation("HAS_SHADOW", "1"); + } - if (sunlight_kill) - { - gDeferredAlphaWaterProgram.addPermutation("SUNLIGHT_KILL", "1"); - } + if (ambient_kill) + { + shader[i]->addPermutation("AMBIENT_KILL", "1"); + } - if (local_light_kill) - { - gDeferredAlphaWaterProgram.addPermutation("LOCAL_LIGHT_KILL", "1"); - } - gDeferredAlphaWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + if (sunlight_kill) + { + shader[i]->addPermutation("SUNLIGHT_KILL", "1"); + } - success = gDeferredAlphaWaterProgram.createShader(NULL, NULL); - llassert(success); + if (local_light_kill) + { + shader[i]->addPermutation("LOCAL_LIGHT_KILL", "1"); + } - // Hack - gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = true; - gDeferredAlphaWaterProgram.mFeatures.hasLighting = true; + if (i == 1) + { // rigged variant + shader[i]->mFeatures.hasObjectSkinning = true; + shader[i]->addPermutation("HAS_SKIN", "1"); + } + else + { + shader[i]->mRiggedVariant = shader[1]; + } + shader[i]->mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + + success = shader[i]->createShader(NULL, NULL); + llassert(success); + + // Hack + shader[i]->mFeatures.calculatesLighting = true; + shader[i]->mFeatures.hasLighting = true; + } } if (success) @@ -2091,6 +2097,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = make_rigged_variant(gDeferredFullbrightProgram, gDeferredSkinnedFullbrightProgram); success = gDeferredFullbrightProgram.createShader(NULL, NULL); llassert(success); } @@ -2108,7 +2115,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredFullbrightAlphaMaskProgram.addPermutation("HAS_ALPHA_MASK","1"); gDeferredFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDeferredFullbrightAlphaMaskProgram, gDeferredSkinnedFullbrightAlphaMaskProgram); + success = success && gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL); llassert(success); } @@ -2127,10 +2135,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1"); - success = gDeferredFullbrightWaterProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDeferredFullbrightWaterProgram, gDeferredSkinnedFullbrightWaterProgram); + success = success && gDeferredFullbrightWaterProgram.createShader(NULL, NULL); llassert(success); } - + if (success) { gDeferredFullbrightAlphaMaskWaterProgram.mName = "Deferred Fullbright Underwater Alpha Masking Shader"; @@ -2147,7 +2156,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1"); gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1"); - success = gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDeferredFullbrightAlphaMaskWaterProgram, gDeferredSkinnedFullbrightAlphaMaskWaterProgram); + success = success && gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL); llassert(success); } @@ -2164,43 +2174,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredFullbrightShinyProgram.createShader(NULL, NULL); - llassert(success); - } - - if (success) - { - gDeferredSkinnedFullbrightProgram.mName = "Skinned Fullbright Shader"; - gDeferredSkinnedFullbrightProgram.mFeatures.calculatesAtmospherics = true; - gDeferredSkinnedFullbrightProgram.mFeatures.hasAtmospherics = true; - gDeferredSkinnedFullbrightProgram.mFeatures.hasGamma = true; - gDeferredSkinnedFullbrightProgram.mFeatures.hasTransport = true; - gDeferredSkinnedFullbrightProgram.mFeatures.hasObjectSkinning = true; - gDeferredSkinnedFullbrightProgram.mFeatures.disableTextureIndex = true; - gDeferredSkinnedFullbrightProgram.mFeatures.hasSrgb = true; - gDeferredSkinnedFullbrightProgram.mShaderFiles.clear(); - gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSkinnedFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gDeferredSkinnedFullbrightProgram.createShader(NULL, NULL); - llassert(success); - } - - if (success) - { - gDeferredSkinnedFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader"; - gDeferredSkinnedFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true; - gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasAtmospherics = true; - gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasGamma = true; - gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasTransport = true; - gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasObjectSkinning = true; - gDeferredSkinnedFullbrightShinyProgram.mFeatures.disableTextureIndex = true; - gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasSrgb = true; - gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.clear(); - gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gDeferredSkinnedFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gDeferredSkinnedFullbrightShinyProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDeferredFullbrightShinyProgram, gDeferredSkinnedFullbrightShinyProgram); + success = success && gDeferredFullbrightShinyProgram.createShader(NULL, NULL); llassert(success); } @@ -2215,7 +2190,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); gDeferredEmissiveProgram.mShaderFiles.push_back(make_pair("deferred/emissiveF.glsl", GL_FRAGMENT_SHADER_ARB)); gDeferredEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; - success = gDeferredEmissiveProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDeferredEmissiveProgram, gDeferredSkinnedEmissiveProgram); + success = success && gDeferredEmissiveProgram.createShader(NULL, NULL); llassert(success); } @@ -2358,10 +2334,29 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() { gDeferredShadowProgram.addPermutation("DEPTH_CLAMP", "1"); } + gDeferredShadowProgram.mRiggedVariant = &gDeferredSkinnedShadowProgram; success = gDeferredShadowProgram.createShader(NULL, NULL); llassert(success); } + if (success) + { + gDeferredSkinnedShadowProgram.mName = "Deferred Skinned Shadow Shader"; + gDeferredSkinnedShadowProgram.mFeatures.isDeferred = true; + gDeferredSkinnedShadowProgram.mFeatures.hasShadows = true; + gDeferredSkinnedShadowProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedShadowProgram.mShaderFiles.clear(); + gDeferredSkinnedShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDeferredSkinnedShadowProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + if (gGLManager.mHasDepthClamp) + { + gDeferredSkinnedShadowProgram.addPermutation("DEPTH_CLAMP", "1"); + } + success = gDeferredSkinnedShadowProgram.createShader(NULL, NULL); + llassert(success); + } + if (success) { gDeferredShadowCubeProgram.mName = "Deferred Shadow Cube Shader"; @@ -2395,11 +2390,32 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() } gDeferredShadowFullbrightAlphaMaskProgram.addPermutation("IS_FULLBRIGHT", "1"); gDeferredShadowFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredShadowFullbrightAlphaMaskProgram.mRiggedVariant = &gDeferredSkinnedShadowFullbrightAlphaMaskProgram; success = gDeferredShadowFullbrightAlphaMaskProgram.createShader(NULL, NULL); llassert(success); } if (success) + { + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mName = "Deferred Skinned Shadow Fullbright Alpha Mask Shader"; + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.clear(); + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB)); + + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.clearPermutations(); + if (gGLManager.mHasDepthClamp) + { + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1"); + } + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.addPermutation("IS_FULLBRIGHT", "1"); + gDeferredSkinnedShadowFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gDeferredSkinnedShadowFullbrightAlphaMaskProgram.createShader(NULL, NULL); + llassert(success); + } + + if (success) { gDeferredShadowAlphaMaskProgram.mName = "Deferred Shadow Alpha Mask Shader"; gDeferredShadowAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; @@ -2412,10 +2428,28 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1"); } gDeferredShadowAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + gDeferredShadowAlphaMaskProgram.mRiggedVariant = &gDeferredSkinnedShadowAlphaMaskProgram; success = gDeferredShadowAlphaMaskProgram.createShader(NULL, NULL); llassert(success); } + if (success) + { + gDeferredSkinnedShadowAlphaMaskProgram.mName = "Deferred Skinned Shadow Alpha Mask Shader"; + gDeferredSkinnedShadowAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; + gDeferredSkinnedShadowAlphaMaskProgram.mFeatures.hasObjectSkinning = true; + gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.clear(); + gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gDeferredSkinnedShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB)); + if (gGLManager.mHasDepthClamp) + { + gDeferredSkinnedShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", "1"); + } + gDeferredSkinnedShadowAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gDeferredSkinnedShadowAlphaMaskProgram.createShader(NULL, NULL); + llassert(success); + } + if (success) { gDeferredAvatarShadowProgram.mName = "Deferred Avatar Shadow Shader"; @@ -2791,79 +2825,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() BOOL LLViewerShaderMgr::loadShadersObject() { BOOL success = TRUE; - - if (mShaderLevel[SHADER_OBJECT] == 0) - { - gObjectShinyProgram.unload(); - gObjectFullbrightShinyProgram.unload(); - gObjectFullbrightShinyWaterProgram.unload(); - gObjectShinyWaterProgram.unload(); - gObjectFullbrightNoColorProgram.unload(); - gObjectFullbrightNoColorWaterProgram.unload(); - gObjectSimpleProgram.unload(); - gObjectSimpleImpostorProgram.unload(); - gObjectPreviewProgram.unload(); - gImpostorProgram.unload(); - gObjectSimpleAlphaMaskProgram.unload(); - gObjectBumpProgram.unload(); - gObjectSimpleWaterProgram.unload(); - gObjectSimpleWaterAlphaMaskProgram.unload(); - gObjectEmissiveProgram.unload(); - gObjectEmissiveWaterProgram.unload(); - gObjectFullbrightProgram.unload(); - gObjectFullbrightAlphaMaskProgram.unload(); - gObjectFullbrightWaterProgram.unload(); - gObjectFullbrightWaterAlphaMaskProgram.unload(); - gObjectShinyNonIndexedProgram.unload(); - gObjectFullbrightShinyNonIndexedProgram.unload(); - gObjectFullbrightShinyNonIndexedWaterProgram.unload(); - gObjectShinyNonIndexedWaterProgram.unload(); - gObjectSimpleNonIndexedTexGenProgram.unload(); - gObjectSimpleNonIndexedTexGenWaterProgram.unload(); - gObjectSimpleNonIndexedWaterProgram.unload(); - gObjectAlphaMaskNonIndexedProgram.unload(); - gObjectAlphaMaskNonIndexedWaterProgram.unload(); - gObjectAlphaMaskNoColorProgram.unload(); - gObjectAlphaMaskNoColorWaterProgram.unload(); - gObjectFullbrightNonIndexedProgram.unload(); - gObjectFullbrightNonIndexedWaterProgram.unload(); - gObjectEmissiveNonIndexedProgram.unload(); - gObjectEmissiveNonIndexedWaterProgram.unload(); - gSkinnedObjectSimpleProgram.unload(); - gSkinnedObjectFullbrightProgram.unload(); - gSkinnedObjectEmissiveProgram.unload(); - gSkinnedObjectFullbrightShinyProgram.unload(); - gSkinnedObjectShinySimpleProgram.unload(); - gSkinnedObjectSimpleWaterProgram.unload(); - gSkinnedObjectFullbrightWaterProgram.unload(); - gSkinnedObjectEmissiveWaterProgram.unload(); - gSkinnedObjectFullbrightShinyWaterProgram.unload(); - gSkinnedObjectShinySimpleWaterProgram.unload(); - gTreeProgram.unload(); - gTreeWaterProgram.unload(); - - return TRUE; - } if (success) { - gObjectSimpleNonIndexedProgram.mName = "Non indexed Shader"; - gObjectSimpleNonIndexedProgram.mFeatures.calculatesLighting = true; - gObjectSimpleNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectSimpleNonIndexedProgram.mFeatures.hasGamma = true; - gObjectSimpleNonIndexedProgram.mFeatures.hasAtmospherics = true; - gObjectSimpleNonIndexedProgram.mFeatures.hasLighting = true; - gObjectSimpleNonIndexedProgram.mFeatures.hasAlphaMask = true; // Fix for MAINT-8836 - gObjectSimpleNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectSimpleNonIndexedProgram.mShaderFiles.clear(); - gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectSimpleNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectSimpleNonIndexedProgram.createShader(NULL, NULL); - } - - if (success) - { gObjectSimpleNonIndexedTexGenProgram.mName = "Non indexed tex-gen Shader"; gObjectSimpleNonIndexedTexGenProgram.mFeatures.calculatesLighting = true; gObjectSimpleNonIndexedTexGenProgram.mFeatures.calculatesAtmospherics = true; @@ -2878,24 +2842,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() success = gObjectSimpleNonIndexedTexGenProgram.createShader(NULL, NULL); } - - if (success) - { - gObjectSimpleNonIndexedWaterProgram.mName = "Non indexed Water Shader"; - gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesLighting = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.hasAtmospherics = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.hasLighting = true; - gObjectSimpleNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectSimpleNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectSimpleNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectSimpleNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - gObjectSimpleNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectSimpleNonIndexedWaterProgram.createShader(NULL, NULL); - } - if (success) { gObjectSimpleNonIndexedTexGenWaterProgram.mName = "Non indexed tex-gen Water Shader"; @@ -3020,70 +2966,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() if (success) { - gObjectFullbrightNonIndexedProgram.mName = "Non Indexed Fullbright Shader"; - gObjectFullbrightNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectFullbrightNonIndexedProgram.mFeatures.hasGamma = true; - gObjectFullbrightNonIndexedProgram.mFeatures.hasTransport = true; - gObjectFullbrightNonIndexedProgram.mFeatures.isFullbright = true; - gObjectFullbrightNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectFullbrightNonIndexedProgram.mShaderFiles.clear(); - gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectFullbrightNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectFullbrightNonIndexedProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectFullbrightNonIndexedWaterProgram.mName = "Non Indexed Fullbright Water Shader"; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.isFullbright = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasTransport = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectFullbrightNonIndexedWaterProgram.mFeatures.hasSrgb = true; - gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectFullbrightNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - gObjectFullbrightNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectFullbrightNonIndexedWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectEmissiveNonIndexedProgram.mName = "Non Indexed Emissive Shader"; - gObjectEmissiveNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectEmissiveNonIndexedProgram.mFeatures.hasGamma = true; - gObjectEmissiveNonIndexedProgram.mFeatures.hasTransport = true; - gObjectEmissiveNonIndexedProgram.mFeatures.isFullbright = true; - gObjectEmissiveNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectEmissiveNonIndexedProgram.mFeatures.hasSrgb = true; - gObjectEmissiveNonIndexedProgram.mShaderFiles.clear(); - gObjectEmissiveNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectEmissiveNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectEmissiveNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectEmissiveNonIndexedProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectEmissiveNonIndexedWaterProgram.mName = "Non Indexed Emissive Water Shader"; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.isFullbright = true; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.hasTransport = true; - gObjectEmissiveNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectEmissiveNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectEmissiveNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - gObjectEmissiveNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectEmissiveNonIndexedWaterProgram.createShader(NULL, NULL); - } - - if (success) - { gObjectFullbrightNoColorProgram.mName = "Non Indexed no color Fullbright Shader"; gObjectFullbrightNoColorProgram.mFeatures.calculatesAtmospherics = true; gObjectFullbrightNoColorProgram.mFeatures.hasGamma = true; @@ -3116,73 +2998,6 @@ BOOL LLViewerShaderMgr::loadShadersObject() if (success) { - gObjectShinyNonIndexedProgram.mName = "Non Indexed Shiny Shader"; - gObjectShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectShinyNonIndexedProgram.mFeatures.calculatesLighting = true; - gObjectShinyNonIndexedProgram.mFeatures.hasGamma = true; - gObjectShinyNonIndexedProgram.mFeatures.hasAtmospherics = true; - gObjectShinyNonIndexedProgram.mFeatures.isShiny = true; - gObjectShinyNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectShinyNonIndexedProgram.mShaderFiles.clear(); - gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectShinyNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectShinyNonIndexedProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectShinyNonIndexedWaterProgram.mName = "Non Indexed Shiny Water Shader"; - gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.calculatesLighting = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.isShiny = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.hasAtmospherics = true; - gObjectShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectShinyNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectShinyNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - gObjectShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectShinyNonIndexedWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectFullbrightShinyNonIndexedProgram.mName = "Non Indexed Fullbright Shiny Shader"; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.calculatesAtmospherics = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.isFullbright = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.isShiny = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasGamma = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.hasTransport = true; - gObjectFullbrightShinyNonIndexedProgram.mFeatures.disableTextureIndex = true; - gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.clear(); - gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectFullbrightShinyNonIndexedProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightShinyNonIndexedProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectFullbrightShinyNonIndexedProgram.createShader(NULL, NULL); - } - - if (success) - { - gObjectFullbrightShinyNonIndexedWaterProgram.mName = "Non Indexed Fullbright Shiny Water Shader"; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.calculatesAtmospherics = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isFullbright = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.isShiny = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasGamma = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasTransport = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.hasWaterFog = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mFeatures.disableTextureIndex = true; - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.clear(); - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - gObjectFullbrightShinyNonIndexedWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectFullbrightShinyNonIndexedWaterProgram.createShader(NULL, NULL); - } - - if (success) - { gImpostorProgram.mName = "Impostor Shader"; gImpostorProgram.mFeatures.disableTextureIndex = true; gImpostorProgram.mFeatures.hasSrgb = true; @@ -3213,6 +3028,24 @@ BOOL LLViewerShaderMgr::loadShadersObject() if (success) { + gPhysicsPreviewProgram.mName = "Preview Physics Shader"; + gPhysicsPreviewProgram.mFeatures.calculatesLighting = false; + gPhysicsPreviewProgram.mFeatures.calculatesAtmospherics = false; + gPhysicsPreviewProgram.mFeatures.hasGamma = false; + gPhysicsPreviewProgram.mFeatures.hasAtmospherics = false; + gPhysicsPreviewProgram.mFeatures.hasLighting = false; + gPhysicsPreviewProgram.mFeatures.mIndexedTextureChannels = 0; + gPhysicsPreviewProgram.mFeatures.disableTextureIndex = true; + gPhysicsPreviewProgram.mShaderFiles.clear(); + gPhysicsPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewPhysicsV.glsl", GL_VERTEX_SHADER_ARB)); + gPhysicsPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewPhysicsF.glsl", GL_FRAGMENT_SHADER_ARB)); + gPhysicsPreviewProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; + success = gPhysicsPreviewProgram.createShader(NULL, NULL); + gPhysicsPreviewProgram.mFeatures.hasLighting = false; + } + + if (success) + { gObjectSimpleProgram.mName = "Simple Shader"; gObjectSimpleProgram.mFeatures.calculatesLighting = true; gObjectSimpleProgram.mFeatures.calculatesAtmospherics = true; @@ -3224,7 +3057,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectSimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectSimpleProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectSimpleProgram, gSkinnedObjectSimpleProgram); + success = success && gObjectSimpleProgram.createShader(NULL, NULL); } if (success) @@ -3244,8 +3078,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectSimpleImpostorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - - success = gObjectSimpleImpostorProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectSimpleImpostorProgram, gSkinnedObjectSimpleImpostorProgram); + success = success && gObjectSimpleImpostorProgram.createShader(NULL, NULL); } if (success) @@ -3262,30 +3096,30 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectSimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; + make_rigged_variant(gObjectSimpleWaterProgram, gSkinnedObjectSimpleWaterProgram); success = gObjectSimpleWaterProgram.createShader(NULL, NULL); } if (success) { gObjectBumpProgram.mName = "Bump Shader"; - /*gObjectBumpProgram.mFeatures.calculatesLighting = true; - gObjectBumpProgram.mFeatures.calculatesAtmospherics = true; - gObjectBumpProgram.mFeatures.hasGamma = true; - gObjectBumpProgram.mFeatures.hasAtmospherics = true; - gObjectBumpProgram.mFeatures.hasLighting = true; - gObjectBumpProgram.mFeatures.mIndexedTextureChannels = 0;*/ gObjectBumpProgram.mFeatures.encodesNormal = true; gObjectBumpProgram.mShaderFiles.clear(); gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpV.glsl", GL_VERTEX_SHADER_ARB)); gObjectBumpProgram.mShaderFiles.push_back(make_pair("objects/bumpF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectBumpProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectBumpProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectBumpProgram, gSkinnedObjectBumpProgram); + success = success && gObjectBumpProgram.createShader(NULL, NULL); if (success) { //lldrawpoolbump assumes "texture0" has channel 0 and "texture1" has channel 1 - gObjectBumpProgram.bind(); - gObjectBumpProgram.uniform1i(sTexture0, 0); - gObjectBumpProgram.uniform1i(sTexture1, 1); - gObjectBumpProgram.unbind(); + LLGLSLShader* shader[] = { &gObjectBumpProgram, &gSkinnedObjectBumpProgram }; + for (int i = 0; i < 2; ++i) + { + shader[i]->bind(); + shader[i]->uniform1i(sTexture0, 0); + shader[i]->uniform1i(sTexture1, 1); + shader[i]->unbind(); + } } } @@ -3304,7 +3138,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB)); gObjectSimpleAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectSimpleAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectSimpleAlphaMaskProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectSimpleAlphaMaskProgram, gSkinnedObjectSimpleAlphaMaskProgram); + success = success && gObjectSimpleAlphaMaskProgram.createShader(NULL, NULL); } if (success) @@ -3322,7 +3157,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectSimpleWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectSimpleWaterAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectSimpleWaterAlphaMaskProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectSimpleWaterAlphaMaskProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectSimpleWaterAlphaMaskProgram, gSkinnedObjectSimpleWaterAlphaMaskProgram); + success = success && gObjectSimpleWaterAlphaMaskProgram.createShader(NULL, NULL); } if (success) @@ -3338,7 +3174,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectFullbrightProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectFullbrightProgram, gSkinnedObjectFullbrightProgram); + success = success && gObjectFullbrightProgram.createShader(NULL, NULL); } if (success) @@ -3346,7 +3183,7 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightWaterProgram.mName = "Fullbright Water Shader"; gObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true; gObjectFullbrightWaterProgram.mFeatures.isFullbright = true; - gObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true; + gObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true; gObjectFullbrightWaterProgram.mFeatures.hasTransport = true; gObjectFullbrightWaterProgram.mFeatures.mIndexedTextureChannels = 0; gObjectFullbrightWaterProgram.mShaderFiles.clear(); @@ -3354,7 +3191,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectFullbrightWaterProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectFullbrightWaterProgram, gSkinnedObjectFullbrightWaterProgram); + success = success && gObjectFullbrightWaterProgram.createShader(NULL, NULL); } if (success) @@ -3370,7 +3208,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/emissiveV.glsl", GL_VERTEX_SHADER_ARB)); gObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectEmissiveProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectEmissiveProgram, gSkinnedObjectEmissiveProgram); + success = success && gObjectEmissiveProgram.createShader(NULL, NULL); } if (success) @@ -3386,7 +3225,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectEmissiveWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectEmissiveWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectEmissiveWaterProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectEmissiveWaterProgram, gSkinnedObjectEmissiveWaterProgram); + success = success && gObjectEmissiveWaterProgram.createShader(NULL, NULL); } if (success) @@ -3403,12 +3243,13 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectFullbrightAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectFullbrightAlphaMaskProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectFullbrightAlphaMaskProgram, gSkinnedObjectFullbrightAlphaMaskProgram); + success = success && gObjectFullbrightAlphaMaskProgram.createShader(NULL, NULL); } if (success) { - gObjectFullbrightWaterAlphaMaskProgram.mName = "Fullbright Water Shader"; + gObjectFullbrightWaterAlphaMaskProgram.mName = "Fullbright Water Alpha Mask Shader"; gObjectFullbrightWaterAlphaMaskProgram.mFeatures.calculatesAtmospherics = true; gObjectFullbrightWaterAlphaMaskProgram.mFeatures.isFullbright = true; gObjectFullbrightWaterAlphaMaskProgram.mFeatures.hasWaterFog = true; @@ -3420,7 +3261,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightWaterAlphaMaskProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectFullbrightWaterAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightWaterAlphaMaskProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectFullbrightWaterAlphaMaskProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectFullbrightWaterAlphaMaskProgram, gSkinnedObjectFullbrightWaterAlphaMaskProgram); + success = success && gObjectFullbrightWaterAlphaMaskProgram.createShader(NULL, NULL); } if (success) @@ -3436,7 +3278,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB)); gObjectShinyProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectShinyProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectShinyProgram, gSkinnedObjectShinyProgram); + success = success && gObjectShinyProgram.createShader(NULL, NULL); } if (success) @@ -3453,7 +3296,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyV.glsl", GL_VERTEX_SHADER_ARB)); gObjectShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectShinyWaterProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectShinyWaterProgram, gSkinnedObjectShinyWaterProgram); + success = success && gObjectShinyWaterProgram.createShader(NULL, NULL); } if (success) @@ -3469,7 +3313,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB)); gObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gObjectFullbrightShinyProgram.createShader(NULL, NULL); + success = make_rigged_variant(gObjectFullbrightShinyProgram, gSkinnedObjectFullbrightShinyProgram); + success = success && gObjectFullbrightShinyProgram.createShader(NULL, NULL); } if (success) @@ -3487,196 +3332,8 @@ BOOL LLViewerShaderMgr::loadShadersObject() gObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectFullbrightShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; gObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - success = gObjectFullbrightShinyWaterProgram.createShader(NULL, NULL); - } - - if (mShaderLevel[SHADER_AVATAR] > 0) - { //load hardware skinned attachment shaders - if (success) - { - gSkinnedObjectSimpleProgram.mName = "Skinned Simple Shader"; - gSkinnedObjectSimpleProgram.mFeatures.calculatesLighting = true; - gSkinnedObjectSimpleProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectSimpleProgram.mFeatures.hasGamma = true; - gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true; - gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true; - gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectSimpleProgram.mFeatures.hasAlphaMask = true; - gSkinnedObjectSimpleProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectSimpleProgram.mShaderFiles.clear(); - gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectSimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectFullbrightProgram.mName = "Skinned Fullbright Shader"; - gSkinnedObjectFullbrightProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectFullbrightProgram.mFeatures.hasGamma = true; - gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true; - gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true; - gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectFullbrightProgram.mFeatures.hasAlphaMask = true; - gSkinnedObjectFullbrightProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectFullbrightProgram.mFeatures.hasSrgb = true; - gSkinnedObjectFullbrightProgram.mShaderFiles.clear(); - gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectFullbrightProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectFullbrightProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectEmissiveProgram.mName = "Skinned Emissive Shader"; - gSkinnedObjectEmissiveProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectEmissiveProgram.mFeatures.hasGamma = true; - gSkinnedObjectEmissiveProgram.mFeatures.hasTransport = true; - gSkinnedObjectEmissiveProgram.mFeatures.isFullbright = true; - gSkinnedObjectEmissiveProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectEmissiveProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectEmissiveProgram.mFeatures.hasSrgb = true; - gSkinnedObjectEmissiveProgram.mShaderFiles.clear(); - gSkinnedObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/emissiveSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectEmissiveProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectEmissiveProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectEmissiveProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectEmissiveWaterProgram.mName = "Skinned Emissive Water Shader"; - gSkinnedObjectEmissiveWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.hasTransport = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.isFullbright = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectEmissiveWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectEmissiveWaterProgram.mShaderFiles.clear(); - gSkinnedObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/emissiveSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectEmissiveWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectEmissiveWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectEmissiveWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader"; - gSkinnedObjectFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.hasGamma = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.hasTransport = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.hasAlphaMask = true; - gSkinnedObjectFullbrightShinyProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear(); - gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectShinySimpleProgram.mName = "Skinned Shiny Simple Shader"; - gSkinnedObjectShinySimpleProgram.mFeatures.calculatesLighting = true; - gSkinnedObjectShinySimpleProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true; - gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true; - gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectShinySimpleProgram.mFeatures.hasAlphaMask = true; - gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true; - gSkinnedObjectShinySimpleProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectShinySimpleProgram.mShaderFiles.clear(); - gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectShinySimpleProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectShinySimpleProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectSimpleWaterProgram.mName = "Skinned Simple Water Shader"; - gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesLighting = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasAtmospherics = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasLighting = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectSimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectSimpleWaterProgram.mFeatures.hasAlphaMask = true; - gSkinnedObjectSimpleWaterProgram.mShaderFiles.clear(); - gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectSimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/simpleWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectSimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectSimpleWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectFullbrightWaterProgram.mName = "Skinned Fullbright Water Shader"; - gSkinnedObjectFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasTransport = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.isFullbright = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasAlphaMask = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectFullbrightWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gSkinnedObjectFullbrightWaterProgram.mShaderFiles.clear(); - gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectFullbrightWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectFullbrightWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectFullbrightWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectFullbrightShinyWaterProgram.mName = "Skinned Fullbright Shiny Water Shader"; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasTransport = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isShiny = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isFullbright = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasAlphaMask = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.clear(); - gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectFullbrightShinyWaterProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectFullbrightShinyWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectFullbrightShinyWaterProgram.createShader(NULL, NULL); - } - - if (success) - { - gSkinnedObjectShinySimpleWaterProgram.mName = "Skinned Shiny Simple Water Shader"; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesLighting = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.calculatesAtmospherics = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasGamma = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAtmospherics = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasObjectSkinning = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAlphaMask = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.isShiny = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasWaterFog = true; - gSkinnedObjectShinySimpleWaterProgram.mFeatures.disableTextureIndex = true; - gSkinnedObjectShinySimpleWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.clear(); - gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); - gSkinnedObjectShinySimpleWaterProgram.mShaderFiles.push_back(make_pair("objects/shinyWaterF.glsl", GL_FRAGMENT_SHADER_ARB)); - gSkinnedObjectShinySimpleWaterProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; - success = gSkinnedObjectShinySimpleWaterProgram.createShader(NULL, NULL); - } + success = make_rigged_variant(gObjectFullbrightShinyWaterProgram, gSkinnedObjectFullbrightShinyWaterProgram); + success = success && gObjectFullbrightShinyWaterProgram.createShader(NULL, NULL); } if( !success ) @@ -3789,12 +3446,6 @@ BOOL LLViewerShaderMgr::loadShadersInterface() { BOOL success = TRUE; - if (mShaderLevel[SHADER_INTERFACE] == 0) - { - gHighlightProgram.unload(); - return TRUE; - } - if (success) { gHighlightProgram.mName = "Highlight Shader"; @@ -3802,7 +3453,8 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightV.glsl", GL_VERTEX_SHADER_ARB)); gHighlightProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB)); gHighlightProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gHighlightProgram.createShader(NULL, NULL); + success = make_rigged_variant(gHighlightProgram, gSkinnedHighlightProgram); + success = success && gHighlightProgram.createShader(NULL, NULL); } if (success) @@ -4004,9 +3656,21 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionV.glsl", GL_VERTEX_SHADER_ARB)); gOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB)); gOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + gOcclusionProgram.mRiggedVariant = &gSkinnedOcclusionProgram; success = gOcclusionProgram.createShader(NULL, NULL); } + if (success) + { + gSkinnedOcclusionProgram.mName = "Skinned Occlusion Shader"; + gSkinnedOcclusionProgram.mFeatures.hasObjectSkinning = true; + gSkinnedOcclusionProgram.mShaderFiles.clear(); + gSkinnedOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionSkinnedV.glsl", GL_VERTEX_SHADER_ARB)); + gSkinnedOcclusionProgram.mShaderFiles.push_back(make_pair("interface/occlusionF.glsl", GL_FRAGMENT_SHADER_ARB)); + gSkinnedOcclusionProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; + success = gSkinnedOcclusionProgram.createShader(NULL, NULL); + } + if (success) { gOcclusionCubeProgram.mName = "Occlusion Cube Shader"; @@ -4023,8 +3687,10 @@ BOOL LLViewerShaderMgr::loadShadersInterface() gDebugProgram.mShaderFiles.clear(); gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugV.glsl", GL_VERTEX_SHADER_ARB)); gDebugProgram.mShaderFiles.push_back(make_pair("interface/debugF.glsl", GL_FRAGMENT_SHADER_ARB)); + gDebugProgram.mRiggedVariant = &gSkinnedDebugProgram; gDebugProgram.mShaderLevel = mShaderLevel[SHADER_INTERFACE]; - success = gDebugProgram.createShader(NULL, NULL); + success = make_rigged_variant(gDebugProgram, gSkinnedDebugProgram); + success = success && gDebugProgram.createShader(NULL, NULL); } if (success) diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 081221f15b..93bb29a355 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -181,13 +181,12 @@ extern LLGLSLShader gOneTextureNoColorProgram; extern LLGLSLShader gObjectSimpleProgram; extern LLGLSLShader gObjectSimpleImpostorProgram; extern LLGLSLShader gObjectPreviewProgram; +extern LLGLSLShader gPhysicsPreviewProgram; extern LLGLSLShader gObjectSimpleAlphaMaskProgram; extern LLGLSLShader gObjectSimpleWaterProgram; extern LLGLSLShader gObjectSimpleWaterAlphaMaskProgram; -extern LLGLSLShader gObjectSimpleNonIndexedProgram; extern LLGLSLShader gObjectSimpleNonIndexedTexGenProgram; extern LLGLSLShader gObjectSimpleNonIndexedTexGenWaterProgram; -extern LLGLSLShader gObjectSimpleNonIndexedWaterProgram; extern LLGLSLShader gObjectAlphaMaskNonIndexedProgram; extern LLGLSLShader gObjectAlphaMaskNonIndexedWaterProgram; extern LLGLSLShader gObjectAlphaMaskNoColorProgram; @@ -200,8 +199,6 @@ extern LLGLSLShader gObjectEmissiveProgram; extern LLGLSLShader gObjectEmissiveWaterProgram; extern LLGLSLShader gObjectFullbrightAlphaMaskProgram; extern LLGLSLShader gObjectFullbrightWaterAlphaMaskProgram; -extern LLGLSLShader gObjectFullbrightNonIndexedProgram; -extern LLGLSLShader gObjectFullbrightNonIndexedWaterProgram; extern LLGLSLShader gObjectEmissiveNonIndexedProgram; extern LLGLSLShader gObjectEmissiveNonIndexedWaterProgram; extern LLGLSLShader gObjectBumpProgram; @@ -213,25 +210,9 @@ extern LLGLSLShader gObjectFullbrightLODProgram; extern LLGLSLShader gObjectFullbrightShinyProgram; extern LLGLSLShader gObjectFullbrightShinyWaterProgram; -extern LLGLSLShader gObjectFullbrightShinyNonIndexedProgram; -extern LLGLSLShader gObjectFullbrightShinyNonIndexedWaterProgram; extern LLGLSLShader gObjectShinyProgram; extern LLGLSLShader gObjectShinyWaterProgram; -extern LLGLSLShader gObjectShinyNonIndexedProgram; -extern LLGLSLShader gObjectShinyNonIndexedWaterProgram; - -extern LLGLSLShader gSkinnedObjectSimpleProgram; -extern LLGLSLShader gSkinnedObjectFullbrightProgram; -extern LLGLSLShader gSkinnedObjectEmissiveProgram; -extern LLGLSLShader gSkinnedObjectFullbrightShinyProgram; -extern LLGLSLShader gSkinnedObjectShinySimpleProgram; - -extern LLGLSLShader gSkinnedObjectSimpleWaterProgram; -extern LLGLSLShader gSkinnedObjectFullbrightWaterProgram; -extern LLGLSLShader gSkinnedObjectEmissiveWaterProgram; -extern LLGLSLShader gSkinnedObjectFullbrightShinyWaterProgram; -extern LLGLSLShader gSkinnedObjectShinySimpleWaterProgram; //environment shaders extern LLGLSLShader gTerrainProgram; @@ -281,9 +262,6 @@ extern LLGLSLShader gDeferredDiffuseAlphaMaskProgram; extern LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskProgram; extern LLGLSLShader gDeferredNonIndexedDiffuseAlphaMaskNoColorProgram; extern LLGLSLShader gDeferredNonIndexedDiffuseProgram; -extern LLGLSLShader gDeferredSkinnedDiffuseProgram; -extern LLGLSLShader gDeferredSkinnedBumpProgram; -extern LLGLSLShader gDeferredSkinnedAlphaProgram; extern LLGLSLShader gDeferredBumpProgram; extern LLGLSLShader gDeferredTerrainProgram; extern LLGLSLShader gDeferredTerrainWaterProgram; @@ -330,8 +308,6 @@ extern LLGLSLShader gDeferredWLSunProgram; extern LLGLSLShader gDeferredWLMoonProgram; extern LLGLSLShader gDeferredStarProgram; extern LLGLSLShader gDeferredFullbrightShinyProgram; -extern LLGLSLShader gDeferredSkinnedFullbrightShinyProgram; -extern LLGLSLShader gDeferredSkinnedFullbrightProgram; extern LLGLSLShader gNormalMapGenProgram; // Deferred materials shaders diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 0ca4a3712d..9d6cfbce7c 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -182,8 +182,9 @@ SimMeasurement<F64Kilobytes > SIM_UNACKED_BYTES("simtotalunackedbytes", "", LL_S SimMeasurement<F64Megabytes > SIM_PHYSICS_MEM("physicsmemoryallocated", "", LL_SIM_STAT_SIMPHYSICSMEMORY); LLTrace::SampleStatHandle<F64Milliseconds > FRAMETIME_JITTER("frametimejitter", "Average delta between successive frame times"), - FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"), - SIM_PING("simpingstat"); + FRAMETIME_SLEW("frametimeslew", "Average delta between frame time and mean"), + FRAMETIME("frametime", "Measured frame time"), + SIM_PING("simpingstat"); LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP("agentpositionsnap", "agent position corrections"); @@ -261,8 +262,11 @@ void LLViewerStats::updateFrameStats(const F64Seconds time_diff) // new "stutter" meter add(LLStatViewer::FRAMETIME_DOUBLED, time_diff >= 2.0 * mLastTimeDiff ? 1 : 0); + sample(LLStatViewer::FRAMETIME, time_diff); + // old stats that were never really used - sample(LLStatViewer::FRAMETIME_JITTER, F64Milliseconds (mLastTimeDiff - time_diff)); + F64Seconds jit = (F64Seconds) std::fabs((mLastTimeDiff - time_diff)); + sample(LLStatViewer::FRAMETIME_JITTER, jit); F32Seconds average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount; sample(LLStatViewer::FRAMETIME_SLEW, F64Milliseconds (average_frametime - time_diff)); @@ -388,8 +392,12 @@ void update_statistics() gTransferManager.resetTransferBitsIn(LLTCT_ASSET); sample(LLStatViewer::VISIBLE_AVATARS, LLVOAvatar::sNumVisibleAvatars); - LLWorld::getInstance()->updateNetStats(); - LLWorld::getInstance()->requestCacheMisses(); + LLWorld *world = LLWorld::getInstance(); // not LLSingleton + if (world) + { + world->updateNetStats(); + world->requestCacheMisses(); + } // Reset all of these values. gVLManager.resetBitCounts(); @@ -540,7 +548,7 @@ void send_viewer_stats(bool include_preferences) { shader_level = 2; } - else if (gPipeline.canUseVertexShaders()) + else if (gPipeline.shadersLoaded()) { shader_level = 1; } diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 4468e44ea8..017c79b2e3 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -217,8 +217,8 @@ extern SimMeasurement<F64Megabytes > SIM_PHYSICS_MEM; extern LLTrace::SampleStatHandle<F64Milliseconds > FRAMETIME_JITTER, - FRAMETIME_SLEW, - SIM_PING; + FRAMETIME_SLEW, + SIM_PING; extern LLTrace::EventStatHandle<LLUnit<F64, LLUnits::Meters> > AGENT_POSITION_SNAP; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 075588d577..e3ac56d0d3 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -182,6 +182,7 @@ void LLViewerTextureManager::findFetchedTextures(const LLUUID& id, std::vector<L void LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewerTexture*> &output) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; std::vector<LLViewerFetchedTexture*> fetched_output; gTextureList.findTexturesByID(id, fetched_output); std::vector<LLViewerFetchedTexture*>::iterator iter = fetched_output.begin(); @@ -206,6 +207,7 @@ void LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewe LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; return gTextureList.findImage(id, (ETexListType)tex_type); } @@ -477,11 +479,10 @@ const F32 GPU_MEMORY_CHECK_WAIT_TIME = 1.0f; F32 texmem_lower_bound_scale = 0.85f; F32 texmem_middle_bound_scale = 0.925f; -static LLTrace::BlockTimerStatHandle FTM_TEXTURE_MEMORY_CHECK("Memory Check"); - //static bool LLViewerTexture::isMemoryForTextureLow() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // Note: we need to figure out a better source for 'min' values, // what is free for low end at minimal settings is 'nothing left' // for higher end gpus at high settings. @@ -498,6 +499,7 @@ bool LLViewerTexture::isMemoryForTextureLow() //static bool LLViewerTexture::isMemoryForTextureSuficientlyFree() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; const S32Megabytes DESIRED_FREE_TEXTURE_MEMORY(50); const S32Megabytes DESIRED_FREE_MAIN_MEMORY(200); @@ -511,10 +513,12 @@ bool LLViewerTexture::isMemoryForTextureSuficientlyFree() //static void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &physical) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static LLFrameTimer timer; + static S32Megabytes gpu_res = S32Megabytes(S32_MAX); static S32Megabytes physical_res = S32Megabytes(S32_MAX); - + if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second. { gpu = gpu_res; @@ -523,48 +527,31 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p } timer.reset(); - LL_RECORD_BLOCK_TIME(FTM_TEXTURE_MEMORY_CHECK); - - if (gGLManager.mHasATIMemInfo) { - S32 meminfo[4]; - glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo); - gpu_res = (S32Megabytes)meminfo[0]; - + gpu_res = (S32Megabytes) LLImageGLThread::getFreeVRAMMegabytes(); + //check main memory, only works for windows. LLMemory::updateMemoryInfo(); physical_res = LLMemory::getAvailableMemKB(); - } - else if (gGLManager.mHasNVXMemInfo) - { - S32 free_memory; - glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory); - gpu_res = (S32Megabytes)(free_memory / 1024); - } - gpu = gpu_res; - physical = physical_res; + gpu = gpu_res; + physical = physical_res; + } } -static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_MEDIA("Media"); -static LLTrace::BlockTimerStatHandle FTM_TEXTURE_UPDATE_TEST("Test"); - //static -void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity) +void LLViewerTexture::updateClass() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; sCurrentTime = gFrameTimeSeconds; LLTexturePipelineTester* tester = (LLTexturePipelineTester*)LLMetricPerformanceTesterBasic::getTester(sTesterName); if (tester) { - LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE_TEST); tester->update(); } - { - LL_RECORD_BLOCK_TIME(FTM_TEXTURE_UPDATE_MEDIA); - LLViewerMediaTexture::updateClass(); - } + LLViewerMediaTexture::updateClass(); sBoundTextureMemory = LLImageGL::sBoundTextureMemory; sTotalTextureMemory = LLImageGL::sGlobalTextureMemory; @@ -680,6 +667,9 @@ void LLViewerTexture::init(bool firstinit) mVolumeList[LLRender::LIGHT_TEX].clear(); mVolumeList[LLRender::SCULPT_TEX].clear(); + + mMainQueue = LL::WorkQueue::getInstance("mainloop"); + mImageQueue = LL::WorkQueue::getInstance("LLImageGL"); } //virtual @@ -701,6 +691,7 @@ void LLViewerTexture::cleanup() void LLViewerTexture::notifyAboutCreatingTexture() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) { for(U32 f = 0; f < mNumFaces[ch]; f++) @@ -712,6 +703,7 @@ void LLViewerTexture::notifyAboutCreatingTexture() void LLViewerTexture::notifyAboutMissingAsset() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; for(U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch) { for(U32 f = 0; f < mNumFaces[ch]; f++) @@ -724,6 +716,7 @@ void LLViewerTexture::notifyAboutMissingAsset() // virtual void LLViewerTexture::dump() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLGLTexture::dump(); LL_INFOS() << "LLViewerTexture" @@ -759,6 +752,7 @@ bool LLViewerTexture::isActiveFetching() bool LLViewerTexture::bindDebugImage(const S32 stage) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (stage < 0) return false; bool res = true; @@ -777,6 +771,7 @@ bool LLViewerTexture::bindDebugImage(const S32 stage) bool LLViewerTexture::bindDefaultImage(S32 stage) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (stage < 0) return false; bool res = true; @@ -819,6 +814,7 @@ void LLViewerTexture::forceImmediateUpdate() void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(needs_gltexture) { mNeedsGLTexture = TRUE; @@ -829,14 +825,14 @@ void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) co { //flag to reset the values because the old values are used. resetMaxVirtualSizeResetCounter(); - mMaxVirtualSize = virtual_size; - mAdditionalDecodePriority = 0.f; + mMaxVirtualSize = virtual_size; + mAdditionalDecodePriority = 0.f; mNeedsGLTexture = needs_gltexture; } else if (virtual_size > mMaxVirtualSize) { mMaxVirtualSize = virtual_size; - } + } } void LLViewerTexture::resetTextureStats() @@ -861,6 +857,7 @@ void LLViewerTexture::setKnownDrawSize(S32 width, S32 height) //virtual void LLViewerTexture::addFace(U32 ch, LLFace* facep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); if(mNumFaces[ch] >= mFaceList[ch].size()) @@ -876,6 +873,7 @@ void LLViewerTexture::addFace(U32 ch, LLFace* facep) //virtual void LLViewerTexture::removeFace(U32 ch, LLFace* facep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); if(mNumFaces[ch] > 1) @@ -916,6 +914,7 @@ S32 LLViewerTexture::getNumFaces(U32 ch) const //virtual void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (mNumVolumes[ch] >= mVolumeList[ch].size()) { mVolumeList[ch].resize(2 * mNumVolumes[ch] + 1); @@ -929,6 +928,7 @@ void LLViewerTexture::addVolume(U32 ch, LLVOVolume* volumep) //virtual void LLViewerTexture::removeVolume(U32 ch, LLVOVolume* volumep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (mNumVolumes[ch] > 1) { S32 index = volumep->getIndexInTex(ch); @@ -952,6 +952,7 @@ S32 LLViewerTexture::getNumVolumes(U32 ch) const void LLViewerTexture::reorganizeFaceList() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static const F32 MAX_WAIT_TIME = 20.f; // seconds static const U32 MAX_EXTRA_BUFFER_SIZE = 4; @@ -975,6 +976,7 @@ void LLViewerTexture::reorganizeFaceList() void LLViewerTexture::reorganizeVolumeList() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static const F32 MAX_WAIT_TIME = 20.f; // seconds static const U32 MAX_EXTRA_BUFFER_SIZE = 4; @@ -1177,6 +1179,7 @@ FTType LLViewerFetchedTexture::getFTType() const void LLViewerFetchedTexture::cleanup() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); iter != mLoadedCallbackList.end(); ) { @@ -1202,6 +1205,7 @@ void LLViewerFetchedTexture::cleanup() //access the fast cache void LLViewerFetchedTexture::loadFromFastCache() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(!mInFastCacheList) { return; //no need to access the fast cache. @@ -1347,6 +1351,7 @@ void LLViewerFetchedTexture::dump() // ONLY called from LLViewerFetchedTextureList void LLViewerFetchedTexture::destroyTexture() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(LLImageGL::sGlobalTextureMemory < sMaxDesiredTextureMem * 0.95f)//not ready to release unused memory. { return ; @@ -1363,6 +1368,7 @@ void LLViewerFetchedTexture::destroyTexture() void LLViewerFetchedTexture::addToCreateTexture() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; bool force_update = false; if (getComponents() != mRawImage->getComponents()) { @@ -1404,6 +1410,7 @@ void LLViewerFetchedTexture::addToCreateTexture() } else { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; #if 1 // //if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up, @@ -1448,99 +1455,104 @@ void LLViewerFetchedTexture::addToCreateTexture() } } #endif - mNeedsCreateTexture = TRUE; - gTextureList.mCreateTextureList.insert(this); - } + scheduleCreateTexture(); + } return; } // ONLY called from LLViewerTextureList -BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) +BOOL LLViewerFetchedTexture::preCreateTexture(S32 usename/*= 0*/) { - if (!mNeedsCreateTexture) - { - destroyRawImage(); - return FALSE; - } - mNeedsCreateTexture = FALSE; - if (mRawImage.isNull()) - { - LL_ERRS() << "LLViewerTexture trying to create texture with no Raw Image" << LL_ENDL; - } - if (mRawImage->isBufferInvalid()) - { - LL_WARNS() << "Can't create a texture: invalid image data" << LL_ENDL; - destroyRawImage(); - return FALSE; - } -// LL_INFOS() << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", -// mRawDiscardLevel, -// mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) -// << mID.getString() << LL_ENDL; - BOOL res = TRUE; + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; +#if LL_IMAGEGL_THREAD_CHECK + mGLTexturep->checkActiveThread(); +#endif - // store original size only for locally-sourced images - if (mUrl.compare(0, 7, "file://") == 0) - { - mOrigWidth = mRawImage->getWidth(); - mOrigHeight = mRawImage->getHeight(); + if (!mNeedsCreateTexture) + { + destroyRawImage(); + return FALSE; + } + mNeedsCreateTexture = FALSE; + + if (mRawImage.isNull()) + { + LL_ERRS() << "LLViewerTexture trying to create texture with no Raw Image" << LL_ENDL; + } + if (mRawImage->isBufferInvalid()) + { + LL_WARNS() << "Can't create a texture: invalid image data" << LL_ENDL; + destroyRawImage(); + return FALSE; + } + // LL_INFOS() << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", + // mRawDiscardLevel, + // mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) + // << mID.getString() << LL_ENDL; + BOOL res = TRUE; + + // store original size only for locally-sourced images + if (mUrl.compare(0, 7, "file://") == 0) + { + mOrigWidth = mRawImage->getWidth(); + mOrigHeight = mRawImage->getHeight(); // This is only safe because it's a local image and fetcher doesn't use raw data // from local images, but this might become unsafe in case of changes to fetcher - if (mBoostLevel == BOOST_PREVIEW) - { - mRawImage->biasedScaleToPowerOfTwo(1024); - } - else - { // leave black border, do not scale image content - mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); - } - - mFullWidth = mRawImage->getWidth(); - mFullHeight = mRawImage->getHeight(); - setTexelsPerImage(); - } - else - { - mOrigWidth = mFullWidth; - mOrigHeight = mFullHeight; - } + if (mBoostLevel == BOOST_PREVIEW) + { + mRawImage->biasedScaleToPowerOfTwo(1024); + } + else + { // leave black border, do not scale image content + mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); + } - bool size_okay = true; + mFullWidth = mRawImage->getWidth(); + mFullHeight = mRawImage->getHeight(); + setTexelsPerImage(); + } + else + { + mOrigWidth = mFullWidth; + mOrigHeight = mFullHeight; + } - S32 discard_level = mRawDiscardLevel; - if (mRawDiscardLevel < 0) - { - LL_DEBUGS() << "Negative raw discard level when creating image: " << mRawDiscardLevel << LL_ENDL; - discard_level = 0; - } + bool size_okay = true; - U32 raw_width = mRawImage->getWidth() << discard_level; - U32 raw_height = mRawImage->getHeight() << discard_level; + S32 discard_level = mRawDiscardLevel; + if (mRawDiscardLevel < 0) + { + LL_DEBUGS() << "Negative raw discard level when creating image: " << mRawDiscardLevel << LL_ENDL; + discard_level = 0; + } - if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE ) - { - LL_INFOS() << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << LL_ENDL; - size_okay = false; - } - - if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) - { - // A non power-of-two image was uploaded (through a non standard client) - LL_INFOS() << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << LL_ENDL; - size_okay = false; - } - - if( !size_okay ) - { - // An inappropriately-sized image was uploaded (through a non standard client) - // We treat these images as missing assets which causes them to - // be renderd as 'missing image' and to stop requesting data - LL_WARNS() << "!size_ok, setting as missing" << LL_ENDL; - setIsMissingAsset(); - destroyRawImage(); - return FALSE; - } + U32 raw_width = mRawImage->getWidth() << discard_level; + U32 raw_height = mRawImage->getHeight() << discard_level; + + if (raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE) + { + LL_INFOS() << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << LL_ENDL; + size_okay = false; + } + + if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) + { + // A non power-of-two image was uploaded (through a non standard client) + LL_INFOS() << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << LL_ENDL; + size_okay = false; + } + + if (!size_okay) + { + // An inappropriately-sized image was uploaded (through a non standard client) + // We treat these images as missing assets which causes them to + // be renderd as 'missing image' and to stop requesting data + LL_WARNS() << "!size_ok, setting as missing" << LL_ENDL; + setIsMissingAsset(); + destroyRawImage(); + return FALSE; + } if (mGLTexturep->getHasExplicitFormat()) { @@ -1562,19 +1574,116 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) } } - res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel); + return res; +} - notifyAboutCreatingTexture(); +BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) +{ + if (!mNeedsCreateTexture) + { + return FALSE; + } - setActive(); + BOOL res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel); + + return res; +} - if (!needsToSaveRawImage()) - { - mNeedsAux = FALSE; - destroyRawImage(); - } +void LLViewerFetchedTexture::postCreateTexture() +{ + if (!mNeedsCreateTexture) + { + return; + } +#if LL_IMAGEGL_THREAD_CHECK + mGLTexturep->checkActiveThread(); +#endif - return res; + notifyAboutCreatingTexture(); + + setActive(); + + if (!needsToSaveRawImage()) + { + mNeedsAux = FALSE; + destroyRawImage(); + } + + mNeedsCreateTexture = FALSE; +} + +void LLViewerFetchedTexture::scheduleCreateTexture() +{ + if (!mNeedsCreateTexture) + { + mNeedsCreateTexture = TRUE; + if (preCreateTexture()) + { +#if LL_IMAGEGL_THREAD_CHECK + //grab a copy of the raw image data to make sure it isn't modified pending texture creation + U8* data = mRawImage->getData(); + U8* data_copy = nullptr; + S32 size = mRawImage->getDataSize(); + if (data != nullptr && size > 0) + { + data_copy = new U8[size]; + memcpy(data_copy, data, size); + } +#endif + mNeedsCreateTexture = TRUE; + auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr; + if (mainq) + { + ref(); + mainq->postTo( + mImageQueue, + // work to be done on LLImageGL worker thread +#if LL_IMAGEGL_THREAD_CHECK + [this, data, data_copy, size]() + { + mGLTexturep->mActiveThread = LLThread::currentID(); + //verify data is unmodified + llassert(data == mRawImage->getData()); + llassert(mRawImage->getDataSize() == size); + llassert(memcmp(data, data_copy, size) == 0); +#else + [this]() + { +#endif + //actually create the texture on a background thread + createTexture(); + +#if LL_IMAGEGL_THREAD_CHECK + //verify data is unmodified + llassert(data == mRawImage->getData()); + llassert(mRawImage->getDataSize() == size); + llassert(memcmp(data, data_copy, size) == 0); +#endif + }, + // callback to be run on main thread +#if LL_IMAGEGL_THREAD_CHECK + [this, data, data_copy, size]() + { + mGLTexturep->mActiveThread = LLThread::currentID(); + llassert(data == mRawImage->getData()); + llassert(mRawImage->getDataSize() == size); + llassert(memcmp(data, data_copy, size) == 0); + delete[] data_copy; +#else + [this]() + { +#endif + //finalize on main thread + postCreateTexture(); + unref(); + }); + } + else + { + gTextureList.mCreateTextureList.insert(this); + } + } + } } // Call with 0,0 to turn this feature off. @@ -1866,6 +1975,7 @@ void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority) void LLViewerFetchedTexture::updateVirtualSize() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(!mMaxVirtualSizeResetCounter) { addTextureStats(0.f, FALSE);//reset @@ -1957,6 +2067,7 @@ bool LLViewerFetchedTexture::isActiveFetching() bool LLViewerFetchedTexture::updateFetch() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled", false); static LLCachedControl<F32> sCameraMotionThreshold(gSavedSettings,"TextureCameraMotionThreshold", 0.2); static LLCachedControl<S32> sCameraMotionBoost(gSavedSettings,"TextureCameraMotionBoost", 3); @@ -2059,7 +2170,7 @@ bool LLViewerFetchedTexture::updateFetch() } else { - mIsRawImageValid = TRUE; + mIsRawImageValid = TRUE; addToCreateTexture(); } @@ -2537,6 +2648,7 @@ void LLViewerFetchedTexture::pauseLoadedCallbacks(const LLLoadedCallbackEntry::s bool LLViewerFetchedTexture::doLoadedCallbacks() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static const F32 MAX_INACTIVE_TIME = 900.f ; //seconds static const F32 MAX_IDLE_WAIT_TIME = 5.f ; //seconds @@ -2887,7 +2999,9 @@ void LLViewerFetchedTexture::destroyRawImage() //virtual void LLViewerFetchedTexture::switchToCachedImage() { - if(mCachedRawImage.notNull()) + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + if(mCachedRawImage.notNull() && + !mNeedsCreateTexture) // <--- texture creation is pending, don't step on it { mRawImage = mCachedRawImage; @@ -2898,12 +3012,12 @@ void LLViewerFetchedTexture::switchToCachedImage() mComponents = mRawImage->getComponents(); mGLTexturep->setComponents(mComponents); gTextureList.dirtyImage(this); - } + } mIsRawImageValid = TRUE; mRawDiscardLevel = mCachedRawDiscardLevel; - gTextureList.mCreateTextureList.insert(this); - mNeedsCreateTexture = TRUE; + + scheduleCreateTexture(); } } @@ -3177,6 +3291,7 @@ bool LLViewerLODTexture::isUpdateFrozen() //virtual void LLViewerLODTexture::processTextureStats() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; updateVirtualSize(); static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes", false); @@ -3340,6 +3455,7 @@ bool LLViewerLODTexture::scaleDown() //static void LLViewerMediaTexture::updateClass() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static const F32 MAX_INACTIVE_TIME = 30.f; #if 0 diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h index 0de49073c8..b953d7006b 100644 --- a/indra/newview/llviewertexture.h +++ b/indra/newview/llviewertexture.h @@ -35,6 +35,7 @@ #include "llrender.h" #include "llmetricperformancetester.h" #include "httpcommon.h" +#include "workqueue.h" #include <map> #include <list> @@ -114,7 +115,7 @@ protected: public: static void initClass(); - static void updateClass(const F32 velocity, const F32 angular_velocity) ; + static void updateClass(); LLViewerTexture(BOOL usemipmaps = TRUE); LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ; @@ -213,6 +214,9 @@ protected: //do not use LLPointer here. LLViewerMediaTexture* mParcelMedia ; + LL::WorkQueue::weak_t mMainQueue; + LL::WorkQueue::weak_t mImageQueue; + static F32 sTexelPixelRatio; public: static const U32 sCurrentFileVersion; @@ -321,9 +325,13 @@ public: void addToCreateTexture(); - - // ONLY call from LLViewerTextureList + //call to determine if createTexture is necessary + BOOL preCreateTexture(S32 usename = 0); + // ONLY call from LLViewerTextureList or ImageGL background thread BOOL createTexture(S32 usename = 0); + void postCreateTexture(); + void scheduleCreateTexture(); + void destroyTexture() ; virtual void processTextureStats() ; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 37344056e1..208574f0a3 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -66,7 +66,6 @@ void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL; S32 LLViewerTextureList::sNumImages = 0; LLViewerTextureList gTextureList; -static LLTrace::BlockTimerStatHandle FTM_PROCESS_IMAGES("Process Images"); ETexListType get_element_type(S32 priority) { @@ -112,6 +111,7 @@ void LLViewerTextureList::init() void LLViewerTextureList::doPreloadImages() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL; llassert_always(mInitialized) ; @@ -203,6 +203,7 @@ static std::string get_texture_list_name() void LLViewerTextureList::doPrefetchImages() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; gTextureTimer.start(); gTextureTimer.pause(); @@ -259,6 +260,7 @@ LLViewerTextureList::~LLViewerTextureList() void LLViewerTextureList::shutdown() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // clear out preloads mImagePreloads.clear(); @@ -334,6 +336,7 @@ void LLViewerTextureList::shutdown() void LLViewerTextureList::dump() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LL_INFOS() << "LLViewerTextureList::dump()" << LL_ENDL; for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) { @@ -378,6 +381,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& LLGLenum primary_format, const LLUUID& force_id) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(!mInitialized) { return NULL ; @@ -405,6 +409,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& LLGLenum primary_format, const LLUUID& force_id) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(!mInitialized) { return NULL ; @@ -493,6 +498,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id, LLGLenum primary_format, LLHost request_from_host) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(!mInitialized) { return NULL ; @@ -555,6 +561,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, LLGLenum primary_format, LLHost request_from_host) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static LLCachedControl<bool> fast_cache_fetching_enabled(gSavedSettings, "FastCacheFetchEnabled", true); LLPointer<LLViewerFetchedTexture> imagep ; @@ -610,6 +617,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<LLViewerFetchedTexture*> &output) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLTextureKey search_key(image_id, TEX_LIST_STANDARD); uuid_map_t::iterator iter = mUUIDMap.lower_bound(search_key); while (iter != mUUIDMap.end() && iter->first.textureId == image_id) @@ -621,6 +629,7 @@ void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<L LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLTextureKey &search_key) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; uuid_map_t::iterator iter = mUUIDMap.find(search_key); if (iter == mUUIDMap.end()) return NULL; @@ -634,6 +643,7 @@ LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id, E void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; assert_main_thread(); llassert_always(mInitialized) ; llassert(image); @@ -653,6 +663,7 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image) void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; assert_main_thread(); llassert_always(mInitialized) ; llassert(image); @@ -701,6 +712,7 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListType tex_type) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (!new_image) { return; @@ -724,6 +736,7 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image, ETexListTy void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if( image) { if (image->hasCallbacks()) @@ -748,18 +761,10 @@ void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image) } //////////////////////////////////////////////////////////////////////////// -static LLTrace::BlockTimerStatHandle FTM_IMAGE_MARK_DIRTY("Dirty Images"); -static LLTrace::BlockTimerStatHandle FTM_IMAGE_UPDATE_PRIORITIES("Prioritize"); -static LLTrace::BlockTimerStatHandle FTM_IMAGE_CALLBACKS("Callbacks"); -static LLTrace::BlockTimerStatHandle FTM_IMAGE_FETCH("Fetch"); -static LLTrace::BlockTimerStatHandle FTM_FAST_CACHE_IMAGE_FETCH("Fast Cache Fetch"); -static LLTrace::BlockTimerStatHandle FTM_IMAGE_CREATE("Create"); -static LLTrace::BlockTimerStatHandle FTM_IMAGE_STATS("Stats"); -static LLTrace::BlockTimerStatHandle FTM_UPDATE_TEXTURES("Update Textures"); void LLViewerTextureList::updateImages(F32 max_time) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_TEXTURES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; static BOOL cleared = FALSE; if(gTeleportDisplay) { @@ -785,66 +790,49 @@ void LLViewerTextureList::updateImages(F32 max_time) sample(FORMATTED_MEM, F64Bytes(LLImageFormatted::sGlobalFormattedMemory)); } - { - //loading from fast cache - LL_RECORD_BLOCK_TIME(FTM_FAST_CACHE_IMAGE_FETCH); - max_time -= updateImagesLoadingFastCache(max_time); - } - - { - LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_PRIORITIES); - updateImagesDecodePriorities(); - } - - F32 total_max_time = max_time; - - { - LL_RECORD_BLOCK_TIME(FTM_IMAGE_FETCH); - max_time -= updateImagesFetchTextures(max_time); - } + //loading from fast cache + max_time -= updateImagesLoadingFastCache(max_time); - { - LL_RECORD_BLOCK_TIME(FTM_IMAGE_CREATE); - max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time - max_time -= updateImagesCreateTextures(max_time); - } + updateImagesDecodePriorities(); + + F32 total_max_time = max_time; + + max_time -= updateImagesFetchTextures(max_time); + + max_time = llmax(max_time, total_max_time*.50f); // at least 50% of max_time + max_time -= updateImagesCreateTextures(max_time); if (!mDirtyTextureList.empty()) { - LL_RECORD_BLOCK_TIME(FTM_IMAGE_MARK_DIRTY); gPipeline.dirtyPoolObjectTextures(mDirtyTextureList); mDirtyTextureList.clear(); } + bool didone = false; + for (image_list_t::iterator iter = mCallbackList.begin(); + iter != mCallbackList.end(); ) { - LL_RECORD_BLOCK_TIME(FTM_IMAGE_CALLBACKS); - bool didone = false; - for (image_list_t::iterator iter = mCallbackList.begin(); - iter != mCallbackList.end(); ) + //trigger loaded callbacks on local textures immediately + LLViewerFetchedTexture* image = *iter++; + if (!image->getUrl().empty()) { - //trigger loaded callbacks on local textures immediately - LLViewerFetchedTexture* image = *iter++; - if (!image->getUrl().empty()) - { - // Do stuff to handle callbacks, update priorities, etc. - didone = image->doLoadedCallbacks(); - } - else if (!didone) - { - // Do stuff to handle callbacks, update priorities, etc. - didone = image->doLoadedCallbacks(); - } + // Do stuff to handle callbacks, update priorities, etc. + didone = image->doLoadedCallbacks(); + } + else if (!didone) + { + // Do stuff to handle callbacks, update priorities, etc. + didone = image->doLoadedCallbacks(); } } + - { - LL_RECORD_BLOCK_TIME(FTM_IMAGE_STATS); - updateImagesUpdateStats(); - } + updateImagesUpdateStats(); } void LLViewerTextureList::clearFetchingRequests() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (LLAppViewer::getTextureFetch()->getNumRequests() == 0) { return; @@ -862,6 +850,7 @@ void LLViewerTextureList::clearFetchingRequests() void LLViewerTextureList::updateImagesDecodePriorities() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // Update the decode priority for N images each frame { F32 lazy_flush_timeout = 30.f; // stop decoding @@ -977,6 +966,7 @@ void LLViewerTextureList::updateImagesDecodePriorities() void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debug_level) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(!tex->setDebugFetching(debug_level)) { return; @@ -1025,6 +1015,7 @@ void LLViewerTextureList::setDebugFetching(LLViewerFetchedTexture* tex, S32 debu F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (gGLManager.mIsDisabled) return 0.0f; // @@ -1041,6 +1032,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) enditer = iter; LLViewerFetchedTexture *imagep = *curiter; imagep->createTexture(); + imagep->postCreateTexture(); if (create_timer.getElapsedTimeF32() > max_time) { break; @@ -1052,6 +1044,7 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (gGLManager.mIsDisabled) return 0.0f; if(mFastCacheList.empty()) { @@ -1082,6 +1075,7 @@ F32 LLViewerTextureList::updateImagesLoadingFastCache(F32 max_time) void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(!imagep) { return ; @@ -1101,6 +1095,7 @@ void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep) F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLTimer image_op_timer; // Update fetch for N images each frame @@ -1176,6 +1171,7 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) void LLViewerTextureList::updateImagesUpdateStats() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (mForceResetTextureStats) { for (image_priority_list_t::iterator iter = mImageList.begin(); @@ -1190,6 +1186,7 @@ void LLViewerTextureList::updateImagesUpdateStats() void LLViewerTextureList::decodeAllImages(F32 max_time) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLTimer timer; //loading from fast cache @@ -1225,6 +1222,7 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) LLViewerFetchedTexture* imagep = *iter++; imagep->updateFetch(); } + std::shared_ptr<LL::WorkQueue> main_queue = LLImageGLThread::sEnabled ? LL::WorkQueue::getInstance("mainloop") : NULL; // Run threads S32 fetch_pending = 0; while (1) @@ -1232,6 +1230,13 @@ void LLViewerTextureList::decodeAllImages(F32 max_time) LLAppViewer::instance()->getTextureCache()->update(1); // unpauses the texture cache thread LLAppViewer::instance()->getImageDecodeThread()->update(1); // unpauses the image thread fetch_pending = LLAppViewer::instance()->getTextureFetch()->update(1); // unpauses the texture fetch thread + + if (LLImageGLThread::sEnabled) + { + main_queue->runFor(std::chrono::milliseconds(1)); + fetch_pending += main_queue->size(); + } + if (fetch_pending == 0 || timer.getElapsedTimeF32() > max_time) { break; @@ -1259,6 +1264,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // Load the image LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec); if (image.isNull()) @@ -1312,6 +1318,7 @@ BOOL LLViewerTextureList::createUploadFile(const std::string& filename, // note: modifies the argument raw_image!!!! LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImageRaw> raw_image) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); LLPointer<LLImageJ2C> compressedImage = new LLImageJ2C(); @@ -1345,6 +1352,7 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage // Returns min setting for TextureMemory (in MB) S32Megabytes LLViewerTextureList::getMinVideoRamSetting() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; U32Megabytes system_ram = gSysMemory.getPhysicalMemoryKB(); //min texture mem sets to 64M if total physical mem is more than 1.5GB return (system_ram > U32Megabytes(1500)) ? S32Megabytes(64) : gMinVideoRam ; @@ -1354,6 +1362,7 @@ S32Megabytes LLViewerTextureList::getMinVideoRamSetting() // Returns max setting for TextureMemory (in MB) S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_multiplier) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; S32Megabytes max_texmem; if (gGLManager.mVRAM != 0) { @@ -1361,7 +1370,7 @@ S32Megabytes LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, fl // - it's going to be swapping constantly regardless S32Megabytes max_vram(gGLManager.mVRAM); - if(gGLManager.mIsATI) + if(gGLManager.mIsAMD) { //shrink the availabe vram for ATI cards because some of them do not handel texture swapping well. max_vram = max_vram * 0.75f; @@ -1434,6 +1443,7 @@ const S32Megabytes VIDEO_CARD_FRAMEBUFFER_MEM(12); const S32Megabytes MIN_MEM_FOR_NON_TEXTURE(512); void LLViewerTextureList::updateMaxResidentTexMem(S32Megabytes mem) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // Initialize the image pipeline VRAM settings S32Megabytes cur_mem(gSavedSettings.getS32("TextureMemory")); F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple"); @@ -1496,8 +1506,8 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d { static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ; - LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES); - + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; + // Receive image header, copy into image object and decompresses // if this is a one-packet image. @@ -1568,7 +1578,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d { static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic", false) ; - LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // Receives image packet, copy into image object, // checks if all packets received, decompresses if so. @@ -1641,7 +1651,7 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d // static void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data) { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_IMAGES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; LLUUID image_id; msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id); @@ -1674,6 +1684,7 @@ void LLUIImageList::cleanUp() LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // use id as image name std::string image_name = image_id.asString(); @@ -1692,6 +1703,7 @@ LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id, S32 priority) LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name, S32 priority) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // look for existing image uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name); if (found_it != mUIImages.end()) @@ -1709,6 +1721,7 @@ LLUIImagePtr LLUIImageList::loadUIImageByName(const std::string& name, const std BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority, LLUIImage::EScaleStyle scale_style) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (boost_priority == LLGLTexture::BOOST_NONE) { boost_priority = LLGLTexture::BOOST_UI; @@ -1721,6 +1734,7 @@ LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLViewerTexture::EBoostLevel boost_priority, LLUIImage::EScaleStyle scale_style) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (boost_priority == LLGLTexture::BOOST_NONE) { boost_priority = LLGLTexture::BOOST_UI; @@ -1732,6 +1746,7 @@ LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id, LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLUIImage::EScaleStyle scale_style) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if (!imagep) return NULL; imagep->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -1769,6 +1784,7 @@ LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const st LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect, const LLRect& clip_rect, LLUIImage::EScaleStyle scale_style) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // look for existing image uuid_ui_image_map_t::iterator found_it = mUIImages.find(name); if (found_it != mUIImages.end()) @@ -1783,6 +1799,7 @@ LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::s //static void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* user_data ) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; if(!success || !user_data) { return; @@ -1884,6 +1901,7 @@ struct UIImageDeclarations : public LLInitParam::Block<UIImageDeclarations> bool LLUIImageList::initFromFile() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; // Look for textures.xml in all the right places. Pass // constraint=LLDir::ALL_SKINS because we want to overlay textures.xml // from all the skins directories. @@ -1958,9 +1976,18 @@ bool LLUIImageList::initFromFile() preloadUIImage(image.name, file_name, image.use_mips, image.scale, image.clip, image.scale_type); } - if (cur_pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload")) + if (!gSavedSettings.getBOOL("NoPreload")) { - gTextureList.decodeAllImages(10.f); // decode preloaded images + if (cur_pass == PASS_DECODE_NOW) + { + // init fetching and decoding of preloaded images + gTextureList.decodeAllImages(9.f); + } + else + { + // decodeAllImages needs two passes to refresh stats and priorities on second pass + gTextureList.decodeAllImages(1.f); + } } } return true; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 9334fa5c76..42e21f7130 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -609,12 +609,6 @@ public: { LLTrace::Recording& last_frame_recording = LLTrace::get_frame_recording().getLastRecording(); - if (gPipeline.getUseVertexShaders() == 0) - { - addText(xpos, ypos, "Shaders Disabled"); - ypos += y_inc; - } - if (gGLManager.mHasATIMemInfo) { S32 meminfo[4]; @@ -1519,8 +1513,15 @@ BOOL LLViewerWindow::handleCloseRequest(LLWindow *window) void LLViewerWindow::handleQuit(LLWindow *window) { - LL_INFOS() << "Window forced quit" << LL_ENDL; - LLAppViewer::instance()->forceQuit(); + if (gNonInteractive) + { + LLAppViewer::instance()->requestQuit(); + } + else + { + LL_INFOS() << "Window forced quit" << LL_ENDL; + LLAppViewer::instance()->forceQuit(); + } } void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height) @@ -1767,6 +1768,7 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data) BOOL LLViewerWindow::handleTimerEvent(LLWindow *window) { + //TODO: just call this every frame from gatherInput instead of using a convoluted 30fps timer callback if (LLViewerJoystick::getInstance()->getOverrideCamera()) { LLViewerJoystick::getInstance()->updateStatus(); @@ -1907,7 +1909,7 @@ LLViewerWindow::LLViewerWindow(const Params& p) p.title, p.name, p.x, p.y, p.width, p.height, 0, p.fullscreen, gHeadlessClient, - gSavedSettings.getBOOL("DisableVerticalSync"), + gSavedSettings.getBOOL("RenderVSyncEnable"), !gHeadlessClient, p.ignore_pixel_depth, gSavedSettings.getBOOL("RenderDeferred") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled @@ -1974,6 +1976,13 @@ LLViewerWindow::LLViewerWindow(const Params& p) } LLFontManager::initClass(); + // Init font system, load default fonts and generate basic glyphs + // currently it takes aprox. 0.5 sec and we would load these fonts anyway + // before login screen. + LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), + mDisplayScale.mV[VX], + mDisplayScale.mV[VY], + gDirUtilp->getAppRODataDir()); // // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off @@ -2015,20 +2024,12 @@ LLViewerWindow::LLViewerWindow(const Params& p) // Init the image list. Must happen after GL is initialized and before the images that // LLViewerWindow needs are requested. - LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ; + LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded")); gTextureList.init(); LLViewerTextureManager::init() ; gBumpImageList.init(); - // Init font system, but don't actually load the fonts yet - // because our window isn't onscreen and they take several - // seconds to parse. - LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), - mDisplayScale.mV[VX], - mDisplayScale.mV[VY], - gDirUtilp->getAppRODataDir()); - - // Create container for all sub-views + // Create container for all sub-views LLView::Params rvp; rvp.name("root"); rvp.rect(mWindowRectScaled); @@ -2058,29 +2059,6 @@ std::string LLViewerWindow::getLastSnapshotDir() void LLViewerWindow::initGLDefaults() { - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - if (!LLGLSLShader::sNoFixedFunction) - { //initialize fixed function state - glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); - - glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,LLColor4::black.mV); - glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,LLColor4::white.mV); - - // lights for objects - glShadeModel( GL_SMOOTH ); - - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } - - glPixelStorei(GL_PACK_ALIGNMENT,1); - glPixelStorei(GL_UNPACK_ALIGNMENT,1); - - gGL.setAmbientLightColor(LLColor4::black); - - glCullFace(GL_BACK); - // RN: Need this for translation and stretch manip. gBox.prerender(); } @@ -2113,6 +2091,8 @@ void LLViewerWindow::initBase() LL_DEBUGS("AppInit") << "initializing edit menu" << LL_ENDL; initialize_edit_menu(); + LLFontGL::loadCommonFonts(); + // Create the floater view at the start so that other views can add children to it. // (But wait to add it as a child of the root view so that it will be in front of the // other views.) @@ -2199,6 +2179,14 @@ void LLViewerWindow::initBase() void LLViewerWindow::initWorldUI() { + if (gNonInteractive) + { + gIMMgr = LLIMMgr::getInstance(); + LLNavigationBar::getInstance(); + gFloaterView->pushVisibleAll(FALSE); + return; + } + S32 height = mRootView->getRect().getHeight(); S32 width = mRootView->getRect().getWidth(); LLRect full_window(0, height, width, 0); @@ -2209,12 +2197,15 @@ void LLViewerWindow::initWorldUI() //getRootView()->sendChildToFront(gFloaterView); //getRootView()->sendChildToFront(gSnapshotFloaterView); - LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container"); - LLChicletBar* chiclet_bar = LLChicletBar::getInstance(); - chiclet_bar->setShape(chiclet_container->getLocalRect()); - chiclet_bar->setFollowsAll(); - chiclet_container->addChild(chiclet_bar); - chiclet_container->setVisible(TRUE); + if (!gNonInteractive) + { + LLPanel* chiclet_container = getRootView()->getChild<LLPanel>("chiclet_container"); + LLChicletBar* chiclet_bar = LLChicletBar::getInstance(); + chiclet_bar->setShape(chiclet_container->getLocalRect()); + chiclet_bar->setFollowsAll(); + chiclet_container->addChild(chiclet_bar); + chiclet_container->setVisible(TRUE); + } LLRect morph_view_rect = full_window; morph_view_rect.stretch( -STATUS_BAR_HEIGHT ); @@ -2306,21 +2297,24 @@ void LLViewerWindow::initWorldUI() gToolBarView->setVisible(TRUE); } - LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents"); - if (destinations) + if (!gNonInteractive) { - destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); - std::string url = gSavedSettings.getString("DestinationGuideURL"); - url = LLWeb::expandURLSubstitutions(url, LLSD()); - destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML); - } - LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents"); - if (avatar_picker) - { - avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); - std::string url = gSavedSettings.getString("AvatarPickerURL"); - url = LLWeb::expandURLSubstitutions(url, LLSD()); - avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML); + LLMediaCtrl* destinations = LLFloaterReg::getInstance("destinations")->getChild<LLMediaCtrl>("destination_guide_contents"); + if (destinations) + { + destinations->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); + std::string url = gSavedSettings.getString("DestinationGuideURL"); + url = LLWeb::expandURLSubstitutions(url, LLSD()); + destinations->navigateTo(url, HTTP_CONTENT_TEXT_HTML); + } + LLMediaCtrl* avatar_picker = LLFloaterReg::getInstance("avatar")->findChild<LLMediaCtrl>("avatar_picker_contents"); + if (avatar_picker) + { + avatar_picker->setErrorPageURL(gSavedSettings.getString("GenericErrorPageURL")); + std::string url = gSavedSettings.getString("AvatarPickerURL"); + url = LLWeb::expandURLSubstitutions(url, LLSD()); + avatar_picker->navigateTo(url, HTTP_CONTENT_TEXT_HTML); + } } } @@ -2426,7 +2420,7 @@ void LLViewerWindow::shutdownGL() LLViewerTextureManager::cleanup() ; SUBSYSTEM_CLEANUP(LLImageGL) ; - + LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ; LL_INFOS() << "Cleaning up select manager" << LL_ENDL; @@ -2564,7 +2558,7 @@ void LLViewerWindow::reshape(S32 width, S32 height) mWindow->setMinSize(min_window_width, min_window_height); LLCoordScreen window_rect; - if (mWindow->getSize(&window_rect)) + if (!gNonInteractive && mWindow->getSize(&window_rect)) { // Only save size if not maximized gSavedSettings.setU32("WindowWidth", window_rect.mX); @@ -2676,10 +2670,7 @@ void LLViewerWindow::drawDebugText() gGL.color4f(1,1,1,1); gGL.pushMatrix(); gGL.pushUIMatrix(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); { // scale view by UI global scale factor and aspect ratio correction factor gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f); @@ -2689,10 +2680,7 @@ void LLViewerWindow::drawDebugText() gGL.popMatrix(); gGL.flush(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } + gUIProgram.unbind(); } void LLViewerWindow::draw() @@ -2738,10 +2726,7 @@ void LLViewerWindow::draw() // Draw all nested UI views. // No translation needed, this view is glued to 0,0 - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); gGL.pushMatrix(); LLUI::pushMatrix(); @@ -2817,14 +2802,9 @@ void LLViewerWindow::draw() LLUI::popMatrix(); gGL.popMatrix(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } + gUIProgram.unbind(); -//#if LL_DEBUG LLView::sIsDrawing = FALSE; -//#endif } // Takes a single keyup event, usually when UI is visible @@ -3355,7 +3335,7 @@ static LLTrace::BlockTimerStatHandle ftm("Update UI"); // event processing. void LLViewerWindow::updateUI() { - LL_RECORD_BLOCK_TIME(ftm); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(ftm); static std::string last_handle_msg; @@ -3801,8 +3781,15 @@ void LLViewerWindow::updateLayout() void LLViewerWindow::updateMouseDelta() { +#if LL_WINDOWS + LLCoordCommon delta; + mWindow->getCursorDelta(&delta); + S32 dx = delta.mX; + S32 dy = delta.mY; +#else S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::getScaleFactor().mV[VX]); S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::getScaleFactor().mV[VY]); +#endif //RN: fix for asynchronous notification of mouse leaving window not working LLCoordWindow mouse_pos; @@ -5399,6 +5386,7 @@ void LLViewerWindow::setup3DRender() void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset; gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset; gGLViewport[2] = mWorldViewRectRaw.getWidth(); @@ -5617,8 +5605,6 @@ void LLViewerWindow::initFonts(F32 zoom_factor) mDisplayScale.mV[VX] * zoom_factor, mDisplayScale.mV[VY] * zoom_factor, gDirUtilp->getAppRODataDir()); - // Force font reloads, which can be very slow - LLFontGL::loadDefaultFonts(); } void LLViewerWindow::requestResolutionUpdate() @@ -5660,7 +5646,7 @@ void LLViewerWindow::restartDisplay(BOOL show_progress_bar) } } -BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar) +BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL enable_vsync, BOOL show_progress_bar) { //BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized"); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 713cc51bf7..979a560508 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -427,7 +427,7 @@ public: void requestResolutionUpdate(); void checkSettings(); void restartDisplay(BOOL show_progress_bar); - BOOL changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar); + BOOL changeDisplaySettings(LLCoordScreen size, BOOL enable_vsync, BOOL show_progress_bar); BOOL getIgnoreDestroyWindow() { return mIgnoreActivate; } F32 getWorldViewAspectRatio() const; const LLVector2& getDisplayScale() const { return mDisplayScale; } diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index c63c5f6b23..46beac8255 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -254,6 +254,7 @@ BOOL LLVLComposition::generateComposition() BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, const F32 width, const F32 height) { + LL_PROFILE_ZONE_SCOPED llassert(mSurfacep); llassert(x >= 0.f); llassert(y >= 0.f); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index d421b3b1f6..cb50390f60 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -111,6 +111,7 @@ #include "llsdserialize.h" #include "llcallstack.h" #include "llrendersphere.h" +#include "llskinningutil.h" #include <boost/lexical_cast.hpp> @@ -126,6 +127,12 @@ const F32 MIN_HOVER_Z = -2.0; const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f; const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f; +// Unlike with 'self' avatar, server doesn't inform viewer about +// expected attachments so viewer has to wait to see if anything +// else will arrive +const F32 FIRST_APPEARANCE_CLOUD_MIN_DELAY = 3.f; // seconds +const F32 FIRST_APPEARANCE_CLOUD_MAX_DELAY = 45.f; + using namespace LLAvatarAppearanceDefines; //----------------------------------------------------------------------------- @@ -328,6 +335,7 @@ public: // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; F32 nx[2]; nx[0]=time*TORSO_NOISE_SPEED; nx[1]=0.0f; @@ -448,6 +456,7 @@ public: // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; mBreatheRate = 1.f; F32 breathe_amt = (sinf(mBreatheRate * time) * BREATHE_ROT_MOTION_STRENGTH); @@ -549,6 +558,7 @@ public: // must return FALSE when the motion is completed. virtual BOOL onUpdate(F32 time, U8* joint_mask) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; mPelvisState->setPosition(LLVector3::zero); return TRUE; @@ -609,6 +619,7 @@ F32 LLVOAvatar::sUnbakedTime = 0.f; F32 LLVOAvatar::sUnbakedUpdateTime = 0.f; F32 LLVOAvatar::sGreyTime = 0.f; F32 LLVOAvatar::sGreyUpdateTime = 0.f; +LLPointer<LLViewerTexture> LLVOAvatar::sCloudTexture = NULL; //----------------------------------------------------------------------------- // Helper functions @@ -664,6 +675,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mVisuallyMuteSetting(AV_RENDER_NORMALLY), mMutedAVColor(LLColor4::white /* used for "uninitialize" */), mFirstFullyVisible(TRUE), + mFirstUseDelaySeconds(FIRST_APPEARANCE_CLOUD_MIN_DELAY), mFullyLoaded(FALSE), mPreviousFullyLoaded(FALSE), mFullyLoadedInitialized(FALSE), @@ -738,7 +750,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mCurrentGesticulationLevel = 0; - + mFirstAppearanceMessageTimer.reset(); mRuthTimer.reset(); mRuthDebugTimer.reset(); mDebugExistenceTimer.reset(); @@ -1125,6 +1137,7 @@ void LLVOAvatar::initClass() LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged); + sCloudTexture = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c"); } @@ -1317,11 +1330,9 @@ void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax) } -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); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; static LLCachedControl<S32> box_detail_cache(gSavedSettings, "AvatarBoundingBoxComplexity"); S32 box_detail = box_detail_cache; @@ -1425,7 +1436,7 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) continue; } LLDrawable* drawable = attached_object->mDrawable; - if (drawable && !drawable->isState(LLDrawable::RIGGED)) + if (drawable && !drawable->isState(LLDrawable::RIGGED | LLDrawable::RIGGED_CHILD)) // <-- don't extend bounding box if any rigged objects are present { LLSpatialBridge* bridge = drawable->getSpatialBridge(); if (bridge) @@ -2491,10 +2502,6 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) return setTETextureCore(te, image); } -static LLTrace::BlockTimerStatHandle FTM_AVATAR_UPDATE("Avatar Update"); -static LLTrace::BlockTimerStatHandle FTM_AVATAR_UPDATE_COMPLEXITY("Avatar Update Complexity"); -static LLTrace::BlockTimerStatHandle FTM_JOINT_UPDATE("Update Joints"); - //------------------------------------------------------------------------ // LLVOAvatar::dumpAnimationState() //------------------------------------------------------------------------ @@ -2527,7 +2534,7 @@ void LLVOAvatar::dumpAnimationState() //------------------------------------------------------------------------ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) { - LL_RECORD_BLOCK_TIME(FTM_AVATAR_UPDATE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (isDead()) { @@ -2564,8 +2571,6 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) // force asynchronous drawable update if(mDrawable.notNull()) { - LL_RECORD_BLOCK_TIME(FTM_JOINT_UPDATE); - if (isSitting() && getParent()) { LLViewerObject *root_object = (LLViewerObject*)getRoot(); @@ -2665,9 +2670,8 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) if ((LLFrameTimer::getFrameCount() + mID.mData[0]) % compl_upd_freq == 0) { - LL_RECORD_BLOCK_TIME(FTM_AVATAR_UPDATE_COMPLEXITY); - idleUpdateRenderComplexity(); -} + idleUpdateRenderComplexity(); + } idleUpdateDebugInfo(); } @@ -2781,10 +2785,17 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) }//if ( voiceEnabled ) } -static LLTrace::BlockTimerStatHandle FTM_ATTACHMENT_UPDATE("Update Attachments"); +static void override_bbox(LLDrawable* drawable, LLVector4a* extents) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_SPATIAL; + drawable->setSpatialExtents(extents[0], extents[1]); + drawable->setPositionGroup(LLVector4a(0, 0, 0)); + drawable->movePartition(); +} void LLVOAvatar::idleUpdateMisc(bool detailed_update) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (LLVOAvatar::sJointDebug) { LL_INFOS() << getFullname() << ": joint touches: " << LLJoint::sNumTouches << " updates: " << LLJoint::sNumUpdates << LL_ENDL; @@ -2798,7 +2809,6 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) // update attachments positions if (detailed_update) { - LL_RECORD_BLOCK_TIME(FTM_ATTACHMENT_UPDATE); for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter) @@ -2810,27 +2820,52 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) ++attachment_iter) { LLViewerObject* attached_object = attachment_iter->get(); - BOOL visibleAttachment = visible || (attached_object && + BOOL visibleAttachment = visible || (attached_object && attached_object->mDrawable.notNull() && !(attached_object->mDrawable->getSpatialBridge() && attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); - if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) + if (visibleAttachment + && attached_object + && !attached_object->isDead() + && attachment->getValid() + && attached_object->mDrawable.notNull()) { - // if selecting any attachments, update all of them as non-damped - if (LLSelectMgr::getInstance()->getSelection()->getObjectCount() && LLSelectMgr::getInstance()->getSelection()->isAttachment()) - { - gPipeline.updateMoveNormalAsync(attached_object->mDrawable); - } - else - { - gPipeline.updateMoveDampedAsync(attached_object->mDrawable); - } - - LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge(); - if (bridge) - { - gPipeline.updateMoveNormalAsync(bridge); - } + + //override rigged attachments' octree spatial extents with this avatar's bounding box + LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge(); + bool rigged = false; + if (bridge && !bridge->isDead()) + { + //transform avatar bounding box into attachment's coordinate frame + LLVector4a extents[2]; + bridge->transformExtents(mDrawable->getSpatialExtents(), extents); + + if (attached_object->mDrawable->isState(LLDrawable::RIGGED | LLDrawable::RIGGED_CHILD)) + { + rigged = true; + override_bbox(attached_object->mDrawable, extents); + } + } + + + attached_object->mDrawable->makeActive(); + attached_object->mDrawable->updateXform(TRUE); + + if (bridge && !bridge->isDead()) + { + if (!rigged) + { + gPipeline.updateMoveNormalAsync(bridge); + } + else + { + //specialized impl of updateMoveNormalAsync just for rigged attachment SpatialBridge + bridge->setState(LLDrawable::MOVE_UNDAMPED); + bridge->updateMove(); + bridge->setState(LLDrawable::EARLY_MOVE); + } + } + attached_object->updateText(); } } @@ -3054,8 +3089,7 @@ void LLVOAvatar::idleUpdateLoadingEffect() particle_parameters.mPartData.mStartColor = LLColor4(1, 1, 1, 0.5f); particle_parameters.mPartData.mEndColor = LLColor4(1, 1, 1, 0.0f); particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; - LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c"); - particle_parameters.mPartImageID = cloud->getID(); + particle_parameters.mPartImageID = sCloudTexture->getID(); particle_parameters.mMaxAge = 0.f; particle_parameters.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE; particle_parameters.mInnerAngle = F_PI; @@ -3138,6 +3172,8 @@ void LLVOAvatar::idleUpdateWindEffect() void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + // update chat bubble //-------------------------------------------------------------------- // draw text label over character's head @@ -4891,6 +4927,8 @@ bool LLVOAvatar::shouldAlphaMask() //----------------------------------------------------------------------------- U32 LLVOAvatar::renderSkinned() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + U32 num_indices = 0; if (!mIsBuilt) @@ -5059,11 +5097,6 @@ U32 LLVOAvatar::renderSkinned() bool should_alpha_mask = shouldAlphaMask(); LLGLState test(GL_ALPHA_TEST, should_alpha_mask); - if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction) - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); - } - BOOL first_pass = TRUE; if (!LLDrawPoolAvatar::sSkipOpaque) { @@ -5110,11 +5143,6 @@ U32 LLVOAvatar::renderSkinned() } } - if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction) - { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - } - if (!LLDrawPoolAvatar::sSkipTransparent || LLPipeline::sImpostorRender) { LLGLState blend(GL_BLEND, !mIsDummy); @@ -5130,21 +5158,21 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) U32 num_indices = 0; if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (isUIAvatar() || isTextureVisible(TEX_SKIRT_BAKED)) ) { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f); + gGL.flush(); LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT); if (skirt_mesh) { num_indices += skirt_mesh->render(mAdjustedPixelArea, FALSE); } first_pass = FALSE; - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.flush(); } if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { if (LLPipeline::sImpostorRender) { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); + gGL.flush(); } if (isTextureVisible(TEX_HEAD_BAKED)) @@ -5167,7 +5195,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) } if (LLPipeline::sImpostorRender) { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.flush(); } } @@ -5199,11 +5227,6 @@ U32 LLVOAvatar::renderRigid() bool should_alpha_mask = shouldAlphaMask(); LLGLState test(GL_ALPHA_TEST, should_alpha_mask); - if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction) - { - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); - } - if (isTextureVisible(TEX_EYES_BAKED) || (getOverallAppearance() == AOA_JELLYDOLL && !isControlAvatar()) || isUIAvatar()) { LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT); @@ -5218,11 +5241,6 @@ U32 LLVOAvatar::renderRigid() } } - if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction) - { - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); - } - return num_indices; } @@ -5273,7 +5291,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel) } { LLGLEnable test(GL_ALPHA_TEST); - gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f); + gGL.flush(); gGL.color4ubv(color.mV); gGL.getTexUnit(diffuse_channel)->bind(&mImpostor); @@ -6166,27 +6184,29 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name ) LLJoint *LLVOAvatar::getJoint( S32 joint_num ) { LLJoint *pJoint = NULL; - S32 collision_start = mNumBones; - S32 attachment_start = mNumBones + mNumCollisionVolumes; - if (joint_num>=attachment_start) + if (joint_num >= 0) { - // Attachment IDs start at 1 - S32 attachment_id = joint_num - attachment_start + 1; - attachment_map_t::iterator iter = mAttachmentPoints.find(attachment_id); - if (iter != mAttachmentPoints.end()) + if (joint_num < mNumBones) { - pJoint = iter->second; + pJoint = mSkeleton[joint_num]; + } + else if (joint_num < mNumBones + mNumCollisionVolumes) + { + S32 collision_id = joint_num - mNumBones; + pJoint = &mCollisionVolumes[collision_id]; + } + else + { + // Attachment IDs start at 1 + S32 attachment_id = joint_num - (mNumBones + mNumCollisionVolumes) + 1; + attachment_map_t::iterator iter = mAttachmentPoints.find(attachment_id); + if (iter != mAttachmentPoints.end()) + { + pJoint = iter->second; + } } } - else if (joint_num>=collision_start) - { - S32 collision_id = joint_num-collision_start; - pJoint = &mCollisionVolumes[collision_id]; - } - else if (joint_num>=0) - { - pJoint = mSkeleton[joint_num]; - } + llassert(!pJoint || pJoint->getJointNum() == joint_num); return pJoint; } @@ -6431,6 +6451,16 @@ void LLVOAvatar::updateAttachmentOverrides() #endif } +void LLVOAvatar::notifyAttachmentMeshLoaded() +{ + if (!isFullyLoaded()) + { + // We just received mesh or skin info + // Reset timer to wait for more potential meshes or changes + mFullyLoadedTimer.reset(); + } +} + //----------------------------------------------------------------------------- // addAttachmentOverridesForObject //----------------------------------------------------------------------------- @@ -6521,7 +6551,7 @@ void LLVOAvatar::addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LL LLJoint* pJoint = getJoint( lookingForJoint ); if (pJoint) { - const LLVector3& jointPos = pSkinData->mAlternateBindMatrix[i].getTranslation(); + const LLVector3& jointPos = LLVector3(pSkinData->mAlternateBindMatrix[i].getTranslation()); if (pJoint->aboveJointPosThreshold(jointPos)) { bool override_changed; @@ -7125,6 +7155,7 @@ void LLVOAvatar::updateGL() { if (mMeshTexturesDirty) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR updateMeshTextures(); mMeshTexturesDirty = FALSE; } @@ -7133,10 +7164,9 @@ void LLVOAvatar::updateGL() //----------------------------------------------------------------------------- // updateGeometry() //----------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_UPDATE_AVATAR("Update Avatar"); BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_AVATAR); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR))) { return TRUE; @@ -7870,6 +7900,8 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) // Do rigged mesh attachments display with this av? bool LLVOAvatar::shouldRenderRigged() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + if (getOverallAppearance() == AOA_NORMAL) { return true; @@ -8134,16 +8166,35 @@ void LLVOAvatar::updateRuthTimer(bool loading) BOOL LLVOAvatar::processFullyLoadedChange(bool loading) { // We wait a little bit before giving the 'all clear', to let things to - // settle down (models to snap into place, textures to get first packets) + // settle down (models to snap into place, textures to get first packets). + // And if viewer isn't aware of some parts yet, this gives them a chance + // to arrive. const F32 LOADED_DELAY = 1.f; - const F32 FIRST_USE_DELAY = 3.f; - if (loading) - mFullyLoadedTimer.reset(); + if (loading) + { + mFullyLoadedTimer.reset(); + } if (mFirstFullyVisible) { - mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > FIRST_USE_DELAY); + if (!isSelf() && loading) + { + // Note that textures can causes 60s delay on thier own + // so this delay might end up on top of textures' delay + mFirstUseDelaySeconds = llclamp( + mFirstAppearanceMessageTimer.getElapsedTimeF32(), + FIRST_APPEARANCE_CLOUD_MIN_DELAY, + FIRST_APPEARANCE_CLOUD_MAX_DELAY); + + if (shouldImpostor()) + { + // Impostors are less of a priority, + // let them stay cloud longer + mFirstUseDelaySeconds *= 1.25; + } + } + mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > mFirstUseDelaySeconds); } else { @@ -8362,6 +8413,7 @@ void LLVOAvatar::updateMeshVisibility() // virtual void LLVOAvatar::updateMeshTextures() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR static S32 update_counter = 0; mBakedTextureDebugText.clear(); @@ -8902,6 +8954,9 @@ void LLVOAvatar::onFirstTEMessageReceived() mMeshTexturesDirty = TRUE; gPipeline.markGLRebuild(this); + + mFirstAppearanceMessageTimer.reset(); + mFullyLoadedTimer.reset(); } } @@ -9433,6 +9488,54 @@ LLViewerTexture* LLVOAvatar::getBakedTexture(const U8 te) } +const LLVOAvatar::MatrixPaletteCache& LLVOAvatar::updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skin) +{ + U64 hash = skin->mHash; + MatrixPaletteCache& entry = mMatrixPaletteCache[hash]; + + if (entry.mFrame != gFrameCount) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + + entry.mFrame = gFrameCount; + + //build matrix palette + U32 count = LLSkinningUtil::getMeshJointCount(skin); + entry.mMatrixPalette.resize(count); + LLSkinningUtil::initSkinningMatrixPalette(&(entry.mMatrixPalette[0]), count, skin, this); + + const LLMatrix4a* mat = &(entry.mMatrixPalette[0]); + + entry.mGLMp.resize(count * 12); + + F32* mp = &(entry.mGLMp[0]); + + for (U32 i = 0; i < count; ++i) + { + F32* m = (F32*)mat[i].mMatrix[0].getF32ptr(); + + U32 idx = i * 12; + + mp[idx + 0] = m[0]; + mp[idx + 1] = m[1]; + mp[idx + 2] = m[2]; + mp[idx + 3] = m[12]; + + mp[idx + 4] = m[4]; + mp[idx + 5] = m[5]; + mp[idx + 6] = m[6]; + mp[idx + 7] = m[13]; + + mp[idx + 8] = m[8]; + mp[idx + 9] = m[9]; + mp[idx + 10] = m[10]; + mp[idx + 11] = m[14]; + } + } + + return entry; +} + // static void LLVOAvatar::getAnimLabels( std::vector<std::string>* labels ) { @@ -10196,6 +10299,7 @@ void showRigInfoTabExtents(LLVOAvatar *avatar, LLJointRiggingInfoTab& tab, S32& void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; for ( LLVOAvatar::attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ++iter ) { LLViewerJointAttachment* attachment = iter->second; @@ -10253,27 +10357,19 @@ void LLVOAvatar::getAssociatedVolumes(std::vector<LLVOVolume*>& volumes) } } -static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_INFO_UPDATE("Av Upd Rig Info"); -static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_KEY_UPDATE("Av Upd Rig Key"); -static LLTrace::BlockTimerStatHandle FTM_AVATAR_RIGGING_AVOL_UPDATE("Av Upd Avol"); - // virtual void LLVOAvatar::updateRiggingInfo() { - LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_INFO_UPDATE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; LL_DEBUGS("RigSpammish") << getFullname() << " updating rig tab" << LL_ENDL; std::vector<LLVOVolume*> volumes; - { - LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_AVOL_UPDATE); - getAssociatedVolumes(volumes); - } + getAssociatedVolumes(volumes); std::map<LLUUID,S32> curr_rigging_info_key; { - LL_RECORD_BLOCK_TIME(FTM_AVATAR_RIGGING_KEY_UPDATE); // Get current rigging info key for (std::vector<LLVOVolume*>::iterator it = volumes.begin(); it != volumes.end(); ++it) { @@ -10435,6 +10531,7 @@ void LLVOAvatar::updateImpostorRendering(U32 newMaxNonImpostorsValue) void LLVOAvatar::idleUpdateRenderComplexity() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (isControlAvatar()) { LLControlAvatar *cav = dynamic_cast<LLControlAvatar*>(this); @@ -10962,6 +11059,7 @@ void LLVOAvatar::updateOverallAppearanceAnimations() // Based on isVisuallyMuted(), but has 3 possible results. LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; AvatarOverallAppearance result = AOA_NORMAL; // Priority order (highest priority first) diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 96a8372188..3c3decaad6 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -53,6 +53,7 @@ #include "llviewerstats.h" #include "llvovolume.h" #include "llavatarrendernotifier.h" +#include "llmodel.h" extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; @@ -77,6 +78,7 @@ class LLViewerJointMesh; const F32 MAX_AVATAR_LOD_FACTOR = 1.0f; +extern U32 gFrameCount; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // LLVOAvatar @@ -87,6 +89,7 @@ class LLVOAvatar : public LLViewerObject, public boost::signals2::trackable { + LL_ALIGN_NEW; LOG_CLASS(LLVOAvatar); public: @@ -99,16 +102,6 @@ public: **/ public: - void* operator new(size_t size) - { - return LLTrace::MemTrackable<LLViewerObject>::aligned_new<16>(size); - } - - void operator delete(void* ptr, size_t size) - { - LLTrace::MemTrackable<LLViewerObject>::aligned_delete<16>(ptr, size); - } - LLVOAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); virtual void markDead(); static void initClass(); // Initialize data that's only init'd once per class. @@ -209,6 +202,11 @@ public: virtual LLJoint* getJoint(const std::string &name); LLJoint* getJoint(S32 num); + //if you KNOW joint_num is a valid animated joint index, use getSkeletonJoint for efficiency + inline LLJoint* getSkeletonJoint(S32 joint_num) { return mSkeleton[joint_num]; } + inline size_t getSkeletonJointCount() const { return mSkeleton.size(); } + + void notifyAttachmentMeshLoaded(); void addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen = NULL, bool recursive = true); void removeAttachmentOverridesForObject(const LLUUID& mesh_id); void removeAttachmentOverridesForObject(LLViewerObject *vo); @@ -338,7 +336,8 @@ public: static F32 sLODFactor; // user-settable LOD factor static F32 sPhysicsLODFactor; // user-settable physics LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar - static BOOL sDebugAvatarRotation; + + static LLPointer<LLViewerTexture> sCloudTexture; //-------------------------------------------------------------------- // Region state @@ -380,6 +379,9 @@ protected: private: BOOL mFirstFullyVisible; + F32 mFirstUseDelaySeconds; + LLFrameTimer mFirstAppearanceMessageTimer; + BOOL mFullyLoaded; BOOL mPreviousFullyLoaded; BOOL mFullyLoadedInitialized; @@ -747,6 +749,34 @@ public: void updateMeshVisibility(); LLViewerTexture* getBakedTexture(const U8 te); + // Matrix palette cache entry + class alignas(16) MatrixPaletteCache + { + public: + // Last frame this entry was updated + U32 mFrame; + + // List of Matrix4a's for this entry + LLMeshSkinInfo::matrix_list_t mMatrixPalette; + + // Float array ready to be sent to GL + std::vector<F32> mGLMp; + + MatrixPaletteCache() : + mFrame(gFrameCount - 1) + { + } + }; + + // Accessor for Matrix Palette Cache + // Will do a map lookup for the entry associated with the given MeshSkinInfo + // Will update said entry if it hasn't been updated yet this frame + const MatrixPaletteCache& updateSkinInfoMatrixPalette(const LLMeshSkinInfo* skinInfo); + + // Map of LLMeshSkinInfo::mHash to MatrixPaletteCache + typedef std::unordered_map<U64, MatrixPaletteCache> matrix_palette_cache_t; + matrix_palette_cache_t mMatrixPaletteCache; + protected: void releaseMeshData(); virtual void restoreMeshData(); diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp index 5ebc65405f..e10a9f9bcb 100644 --- a/indra/newview/llvocache.cpp +++ b/indra/newview/llvocache.cpp @@ -63,8 +63,7 @@ BOOL check_write(LLAPRFile* apr_file, void* src, S32 n_bytes) //--------------------------------------------------------------------------- LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer &dp) -: LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"), - LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), +: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), mLocalID(local_id), mCRC(crc), mUpdateFlags(-1), @@ -83,8 +82,7 @@ LLVOCacheEntry::LLVOCacheEntry(U32 local_id, U32 crc, LLDataPackerBinaryBuffer & } LLVOCacheEntry::LLVOCacheEntry() -: LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"), - LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), +: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), mLocalID(0), mCRC(0), mUpdateFlags(-1), @@ -102,8 +100,7 @@ LLVOCacheEntry::LLVOCacheEntry() } LLVOCacheEntry::LLVOCacheEntry(LLAPRFile* apr_file) -: LLTrace::MemTrackable<LLVOCacheEntry, 16>("LLVOCacheEntry"), - LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), +: LLViewerOctreeEntryData(LLViewerOctreeEntry::LLVOCACHEENTRY), mBuffer(NULL), mUpdateFlags(-1), mState(INACTIVE), @@ -619,7 +616,6 @@ void LLVOCacheGroup::handleChildAddition(const OctreeNode* parent, OctreeNode* c } LLVOCachePartition::LLVOCachePartition(LLViewerRegion* regionp) -: LLTrace::MemTrackable<LLVOCachePartition>("LLVOCachePartition") { mLODPeriod = 16; mRegionp = regionp; diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h index dd6afd6b85..c510ff77fc 100644 --- a/indra/newview/llvocache.h +++ b/indra/newview/llvocache.h @@ -38,9 +38,9 @@ class LLCamera; class LLVOCacheEntry -: public LLViewerOctreeEntryData, - public LLTrace::MemTrackable<LLVOCacheEntry, 16> +: public LLViewerOctreeEntryData { + LL_ALIGN_NEW public: enum { @@ -185,7 +185,7 @@ protected: virtual ~LLVOCacheGroup(); }; -class LLVOCachePartition : public LLViewerOctreePartition, public LLTrace::MemTrackable<LLVOCachePartition> +class LLVOCachePartition : public LLViewerOctreePartition { public: LLVOCachePartition(LLViewerRegion* regionp); diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index 345e87eea8..9a41eedb54 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -661,11 +661,9 @@ void LLGrassPartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_count } } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_GRASS_VB("Grass VB"); - void LLGrassPartition::getGeometry(LLSpatialGroup* group) { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_GRASS_VB); + LL_PROFILE_ZONE_SCOPED; std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 7a034022ea..19036a3f77 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -5584,7 +5584,9 @@ void LLVivoxVoiceClient::setVoiceEnabled(bool enabled) bool LLVivoxVoiceClient::voiceEnabled() { - return gSavedSettings.getBOOL("EnableVoiceChat") && !gSavedSettings.getBOOL("CmdLineDisableVoice"); + return gSavedSettings.getBOOL("EnableVoiceChat") && + !gSavedSettings.getBOOL("CmdLineDisableVoice") && + !gNonInteractive; } void LLVivoxVoiceClient::setLipSyncEnabled(BOOL enabled) diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index b31afca61d..068e8a131d 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -306,10 +306,9 @@ LLVector3 LLVOPartGroup::getCameraPosition() const return gAgentCamera.getCameraPositionAgent(); } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_PARTICLES("Update Particles"); BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_PARTICLES); + LL_PROFILE_ZONE_SCOPED; dirtySpatialGroup(); @@ -754,10 +753,9 @@ LLHUDParticlePartition::LLHUDParticlePartition(LLViewerRegion* regionp) : mPartitionType = LLViewerRegion::PARTITION_HUD_PARTICLE; } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_PARTICLE_VBO("Particle VBO"); - void LLParticlePartition::rebuildGeom(LLSpatialGroup* group) { + LL_PROFILE_ZONE_SCOPED; if (group->isDead() || !group->hasState(LLSpatialGroup::GEOM_DIRTY)) { return; @@ -769,8 +767,6 @@ void LLParticlePartition::rebuildGeom(LLSpatialGroup* group) group->mLastUpdateViewAngle = group->mViewAngle; } - LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_VBO); - group->clearDrawMap(); //get geometry count @@ -843,11 +839,9 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_PARTICLE_GEOM("Particle Geom"); - void LLParticlePartition::getGeometry(LLSpatialGroup* group) { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_GEOM); + LL_PROFILE_ZONE_SCOPED; std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index 878d7287ed..01312d65cc 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llvosky.cpp * @brief LLVOSky class implementation * * $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$ */ @@ -64,7 +64,9 @@ namespace const S32 NUM_TILES_X = 8; const S32 NUM_TILES_Y = 4; const S32 NUM_TILES = NUM_TILES_X * NUM_TILES_Y; - const S32 NUM_CUBEMAP_FACES = 6; + const S32 NUM_CUBEMAP_FACES = 6; // See SKYTEX_RESOLUTION for face dimensions + const S32 TOTAL_TILES = NUM_CUBEMAP_FACES * NUM_TILES; + const S32 MAX_TILES = TOTAL_TILES + 1; // Heavenly body constants const F32 SUN_DISK_RADIUS = 0.5f; @@ -77,11 +79,6 @@ namespace const LLVector2 TEX10 = LLVector2(1.f, 0.f); const LLVector2 TEX11 = LLVector2(1.f, 1.f); - LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATETIMER("VOSky Update Timer Tick"); - LLTrace::BlockTimerStatHandle FTM_VOSKY_CALC("VOSky Update Calculations"); - LLTrace::BlockTimerStatHandle FTM_VOSKY_CREATETEXTURES("VOSky Update Textures"); - LLTrace::BlockTimerStatHandle FTM_VOSKY_UPDATEFORCED("VOSky Update Forced"); - F32Seconds UPDATE_EXPRY(0.25f); const F32 UPDATE_MIN_DELTA_THRESHOLD = 0.0005f; @@ -90,8 +87,6 @@ namespace SkyTex ***************************************/ -S32 LLSkyTex::sComponents = 4; -S32 LLSkyTex::sResolution = 64; S32 LLSkyTex::sCurrent = 0; @@ -105,15 +100,15 @@ LLSkyTex::LLSkyTex() : void LLSkyTex::init(bool isShiny) { mIsShiny = isShiny; - mSkyData = new LLColor4[sResolution * sResolution]; - mSkyDirs = new LLVector3[sResolution * sResolution]; + mSkyData = new LLColor4[SKYTEX_RESOLUTION * SKYTEX_RESOLUTION]; + mSkyDirs = new LLVector3[SKYTEX_RESOLUTION * SKYTEX_RESOLUTION]; for (S32 i = 0; i < 2; ++i) { mTexture[i] = LLViewerTextureManager::getLocalTexture(FALSE); mTexture[i]->setAddressMode(LLTexUnit::TAM_CLAMP); - mImageRaw[i] = new LLImageRaw(sResolution, sResolution, sComponents); - + mImageRaw[i] = new LLImageRaw(SKYTEX_RESOLUTION, SKYTEX_RESOLUTION, SKYTEX_COMPONENTS); + initEmpty(i); } } @@ -144,7 +139,7 @@ LLSkyTex::~LLSkyTex() S32 LLSkyTex::getResolution() { - return sResolution; + return SKYTEX_RESOLUTION; } S32 LLSkyTex::getCurrent() @@ -172,12 +167,12 @@ S32 LLSkyTex::getWhich(const BOOL curr) void LLSkyTex::initEmpty(const S32 tex) { U8* data = mImageRaw[tex]->getData(); - for (S32 i = 0; i < sResolution; ++i) + for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i) { - for (S32 j = 0; j < sResolution; ++j) + for (S32 j = 0; j < SKYTEX_RESOLUTION; ++j) { - const S32 basic_offset = (i * sResolution + j); - S32 offset = basic_offset * sComponents; + const S32 basic_offset = (i * SKYTEX_RESOLUTION + j); + S32 offset = basic_offset * SKYTEX_COMPONENTS; data[offset] = 0; data[offset+1] = 0; data[offset+2] = 0; @@ -193,12 +188,12 @@ void LLSkyTex::initEmpty(const S32 tex) void LLSkyTex::create() { U8* data = mImageRaw[sCurrent]->getData(); - for (S32 i = 0; i < sResolution; ++i) + for (S32 i = 0; i < SKYTEX_RESOLUTION; ++i) { - for (S32 j = 0; j < sResolution; ++j) + for (S32 j = 0; j < SKYTEX_RESOLUTION; ++j) { - const S32 basic_offset = (i * sResolution + j); - S32 offset = basic_offset * sComponents; + const S32 basic_offset = (i * SKYTEX_RESOLUTION + j); + S32 offset = basic_offset * SKYTEX_COMPONENTS; U32* pix = (U32*)(data + offset); LLColor4U temp = LLColor4U(mSkyData[basic_offset]); *pix = temp.asRGBA(); @@ -208,7 +203,7 @@ void LLSkyTex::create() } void LLSkyTex::createGLImage(S32 which) -{ +{ mTexture[which]->setExplicitFormat(GL_RGBA8, GL_RGBA); mTexture[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLGLTexture::LOCAL); mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -395,10 +390,8 @@ const LLVector3* LLHeavenBody::corners() const Sky ***************************************/ - -S32 LLVOSky::sResolution = LLSkyTex::getResolution(); -S32 LLVOSky::sTileResX = sResolution/NUM_TILES_X; -S32 LLVOSky::sTileResY = sResolution/NUM_TILES_Y; +const S32 SKYTEX_TILE_RES_X = SKYTEX_RESOLUTION / NUM_TILES_X; +const S32 SKYTEX_TILE_RES_Y = SKYTEX_RESOLUTION / NUM_TILES_Y; LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLStaticViewerObject(id, pcode, regionp, TRUE), @@ -433,7 +426,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) { mFace[i] = NULL; } - + mCameraPosAgent = gAgentCamera.getCameraPositionAgent(); mAtmHeight = ATM_HEIGHT; mEarthCenter = LLVector3(mCameraPosAgent.mV[0], mCameraPosAgent.mV[1], -EARTH_RADIUS); @@ -461,30 +454,12 @@ void LLVOSky::init() llassert(!mInitialized); // Update sky at least once to get correct initial sun/moon directions and lighting calcs performed - LLEnvironment::instance().getCurrentSky()->update(); - - updateDirections(); - LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + psky->update(); - // invariants across whole sky tex process... - m_atmosphericsVars.blue_density = psky->getBlueDensity(); - m_atmosphericsVars.blue_horizon = psky->getBlueHorizon(); - m_atmosphericsVars.haze_density = psky->getHazeDensity(); - m_atmosphericsVars.haze_horizon = psky->getHazeHorizon(); - m_atmosphericsVars.density_multiplier = psky->getDensityMultiplier(); - m_atmosphericsVars.max_y = psky->getMaxY(); - m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm(); - m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor(); - m_atmosphericsVars.ambient = psky->getAmbientColor(); - m_atmosphericsVars.glow = psky->getGlow(); - m_atmosphericsVars.cloud_shadow = psky->getCloudShadow(); - m_atmosphericsVars.dome_radius = psky->getDomeRadius(); - m_atmosphericsVars.dome_offset = psky->getDomeOffset(); - m_atmosphericsVars.light_atten = psky->getLightAttenuation(m_atmosphericsVars.max_y); - m_atmosphericsVars.light_transmittance = psky->getLightTransmittance(m_atmosphericsVars.max_y); - m_atmosphericsVars.total_density = psky->getTotalDensity(); - m_atmosphericsVars.gamma = psky->getGamma(); + updateDirections(psky); + + cacheEnvironment(psky,m_atmosphericsVars); // Initialize the cached normalized direction vectors for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side) @@ -492,7 +467,7 @@ void LLVOSky::init() for (S32 tile = 0; tile < NUM_TILES; ++tile) { initSkyTextureDirs(side, tile); - createSkyTexture(m_atmosphericsVars, side, tile); + createSkyTexture(psky, m_atmosphericsVars, side, tile); } mSkyTex[side].create(); mShinyTex[side].create(); @@ -509,28 +484,35 @@ void LLVOSky::init() } +void LLVOSky::cacheEnvironment(LLSettingsSky::ptr_t psky,AtmosphericsVars& atmosphericsVars) +{ + // NOTE: Also see: LLAtmospherics::updateFog() + // invariants across whole sky tex process... + atmosphericsVars.blue_density = psky->getBlueDensity(); + atmosphericsVars.blue_horizon = psky->getBlueHorizon(); + atmosphericsVars.haze_density = psky->getHazeDensity(); + atmosphericsVars.haze_horizon = psky->getHazeHorizon(); + atmosphericsVars.density_multiplier = psky->getDensityMultiplier(); + atmosphericsVars.distance_multiplier = psky->getDistanceMultiplier(); + atmosphericsVars.max_y = psky->getMaxY(); + atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm(); + atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor(); + atmosphericsVars.ambient = psky->getAmbientColor(); + atmosphericsVars.glow = psky->getGlow(); + atmosphericsVars.cloud_shadow = psky->getCloudShadow(); + atmosphericsVars.dome_radius = psky->getDomeRadius(); + atmosphericsVars.dome_offset = psky->getDomeOffset(); + atmosphericsVars.light_atten = psky->getLightAttenuation(atmosphericsVars.max_y); + atmosphericsVars.light_transmittance = psky->getLightTransmittance(atmosphericsVars.max_y); + atmosphericsVars.total_density = psky->getTotalDensity(); + atmosphericsVars.gamma = psky->getGamma(); +} + void LLVOSky::calc() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - - // invariants across whole sky tex process... - m_atmosphericsVars.blue_density = psky->getBlueDensity(); - m_atmosphericsVars.blue_horizon = psky->getBlueHorizon(); - m_atmosphericsVars.haze_density = psky->getHazeDensity(); - m_atmosphericsVars.haze_horizon = psky->getHazeHorizon(); - m_atmosphericsVars.density_multiplier = psky->getDensityMultiplier(); - m_atmosphericsVars.distance_multiplier = psky->getDistanceMultiplier(); - m_atmosphericsVars.max_y = psky->getMaxY(); - m_atmosphericsVars.sun_norm = LLEnvironment::instance().getClampedSunNorm(); - m_atmosphericsVars.sunlight = psky->getIsSunUp() ? psky->getSunlightColor() : psky->getMoonlightColor(); - m_atmosphericsVars.ambient = psky->getAmbientColor(); - m_atmosphericsVars.glow = psky->getGlow(); - m_atmosphericsVars.cloud_shadow = psky->getCloudShadow(); - m_atmosphericsVars.dome_radius = psky->getDomeRadius(); - m_atmosphericsVars.dome_offset = psky->getDomeOffset(); - m_atmosphericsVars.light_atten = psky->getLightAttenuation(m_atmosphericsVars.max_y); - m_atmosphericsVars.light_transmittance = psky->getLightTransmittance(m_atmosphericsVars.max_y); - m_atmosphericsVars.gamma = psky->getGamma(); + cacheEnvironment(psky,m_atmosphericsVars); mSun.setColor(psky->getSunDiffuse()); mMoon.setColor(LLColor3(1.0f, 1.0f, 1.0f)); @@ -541,14 +523,14 @@ void LLVOSky::calc() mMoon.renewColor(); } -void LLVOSky::initCubeMap() +void LLVOSky::initCubeMap() { std::vector<LLPointer<LLImageRaw> > images; for (S32 side = 0; side < NUM_CUBEMAP_FACES; side++) { images.push_back(mShinyTex[side].getImageRaw()); } - + if (!mCubeMap && gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) { mCubeMap = new LLCubeMap(false); @@ -592,12 +574,12 @@ void LLVOSky::restoreGL() setMoonTextures(psky->getMoonTextureId(), psky->getNextMoonTextureId()); } - updateDirections(); + updateDirections(psky); if (gSavedSettings.getBOOL("RenderWater") && gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps) - { + { initCubeMap(); - } + } forceSkyUpdate(); @@ -613,8 +595,8 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile) S32 tile_x = tile % NUM_TILES_X; S32 tile_y = tile / NUM_TILES_X; - S32 tile_x_pos = tile_x * sTileResX; - S32 tile_y_pos = tile_y * sTileResY; + S32 tile_x_pos = tile_x * SKYTEX_TILE_RES_X; + S32 tile_y_pos = tile_y * SKYTEX_TILE_RES_Y; F32 coeff[3] = {0, 0, 0}; const S32 curr_coef = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X @@ -624,11 +606,11 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile) coeff[curr_coef] = (F32)side_dir; - F32 inv_res = 1.f/sResolution; + F32 inv_res = 1.f/SKYTEX_RESOLUTION; S32 x, y; - for (y = tile_y_pos; y < (tile_y_pos + sTileResY); ++y) + for (y = tile_y_pos; y < (tile_y_pos + SKYTEX_TILE_RES_Y); ++y) { - for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x) + for (x = tile_x_pos; x < (tile_x_pos + SKYTEX_TILE_RES_X); ++x) { coeff[x_coef] = F32((x<<1) + 1) * inv_res - 1.f; coeff[y_coef] = F32((y<<1) + 1) * inv_res - 1.f; @@ -640,37 +622,35 @@ void LLVOSky::initSkyTextureDirs(const S32 side, const S32 tile) } } -void LLVOSky::createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile) +void LLVOSky::createSkyTexture(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const S32 side, const S32 tile) { - LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + const bool low_end = !gPipeline.canUseWindLightShaders(); S32 tile_x = tile % NUM_TILES_X; S32 tile_y = tile / NUM_TILES_X; - S32 tile_x_pos = tile_x * sTileResX; - S32 tile_y_pos = tile_y * sTileResY; + S32 tile_x_pos = tile_x * SKYTEX_TILE_RES_X; + S32 tile_y_pos = tile_y * SKYTEX_TILE_RES_Y; S32 x, y; - for (y = tile_y_pos; y < (tile_y_pos + sTileResY); ++y) + for (y = tile_y_pos; y < (tile_y_pos + SKYTEX_TILE_RES_Y); ++y) { - for (x = tile_x_pos; x < (tile_x_pos + sTileResX); ++x) + for (x = tile_x_pos; x < (tile_x_pos + SKYTEX_TILE_RES_X); ++x) { - mSkyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex[side].getDir(x, y), false), x, y); - mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true), x, y); + mSkyTex [side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mSkyTex [side].getDir(x, y), false, low_end), x, y); + mShinyTex[side].setPixel(m_legacyAtmospherics.calcSkyColorInDir(psky, vars, mShinyTex[side].getDir(x, y), true , low_end), x, y); } } } -void LLVOSky::updateDirections(void) +void LLVOSky::updateDirections(LLSettingsSky::ptr_t psky) { - LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - mSun.setDirection(psky->getSunDirection()); - mMoon.setDirection(psky->getMoonDirection()); + mMoon.setDirection(psky->getMoonDirection()); mSun.setRotation(psky->getSunRotation()); - mMoon.setRotation(psky->getMoonRotation()); - mSun.renewDirection(); - mMoon.renewDirection(); + mMoon.setRotation(psky->getMoonRotation()); + mSun.renewDirection(); + mMoon.renewDirection(); } void LLVOSky::idleUpdate(LLAgent &agent, const F64 &time) @@ -692,11 +672,6 @@ bool LLVOSky::updateSky() if (mDead || !(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SKY))) { - return TRUE; - } - - if (mDead) - { // It's dead. Don't update it. return TRUE; } @@ -706,18 +681,18 @@ bool LLVOSky::updateSky() return TRUE; } + LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT; + static S32 next_frame = 0; - const S32 total_no_tiles = NUM_CUBEMAP_FACES * NUM_TILES; - const S32 cycle_frame_no = total_no_tiles + 1; - + mNeedUpdate = mForceUpdate; ++next_frame; - next_frame = next_frame % cycle_frame_no; + next_frame = next_frame % MAX_TILES; - mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / cycle_frame_no; + mInterpVal = (!mInitialized) ? 1 : (F32)next_frame / MAX_TILES; LLHeavenBody::setInterpVal( mInterpVal ); - updateDirections(); + updateDirections(psky); if (!mCubeMap) { @@ -725,10 +700,9 @@ bool LLVOSky::updateSky() mForceUpdate = FALSE; return TRUE; } - + if (mCubeMapUpdateStage < 0) { - LL_RECORD_BLOCK_TIME(FTM_VOSKY_CALC); calc(); bool same_atmospherics = approximatelyEqual(m_lastAtmosphericsVars, m_atmosphericsVars, UPDATE_MIN_DELTA_THRESHOLD); @@ -745,7 +719,7 @@ bool LLVOSky::updateSky() } else if (mCubeMapUpdateStage == NUM_CUBEMAP_FACES) { - LL_RECORD_BLOCK_TIME(FTM_VOSKY_UPDATEFORCED); + LL_PROFILE_ZONE_NAMED("updateSky - forced"); LLSkyTex::stepCurrent(); bool is_alm_wl_sky = gPipeline.canUseWindLightShaders(); @@ -805,8 +779,8 @@ bool LLVOSky::updateSky() } // run 0 to 5 faces, each face in own frame else if (mCubeMapUpdateStage >= 0 && mCubeMapUpdateStage < NUM_CUBEMAP_FACES) - { - LL_RECORD_BLOCK_TIME(FTM_VOSKY_CREATETEXTURES); + { + LL_PROFILE_ZONE_NAMED("updateSky - create"); S32 side = mCubeMapUpdateStage; // CPU hungry part, createSkyTexture() is math heavy // Prior to EEP it was mostly per tile, but since EPP it is per face. @@ -815,7 +789,7 @@ bool LLVOSky::updateSky() // instead of executing per face, or may be can be moved to shaders) for (S32 tile = 0; tile < NUM_TILES; tile++) { - createSkyTexture(m_atmosphericsVars, side, tile); + createSkyTexture(psky, m_atmosphericsVars, side, tile); } mCubeMapUpdateStage++; } @@ -889,10 +863,10 @@ void LLVOSky::setSunScale(F32 sun_scale) void LLVOSky::setMoonScale(F32 moon_scale) { mMoonScale = moon_scale; - } - +} + void LLVOSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_texture_next) - { +{ // We test the UUIDs here because we explicitly do not want the default image returned by getFetchedTexture in that case... mSunTexturep[0] = sun_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(sun_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); mSunTexturep[1] = sun_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(sun_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); @@ -910,32 +884,32 @@ void LLVOSky::setSunTextures(const LLUUID& sun_texture, const LLUUID& sun_textur LLViewerTexture* current_tex1 = mFace[FACE_SUN]->getTexture(LLRender::ALTERNATE_DIFFUSE_MAP); if (current_tex0 && (mSunTexturep[0] != current_tex0) && current_tex0->isViewerMediaTexture()) - { + { static_cast<LLViewerMediaTexture*>(current_tex0)->removeMediaFromFace(mFace[FACE_SUN]); } if (current_tex1 && (mSunTexturep[1] != current_tex1) && current_tex1->isViewerMediaTexture()) - { + { static_cast<LLViewerMediaTexture*>(current_tex1)->removeMediaFromFace(mFace[FACE_SUN]); - } + } mFace[FACE_SUN]->setTexture(LLRender::DIFFUSE_MAP, mSunTexturep[0]); if (can_use_wl) { if (mSunTexturep[1]) - { - mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); - } + { + mSunTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); + } mFace[FACE_SUN]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mSunTexturep[1]); - } - } - } + } + } +} void LLVOSky::setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_texture_next) - { +{ LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); - + bool can_use_wl = gPipeline.canUseWindLightShaders(); mMoonTexturep[0] = moon_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(moon_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); @@ -944,17 +918,17 @@ void LLVOSky::setMoonTextures(const LLUUID& moon_texture, const LLUUID& moon_tex if (mFace[FACE_MOON]) { if (mMoonTexturep[0]) - { - mMoonTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP); - } + { + mMoonTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP); + } mFace[FACE_MOON]->setTexture(LLRender::DIFFUSE_MAP, mMoonTexturep[0]); if (mMoonTexturep[1] && can_use_wl) - { - mMoonTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); + { + mMoonTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); mFace[FACE_MOON]->setTexture(LLRender::ALTERNATE_DIFFUSE_MAP, mMoonTexturep[1]); - } - } + } + } } void LLVOSky::setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLUUID& cloud_noise_texture_next) @@ -963,7 +937,7 @@ void LLVOSky::setCloudNoiseTextures(const LLUUID& cloud_noise_texture, const LLU mCloudNoiseTexturep[0] = cloud_noise_texture.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(cloud_noise_texture, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); mCloudNoiseTexturep[1] = cloud_noise_texture_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(cloud_noise_texture_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); - + if (mCloudNoiseTexturep[0]) { mCloudNoiseTexturep[0]->setAddressMode(LLTexUnit::TAM_WRAP); @@ -986,21 +960,19 @@ void LLVOSky::setBloomTextures(const LLUUID& bloom_texture, const LLUUID& bloom_ mBloomTexturep[1] = bloom_tex_next.isNull() ? nullptr : LLViewerTextureManager::getFetchedTexture(bloom_tex_next, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_UI); if (mBloomTexturep[0]) -{ - mBloomTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP); + { + mBloomTexturep[0]->setAddressMode(LLTexUnit::TAM_CLAMP); } if (mBloomTexturep[1]) - { - mBloomTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); + { + mBloomTexturep[1]->setAddressMode(LLTexUnit::TAM_CLAMP); } - } - -static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Sky Geometry"); +} BOOL LLVOSky::updateGeometry(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_GEO_SKY); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWABLE; if (mFace[FACE_REFLECTION] == NULL) { LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); @@ -1029,11 +1001,11 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) LLStrider<LLVector2> texCoordsp; LLStrider<U16> indicesp; U16 index_offset; - LLFace *face; + LLFace *face; for (S32 side = 0; side < NUM_CUBEMAP_FACES; ++side) { - face = mFace[FACE_SIDE0 + side]; + face = mFace[FACE_SIDE0 + side]; if (!face->getVertexBuffer()) { @@ -1045,7 +1017,7 @@ BOOL LLVOSky::updateGeometry(LLDrawable *drawable) face->setVertexBuffer(buff); index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); - + S32 vtx = 0; S32 curr_bit = side >> 1; // 0/1 = Z axis, 2/3 = Y, 4/5 = X S32 side_dir = side & 1; // even - 0, odd - 1 @@ -1164,11 +1136,11 @@ bool LLVOSky::updateHeavenlyBodyGeometry(LLDrawable *drawable, F32 scale, const hb.setVisible(TRUE); - facep = mFace[f]; + facep = mFace[f]; if (!facep->getVertexBuffer()) { - facep->setSize(4, 6); + facep->setSize(4, 6); LLVertexBuffer* buff = new LLVertexBuffer(LLDrawPoolSky::VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB); if (!buff->allocateBuffer(facep->getGeomCount(), facep->getIndicesCount(), TRUE)) { @@ -1402,7 +1374,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, dt_clip = -0.1f; } - LLFace *face = mFace[FACE_REFLECTION]; + LLFace *face = mFace[FACE_REFLECTION]; if (face) { @@ -1420,13 +1392,13 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, face->setGeomIndex(0); face->setVertexBuffer(buff); } - + LLStrider<LLVector3> verticesp; LLStrider<LLVector3> normalsp; LLStrider<LLVector2> texCoordsp; LLStrider<U16> indicesp; S32 index_offset; - + index_offset = face->getGeometry(verticesp,normalsp,texCoordsp, indicesp); if (-1 == index_offset) { @@ -1444,7 +1416,7 @@ void LLVOSky::updateReflectionGeometry(LLDrawable *drawable, F32 H, LLColor4 hb_refl_col = (1 - attenuation) * hb_col + attenuation * getSkyFogColor(); face->setFaceColor(hb_refl_col); - + LLVector3 v_far[2]; v_far[0] = v_refl_corner[1]; v_far[1] = v_refl_corner[3]; @@ -1568,52 +1540,53 @@ void LLVOSky::updateFog(const F32 distance) } void LLVOSky::setSunAndMoonDirectionsCFR(const LLVector3 &sun_dir_cfr, const LLVector3 &moon_dir_cfr) - { - mSun.setDirection(sun_dir_cfr); - mMoon.setDirection(moon_dir_cfr); +{ + mSun.setDirection(sun_dir_cfr); + mMoon.setDirection(moon_dir_cfr); - // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping - // on the upward facing faces of cubes. - { - // Same as dot product with the up direction + clamp. - F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]); - sunDot *= sunDot; - - // Create normalized vector that has the sunDir pushed south about an hour and change. - LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f; - - // Blend between normal sun dir and adjusted sun dir based on how close we are - // to having the sun overhead. - mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot); - mBumpSunDir.normalize(); - } - updateDirections(); - } + // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping + // on the upward facing faces of cubes. + // Same as dot product with the up direction + clamp. + F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]); + sunDot *= sunDot; + + // Create normalized vector that has the sunDir pushed south about an hour and change. + LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f; + + // Blend between normal sun dir and adjusted sun dir based on how close we are + // to having the sun overhead. + mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot); + mBumpSunDir.normalize(); + + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + updateDirections(psky); +} void LLVOSky::setSunDirectionCFR(const LLVector3 &sun_dir_cfr) - { - mSun.setDirection(sun_dir_cfr); +{ + mSun.setDirection(sun_dir_cfr); - // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping - // on the upward facing faces of cubes. - { - // Same as dot product with the up direction + clamp. - F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]); - sunDot *= sunDot; + // Push the sun "South" as it approaches directly overhead so that we can always see bump mapping + // on the upward facing faces of cubes. + // Same as dot product with the up direction + clamp. + F32 sunDot = llmax(0.f, sun_dir_cfr.mV[2]); + sunDot *= sunDot; - // Create normalized vector that has the sunDir pushed south about an hour and change. - LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f; + // Create normalized vector that has the sunDir pushed south about an hour and change. + LLVector3 adjustedDir = (sun_dir_cfr + LLVector3(0.f, -0.70711f, 0.70711f)) * 0.5f; - // Blend between normal sun dir and adjusted sun dir based on how close we are - // to having the sun overhead. - mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot); - mBumpSunDir.normalize(); - } - updateDirections(); + // Blend between normal sun dir and adjusted sun dir based on how close we are + // to having the sun overhead. + mBumpSunDir = adjustedDir * sunDot + sun_dir_cfr * (1.0f - sunDot); + mBumpSunDir.normalize(); + + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + updateDirections(psky); } void LLVOSky::setMoonDirectionCFR(const LLVector3 &moon_dir_cfr) { - mMoon.setDirection(moon_dir_cfr); - updateDirections(); + mMoon.setDirection(moon_dir_cfr); + LLSettingsSky::ptr_t psky = LLEnvironment::instance().getCurrentSky(); + updateDirections(psky); } diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h index 39e42bbb24..5941ab6e3b 100644 --- a/indra/newview/llvosky.h +++ b/indra/newview/llvosky.h @@ -43,6 +43,9 @@ const F32 HEAVENLY_BODY_DIST = HORIZON_DIST - 20.f; const F32 HEAVENLY_BODY_FACTOR = 0.1f; const F32 HEAVENLY_BODY_SCALE = HEAVENLY_BODY_DIST * HEAVENLY_BODY_FACTOR; +const F32 SKYTEX_COMPONENTS = 4; +const F32 SKYTEX_RESOLUTION = 64; + class LLFace; class LLHaze; @@ -50,8 +53,6 @@ class LLSkyTex { friend class LLVOSky; private: - static S32 sResolution; - static S32 sComponents; LLPointer<LLViewerTexture> mTexture[2]; LLPointer<LLImageRaw> mImageRaw[2]; LLColor4 *mSkyData; @@ -82,25 +83,25 @@ protected: void setDir(const LLVector3 &dir, const S32 i, const S32 j) { - S32 offset = i * sResolution + j; + S32 offset = i * SKYTEX_RESOLUTION + j; mSkyDirs[offset] = dir; } const LLVector3 &getDir(const S32 i, const S32 j) const { - S32 offset = i * sResolution + j; + S32 offset = i * SKYTEX_RESOLUTION + j; return mSkyDirs[offset]; } void setPixel(const LLColor4 &col, const S32 i, const S32 j) { - S32 offset = i * sResolution + j; + S32 offset = i * SKYTEX_RESOLUTION + j; mSkyData[offset] = col; } void setPixel(const LLColor4U &col, const S32 i, const S32 j) { - S32 offset = (i * sResolution + j) * sComponents; + S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS; U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]); *pix = col.asRGBA(); } @@ -108,7 +109,7 @@ protected: LLColor4U getPixel(const S32 i, const S32 j) { LLColor4U col; - S32 offset = (i * sResolution + j) * sComponents; + S32 offset = (i * SKYTEX_RESOLUTION + j) * SKYTEX_COMPONENTS; U32* pix = (U32*) &(mImageRaw[sCurrent]->getData()[offset]); col.fromRGBA( *pix ); return col; @@ -214,12 +215,12 @@ public: // Initialize/delete data that's only inited once per class. void init(); void initCubeMap(); - void initEmpty(); void cleanupGL(); void restoreGL(); void calc(); + void cacheEnvironment(LLSettingsSky::ptr_t psky, AtmosphericsVars& atmosphericsVars); /*virtual*/ void idleUpdate(LLAgent &agent, const F64 &time); bool updateSky(); @@ -253,8 +254,6 @@ public: LLColor4 getSkyFogColor() const { return m_legacyAtmospherics.getFogColor(); } LLColor4 getGLFogColor() const { return m_legacyAtmospherics.getGLFogColor(); } - LLColor4U getFadeColor() const; - void setCloudDensity(F32 cloud_density) { mCloudDensity = cloud_density; } void setWind ( const LLVector3& wind ) { mWind = wind.length(); } @@ -299,10 +298,10 @@ public: protected: ~LLVOSky(); - void updateDirections(void); + void updateDirections(LLSettingsSky::ptr_t psky); void initSkyTextureDirs(const S32 side, const S32 tile); - void createSkyTexture(AtmosphericsVars& vars, const S32 side, const S32 tile); + void createSkyTexture(const LLSettingsSky::ptr_t &psky, AtmosphericsVars& vars, const S32 side, const S32 tile); LLPointer<LLViewerFetchedTexture> mSunTexturep[2]; LLPointer<LLViewerFetchedTexture> mMoonTexturep[2]; diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 897bace4e1..b0af565867 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -59,63 +59,7 @@ public: // virtual void setupVertexBuffer(U32 data_mask) { - if (LLGLSLShader::sNoFixedFunction) - { //just use default if shaders are in play - LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3)); - return; - } - - volatile U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData; - - //assume tex coords 2 and 3 are present - U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3; - - if ((data_mask & type_mask) != data_mask) - { - LL_ERRS() << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << LL_ENDL; - } - - if (data_mask & MAP_NORMAL) - { - glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL])); - } - if (data_mask & MAP_TEXCOORD3) - { //substitute tex coord 1 for tex coord 3 - glClientActiveTextureARB(GL_TEXTURE3_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD2) - { //substitute tex coord 0 for tex coord 2 - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD1) - { - glClientActiveTextureARB(GL_TEXTURE1_ARB); - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TANGENT) - { - glClientActiveTextureARB(GL_TEXTURE2_ARB); - glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT])); - glClientActiveTextureARB(GL_TEXTURE0_ARB); - } - if (data_mask & MAP_TEXCOORD0) - { - glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0])); - } - if (data_mask & MAP_COLOR) - { - glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeSize[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR])); - } - - if (data_mask & MAP_VERTEX) - { - glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_VERTEX], (void*)(base + 0)); - } + LLVertexBuffer::setupVertexBuffer(data_mask & ~(MAP_TEXCOORD2 | MAP_TEXCOORD3)); } }; @@ -212,19 +156,19 @@ LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline) return mDrawable; } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_TERRAIN("Update Terrain"); void LLVOSurfacePatch::updateGL() { if (mPatchp) { + LL_PROFILE_ZONE_SCOPED mPatchp->updateGL(); } } BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_TERRAIN); + LL_PROFILE_ZONE_SCOPED; dirtySpatialGroup(TRUE); @@ -1070,10 +1014,9 @@ LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage) return new LLVertexBufferTerrain(); } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_TERRAIN_VB("Terrain VB"); void LLTerrainPartition::getGeometry(LLSpatialGroup* group) { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_TERRAIN_VB); + LL_PROFILE_ZONE_SCOPED; LLVertexBuffer* buffer = group->mVertexBuffer; diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 41099cb570..493162b47b 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -493,11 +493,9 @@ LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline) const S32 LEAF_INDICES = 24; const S32 LEAF_VERTICES = 16; -static LLTrace::BlockTimerStatHandle FTM_UPDATE_TREE("Update Tree"); - BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_TREE); + LL_PROFILE_ZONE_SCOPED; if(mTrunkLOD >= sMAX_NUM_TREE_LOD_LEVELS) //do not display the tree. { diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index d75a4fd42d..126a25115d 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -105,10 +105,6 @@ S32 LLVOVolume::mRenderComplexity_current = 0; LLPointer<LLObjectMediaDataClient> LLVOVolume::sObjectMediaClient = NULL; LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient = NULL; -static LLTrace::BlockTimerStatHandle FTM_GEN_TRIANGLES("Generate Triangles"); -static LLTrace::BlockTimerStatHandle FTM_GEN_VOLUME("Generate Volumes"); -static LLTrace::BlockTimerStatHandle FTM_VOLUME_TEXTURES("Volume Textures"); - extern BOOL gGLDebugLoggingEnabled; // Implementation class of LLMediaDataClientObject. See llmediadataclient.h @@ -231,6 +227,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mNumFaces = 0; mLODChanged = FALSE; mSculptChanged = FALSE; + mColorChanged = FALSE; mSpotLightPriority = 0.f; mMediaImplList.resize(getNumTEs()); @@ -718,7 +715,7 @@ BOOL LLVOVolume::isVisible() const void LLVOVolume::updateTextureVirtualSize(bool forced) { - LL_RECORD_BLOCK_TIME(FTM_VOLUME_TEXTURES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; // Update the pixel area of all faces if (mDrawable.isNull()) @@ -997,6 +994,7 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline) BOOL LLVOVolume::setVolume(const LLVolumeParams ¶ms_in, const S32 detail, bool unique_volume) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; LLVolumeParams volume_params = params_in; S32 last_lod = mVolumep.notNull() ? LLVolumeLODGroup::getVolumeDetailFromScale(mVolumep->getDetail()) : -1; @@ -1175,13 +1173,17 @@ void LLVOVolume::notifyMeshLoaded() mSculptChanged = TRUE; gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); - if (getAvatar() && !isAnimatedObject()) + LLVOAvatar *av = getAvatar(); + if (av && !isAnimatedObject()) { - getAvatar()->addAttachmentOverridesForObject(this); + av->addAttachmentOverridesForObject(this); + av->notifyAttachmentMeshLoaded(); } - if (getControlAvatar() && isAnimatedObject()) + LLControlAvatar *cav = getControlAvatar(); + if (cav && isAnimatedObject()) { - getControlAvatar()->addAttachmentOverridesForObject(this); + cav->addAttachmentOverridesForObject(this); + cav->notifyAttachmentMeshLoaded(); } updateVisualComplexity(); } @@ -1624,6 +1626,7 @@ BOOL LLVOVolume::setParent(LLViewerObject* parent) // NOTE: regenFaces() MUST be followed by genTriangles()! void LLVOVolume::regenFaces() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; // remove existing faces BOOL count_changed = mNumFaces != getNumTEs(); @@ -1671,14 +1674,15 @@ void LLVOVolume::regenFaces() BOOL LLVOVolume::genBBoxes(BOOL force_global) { - BOOL res = TRUE; + LL_PROFILE_ZONE_SCOPED; + BOOL res = TRUE; - LLVector4a min,max; + LLVector4a min, max; - min.clear(); - max.clear(); + min.clear(); + max.clear(); - BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED); + BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED); if (getRiggedVolume()) { @@ -1689,74 +1693,112 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) // Without the flag, this will remove unused rigged volumes, which we are not currently very aggressive about. updateRiggedVolume(); } - - LLVolume* volume = mRiggedVolume; - if (!volume) - { - volume = getVolume(); - } + + LLVolume* volume = mRiggedVolume; + if (!volume) + { + volume = getVolume(); + } bool any_valid_boxes = false; - + if (getRiggedVolume()) { LL_DEBUGS("RiggedBox") << "rebuilding box, volume face count " << getVolume()->getNumVolumeFaces() << " drawable face count " << mDrawable->getNumFaces() << LL_ENDL; } + // There's no guarantee that getVolume()->getNumFaces() == mDrawable->getNumFaces() - for (S32 i = 0; - i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs(); - i++) - { - LLFace *face = mDrawable->getFace(i); - if (!face) - { - continue; - } + for (S32 i = 0; + i < getVolume()->getNumVolumeFaces() && i < mDrawable->getNumFaces() && i < getNumTEs(); + i++) + { + LLFace* face = mDrawable->getFace(i); + if (!face) + { + continue; + } BOOL face_res = face->genVolumeBBoxes(*volume, i, - mRelativeXform, - (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); + mRelativeXform, + (mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global); res &= face_res; // note that this result is never used - + // MAINT-8264 - ignore bboxes of ill-formed faces. if (!face_res) { continue; } - if (rebuild) - { + if (rebuild) + { if (getRiggedVolume()) { LL_DEBUGS("RiggedBox") << "rebuilding box, face " << i << " extents " << face->mExtents[0] << ", " << face->mExtents[1] << LL_ENDL; } - if (!any_valid_boxes) - { - min = face->mExtents[0]; - max = face->mExtents[1]; + if (!any_valid_boxes) + { + min = face->mExtents[0]; + max = face->mExtents[1]; any_valid_boxes = true; - } - else - { - min.setMin(min, face->mExtents[0]); - max.setMax(max, face->mExtents[1]); - } - } - } + } + else + { + min.setMin(min, face->mExtents[0]); + max.setMax(max, face->mExtents[1]); + } + } + } + + bool rigged = false; + + if (!isAnimatedObject()) + { + rigged = isRiggedMesh() && isAttachment(); + } + else + { + rigged = isRiggedMesh() && getControlAvatar() && getControlAvatar()->mPlaying; + } if (any_valid_boxes) { if (rebuild) { - if (getRiggedVolume()) + //get the Avatar associated with this object if it's rigged + LLVOAvatar* avatar = nullptr; + if (isRiggedMesh()) { - LL_DEBUGS("RiggedBox") << "rebuilding got extents " << min << ", " << max << LL_ENDL; + if (!isAnimatedObject()) + { + if (isAttachment()) + { + avatar = getAvatar(); + } + } + else + { + LLControlAvatar* controlAvatar = getControlAvatar(); + if (controlAvatar && controlAvatar->mPlaying) + { + avatar = controlAvatar; + } + } } - mDrawable->setSpatialExtents(min,max); - min.add(max); - min.mul(0.5f); - mDrawable->setPositionGroup(min); - } + mDrawable->setSpatialExtents(min, max); + + if (avatar) + { + // put all rigged drawables in the same octree node for better batching + mDrawable->setPositionGroup(LLVector4a(0, 0, 0)); + } + else + { + min.add(max); + min.mul(0.5f); + mDrawable->setPositionGroup(min); + } + } + updateRadius(); mDrawable->movePartition(); } @@ -1764,8 +1806,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global) { LL_DEBUGS("RiggedBox") << "genBBoxes failed to find any valid face boxes" << LL_ENDL; } - - return res; + + return res; } void LLVOVolume::preRebuild() @@ -1881,12 +1923,9 @@ void LLVOVolume::updateRelativeXform(bool force_identity) } } -static LLTrace::BlockTimerStatHandle FTM_GEN_FLEX("Generate Flexies"); -static LLTrace::BlockTimerStatHandle FTM_UPDATE_PRIMITIVES("Update Primitives"); -static LLTrace::BlockTimerStatHandle FTM_UPDATE_RIGGED_VOLUME("Update Rigged"); - bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; bool regen_faces = false; LLVolume *old_volumep, *new_volumep; @@ -1899,7 +1938,6 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) old_volumep = NULL; { - LL_RECORD_BLOCK_TIME(FTM_GEN_VOLUME); const LLVolumeParams &volume_params = getVolume()->getParams(); setVolume(volume_params, 0); } @@ -1927,7 +1965,6 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() { - LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); regen_faces = new_num_faces != old_num_faces || mNumFaces != (S32)getNumTEs(); if (regen_faces) { @@ -1952,14 +1989,11 @@ bool LLVOVolume::lodOrSculptChanged(LLDrawable *drawable, BOOL &compiled) BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_PRIMITIVES); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; if (mDrawable->isState(LLDrawable::REBUILD_RIGGED)) { - { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_RIGGED_VOLUME); - updateRiggedVolume(); - } + updateRiggedVolume(); genBBoxes(FALSE); mDrawable->clearState(LLDrawable::REBUILD_RIGGED); } @@ -1968,7 +2002,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { BOOL res; { - LL_RECORD_BLOCK_TIME(FTM_GEN_FLEX); res = mVolumeImpl->doUpdateGeometry(drawable); } updateFaceFlags(); @@ -2001,20 +2034,19 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) was_regen_faces = lodOrSculptChanged(drawable, compiled); drawable->setState(LLDrawable::REBUILD_VOLUME); } - else if (mSculptChanged || mLODChanged) + else if (mSculptChanged || mLODChanged || mColorChanged) { compiled = TRUE; was_regen_faces = lodOrSculptChanged(drawable, compiled); } if (!was_regen_faces) { - LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); regenFaces(); } genBBoxes(FALSE); } - else if (mLODChanged || mSculptChanged) + else if (mLODChanged || mSculptChanged || mColorChanged) { dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1)); compiled = TRUE; @@ -2031,7 +2063,6 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { compiled = TRUE; // All it did was move or we changed the texture coordinate offset - LL_RECORD_BLOCK_TIME(FTM_GEN_TRIANGLES); genBBoxes(FALSE); } @@ -2047,6 +2078,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) mLODChanged = FALSE; mSculptChanged = FALSE; mFaceMappingChanged = FALSE; + mColorChanged = FALSE; return LLViewerObject::updateGeometry(drawable); } @@ -2185,6 +2217,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color) if (mDrawable.notNull() && retval) { // These should only happen on updates which are not the initial update. + mColorChanged = TRUE; mDrawable->setState(LLDrawable::REBUILD_COLOR); dirtyMesh(); } @@ -3592,7 +3625,7 @@ const LLMeshSkinInfo* LLVOVolume::getSkinInfo() const { if (getVolume()) { - return gMeshRepo.getSkinInfo(getVolume()->getParams().getSculptID(), this); + return gMeshRepo.getSkinInfo(getMeshID(), this); } else { @@ -3754,11 +3787,9 @@ void LLVOVolume::afterReparent() } //---------------------------------------------------------------------------- -static LLTrace::BlockTimerStatHandle FTM_VOVOL_RIGGING_INFO("VOVol Rigging Info"); - void LLVOVolume::updateRiggingInfo() { - LL_RECORD_BLOCK_TIME(FTM_VOVOL_RIGGING_INFO); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; if (isRiggedMesh()) { const LLMeshSkinInfo* skin = getSkinInfo(); @@ -4368,6 +4399,7 @@ void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) F32 LLVOVolume::getBinRadius() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; F32 radius; F32 scale = 1.f; @@ -4763,6 +4795,7 @@ void LLVOVolume::clearRiggedVolume() void LLVOVolume::updateRiggedVolume(bool force_update) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; //Update mRiggedVolume to match current animation frame of avatar. //Also update position/size in octree. @@ -4798,11 +4831,9 @@ void LLVOVolume::updateRiggedVolume(bool force_update) mRiggedVolume->update(skin, avatar, volume); } -static LLTrace::BlockTimerStatHandle FTM_SKIN_RIGGED("Skin"); -static LLTrace::BlockTimerStatHandle FTM_RIGGED_OCTREE("Octree"); - void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; bool copy = false; if (volume->getNumVolumeFaces() != getNumVolumeFaces()) { @@ -4823,7 +4854,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons if (copy) { - copyVolumeFaces(volume); + copyVolumeFaces(volume); } else { @@ -4844,7 +4875,8 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons LLMatrix4a mat[kMaxJoints]; U32 maxJoints = LLSkinningUtil::getMeshJointCount(skin); - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, maxJoints, skin, avatar); + LLSkinningUtil::initSkinningMatrixPalette(mat, maxJoints, skin, avatar); + const LLMatrix4a bind_shape_matrix = skin->mBindShapeMatrix; S32 rigged_vert_count = 0; S32 rigged_face_count = 0; @@ -4860,15 +4892,11 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons if ( weight ) { LLSkinningUtil::checkSkinWeights(weight, dst_face.mNumVertices, skin); - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); LLVector4a* pos = dst_face.mPositions; if (pos && dst_face.mExtents) { - LL_RECORD_BLOCK_TIME(FTM_SKIN_RIGGED); - U32 max_joints = LLSkinningUtil::getMaxJointCount(); rigged_vert_count += dst_face.mNumVertices; rigged_face_count++; @@ -4939,8 +4967,7 @@ void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, cons } { - LL_RECORD_BLOCK_TIME(FTM_RIGGED_OCTREE); - delete dst_face.mOctree; + delete dst_face.mOctree; dst_face.mOctree = NULL; LLVector4a size; @@ -5042,13 +5069,13 @@ bool can_batch_texture(LLFace* facep) const static U32 MAX_FACE_COUNT = 4096U; int32_t LLVolumeGeometryManager::sInstanceCount = 0; -LLFace** LLVolumeGeometryManager::sFullbrightFaces = NULL; -LLFace** LLVolumeGeometryManager::sBumpFaces = NULL; -LLFace** LLVolumeGeometryManager::sSimpleFaces = NULL; -LLFace** LLVolumeGeometryManager::sNormFaces = NULL; -LLFace** LLVolumeGeometryManager::sSpecFaces = NULL; -LLFace** LLVolumeGeometryManager::sNormSpecFaces = NULL; -LLFace** LLVolumeGeometryManager::sAlphaFaces = NULL; +LLFace** LLVolumeGeometryManager::sFullbrightFaces[2] = { NULL }; +LLFace** LLVolumeGeometryManager::sBumpFaces[2] = { NULL }; +LLFace** LLVolumeGeometryManager::sSimpleFaces[2] = { NULL }; +LLFace** LLVolumeGeometryManager::sNormFaces[2] = { NULL }; +LLFace** LLVolumeGeometryManager::sSpecFaces[2] = { NULL }; +LLFace** LLVolumeGeometryManager::sNormSpecFaces[2] = { NULL }; +LLFace** LLVolumeGeometryManager::sAlphaFaces[2] = { NULL }; LLVolumeGeometryManager::LLVolumeGeometryManager() : LLGeometryManager() @@ -5076,39 +5103,43 @@ LLVolumeGeometryManager::~LLVolumeGeometryManager() void LLVolumeGeometryManager::allocateFaces(U32 pMaxFaceCount) { - sFullbrightFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); - sBumpFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); - sSimpleFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); - sNormFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); - sSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); - sNormSpecFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); - sAlphaFaces = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount*sizeof(LLFace*))); + for (int i = 0; i < 2; ++i) + { + sFullbrightFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); + sBumpFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); + sSimpleFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); + sNormFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); + sSpecFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); + sNormSpecFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); + sAlphaFaces[i] = static_cast<LLFace**>(ll_aligned_malloc<64>(pMaxFaceCount * sizeof(LLFace*))); + } } void LLVolumeGeometryManager::freeFaces() { - ll_aligned_free<64>(sFullbrightFaces); - ll_aligned_free<64>(sBumpFaces); - ll_aligned_free<64>(sSimpleFaces); - ll_aligned_free<64>(sNormFaces); - ll_aligned_free<64>(sSpecFaces); - ll_aligned_free<64>(sNormSpecFaces); - ll_aligned_free<64>(sAlphaFaces); - - sFullbrightFaces = NULL; - sBumpFaces = NULL; - sSimpleFaces = NULL; - sNormFaces = NULL; - sSpecFaces = NULL; - sNormSpecFaces = NULL; - sAlphaFaces = NULL; + for (int i = 0; i < 2; ++i) + { + ll_aligned_free<64>(sFullbrightFaces[i]); + ll_aligned_free<64>(sBumpFaces[i]); + ll_aligned_free<64>(sSimpleFaces[i]); + ll_aligned_free<64>(sNormFaces[i]); + ll_aligned_free<64>(sSpecFaces[i]); + ll_aligned_free<64>(sNormSpecFaces[i]); + ll_aligned_free<64>(sAlphaFaces[i]); + + sFullbrightFaces[i] = NULL; + sBumpFaces[i] = NULL; + sSimpleFaces[i] = NULL; + sNormFaces[i] = NULL; + sSpecFaces[i] = NULL; + sNormSpecFaces[i] = NULL; + sAlphaFaces[i] = NULL; + } } -static LLTrace::BlockTimerStatHandle FTM_REGISTER_FACE("Register Face"); - void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type) { - LL_RECORD_BLOCK_TIME(FTM_REGISTER_FACE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; if ( type == LLRenderPass::PASS_ALPHA && facep->getTextureEntry()->getMaterialParams().notNull() && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT) @@ -5124,8 +5155,18 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, return; } + U32 passType = type; + + bool rigged = facep->isState(LLFace::RIGGED); + + if (rigged) + { + // hacky, should probably clean up -- if this face is rigged, put it in "type + 1" + // See LLRenderPass PASS_foo enum + passType += 1; + } //add face to drawmap - LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[type]; + LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[passType]; S32 idx = draw_vec.size()-1; @@ -5151,7 +5192,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LLDrawable* drawable = facep->getDrawable(); - if (drawable->isState(LLDrawable::ANIMATED_CHILD)) + if (rigged) + { + // rigged meshes ignore their model matrix + model_mat = nullptr; + } + else if (drawable->isState(LLDrawable::ANIMATED_CHILD)) { model_mat = &drawable->getWorldMatrix(); } @@ -5192,6 +5238,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } } + F32 vsize = facep->getVirtualSize(); //TODO -- adjust by texture scale? if (index < FACE_DO_NOT_BATCH_TEXTURES && idx >= 0) { @@ -5205,10 +5252,12 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, { batchable = true; draw_vec[idx]->mTextureList[index] = tex; + draw_vec[idx]->mTextureListVSize[index] = vsize; } else if (draw_vec[idx]->mTextureList[index] == tex) { //this face's texture index can be used with this batch batchable = true; + draw_vec[idx]->mTextureListVSize[index] = llmax(vsize, draw_vec[idx]->mTextureListVSize[index]); } } else @@ -5225,7 +5274,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange && draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange && #endif - draw_vec[idx]->mMaterial == mat && + //draw_vec[idx]->mMaterial == mat && draw_vec[idx]->mMaterialID == mat_id && draw_vec[idx]->mFullbright == fullbright && draw_vec[idx]->mBump == bump && @@ -5233,16 +5282,20 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_vec[idx]->mTextureMatrix == tex_mat && draw_vec[idx]->mModelMatrix == model_mat && draw_vec[idx]->mShaderMask == shader_mask && - draw_vec[idx]->mSelected == selected) + draw_vec[idx]->mSelected == selected && + draw_vec[idx]->mAvatar == facep->mAvatar && + draw_vec[idx]->getSkinHash() == facep->getSkinHash()) { draw_vec[idx]->mCount += facep->getIndicesCount(); draw_vec[idx]->mEnd += facep->getGeomCount(); - draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize()); + draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, vsize); if (index < FACE_DO_NOT_BATCH_TEXTURES && index >= draw_vec[idx]->mTextureList.size()) { draw_vec[idx]->mTextureList.resize(index+1); draw_vec[idx]->mTextureList[index] = tex; + draw_vec[idx]->mTextureListVSize.resize(index + 1); + draw_vec[idx]->mTextureListVSize[index] = vsize; } draw_vec[idx]->validate(); update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]); @@ -5257,7 +5310,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, facep->getVertexBuffer(), selected, fullbright, bump); draw_info->mGroup = group; - draw_info->mVSize = facep->getVirtualSize(); + draw_info->mVSize = vsize; draw_vec.push_back(draw_info); draw_info->mTextureMatrix = tex_mat; draw_info->mModelMatrix = model_mat; @@ -5279,6 +5332,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, draw_info->mSpecularMap = NULL; draw_info->mMaterial = mat; draw_info->mShaderMask = shader_mask; + draw_info->mAvatar = facep->mAvatar; + draw_info->mSkinInfo = facep->mSkinInfo; if (mat) { @@ -5330,6 +5385,8 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, { //initialize texture list for texture batching draw_info->mTextureList.resize(index+1); draw_info->mTextureList[index] = tex; + draw_info->mTextureListVSize.resize(index + 1); + draw_info->mTextureListVSize[index] = vsize; } draw_info->validate(); } @@ -5340,38 +5397,6 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_VB("Volume VB"); -static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_FACE_LIST("Build Face List"); -static LLTrace::BlockTimerStatHandle FTM_REBUILD_VOLUME_GEN_DRAW_INFO("Gen Draw Info"); - -static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj) -{ - LLVOAvatar* avatar = vobj->getAvatar(); - - if (avatar) - { - LLDrawable* drawable = avatar->mDrawable; - if (drawable && drawable->getNumFaces() > 0) - { - LLFace* face = drawable->getFace(0); - if (face) - { - LLDrawPool* drawpool = face->getPool(); - if (drawpool) - { - if (drawpool->getType() == LLDrawPool::POOL_AVATAR - || drawpool->getType() == LLDrawPool::POOL_CONTROL_AV) - { - return (LLDrawPoolAvatar*) drawpool; - } - } - } - } - } - - return NULL; -} - void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value) { static LLCachedControl<U32> render_auto_mute_byte_limit(gSavedSettings, "RenderAutoMuteByteLimit", 0U); @@ -5447,8 +5472,31 @@ void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value) } } +// add a face pointer to a list of face pointers without going over MAX_COUNT faces +template<typename T> +static inline void add_face(T*** list, U32* count, T* face) +{ + if (face->isState(LLFace::RIGGED)) + { + if (count[1] < MAX_FACE_COUNT) + { + face->setDrawOrderIndex(count[1]); + list[1][count[1]++] = face; + } + } + else + { + if (count[0] < MAX_FACE_COUNT) + { + face->setDrawOrderIndex(count[0]); + list[0][count[0]++] = face; + } + } +} + void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; if (group->changeLOD()) { group->mLastUpdateDistance = group->mDistance; @@ -5465,8 +5513,6 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) return; } - LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB); - group->mBuilt = 1.f; LLSpatialBridge* bridge = group->getSpatialPartition()->asBridge(); @@ -5492,16 +5538,13 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->clearDrawMap(); - mFaceList.clear(); - - U32 fullbright_count = 0; - U32 bump_count = 0; - U32 simple_count = 0; - U32 alpha_count = 0; - U32 norm_count = 0; - U32 spec_count = 0; - U32 normspec_count = 0; - + U32 fullbright_count[2] = { 0 }; + U32 bump_count[2] = { 0 }; + U32 simple_count[2] = { 0 }; + U32 alpha_count[2] = { 0 }; + U32 norm_count[2] = { 0 }; + U32 spec_count[2] = { 0 }; + U32 normspec_count[2] = { 0 }; U32 useage = group->getSpatialPartition()->mBufferUsage; @@ -5523,7 +5566,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) #endif { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_FACE_LIST); + LL_PROFILE_ZONE_NAMED("rebuildGeom - face list"); //get all the faces into a list for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); @@ -5550,7 +5593,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) std::string vobj_name = llformat("Vol%p", vobj); - if (vobj->isMesh() && + bool is_mesh = vobj->isMesh(); + if (is_mesh && ((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled())) { continue; @@ -5563,7 +5607,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) 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(); vobj->updateControlAvatar(); @@ -5587,15 +5631,32 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) drawablep->clearState(LLDrawable::HAS_ALPHA); - if (vobj->isRiggedMesh() && - ((vobj->isAnimatedObject() && vobj->getControlAvatar()) || - (!vobj->isAnimatedObject() && vobj->getAvatar()))) + LLVOAvatar* avatar = nullptr; + const LLMeshSkinInfo* skinInfo = nullptr; + if (is_mesh) + { + skinInfo = vobj->getSkinInfo(); + } + + if (skinInfo) + { + if (vobj->isAnimatedObject()) + { + avatar = vobj->getControlAvatar(); + } + else + { + avatar = vobj->getAvatar(); + } + } + + if (avatar != nullptr) { - vobj->getAvatar()->addAttachmentOverridesForObject(vobj, NULL, false); + avatar->addAttachmentOverridesForObject(vobj, NULL, false); } // Standard rigged mesh attachments: - bool rigged = !vobj->isAnimatedObject() && vobj->isRiggedMesh() && vobj->isAttachment(); + bool rigged = !vobj->isAnimatedObject() && skinInfo && vobj->isAttachment(); // Animated objects. Have to check for isRiggedMesh() to // exclude static objects in animated object linksets. rigged = rigged || (vobj->isAnimatedObject() && vobj->isRiggedMesh() && @@ -5619,183 +5680,34 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) //sum up face verts and indices drawablep->updateFaceSize(i); - - if (rigged) - { - if (!facep->isState(LLFace::RIGGED)) - { //completely reset vertex buffer - facep->clearVertexBuffer(); - } - - facep->setState(LLFace::RIGGED); - any_rigged_face = true; - - //get drawpool of avatar with rigged face - LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj); - - if (pool) - { - const LLTextureEntry* te = facep->getTextureEntry(); - - //remove face from old pool if it exists - LLDrawPool* old_pool = facep->getPool(); - if (old_pool - && (old_pool->getType() == LLDrawPool::POOL_AVATAR || old_pool->getType() == LLDrawPool::POOL_CONTROL_AV)) - { - ((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep); - } - - //add face to new pool - LLViewerTexture* tex = facep->getTexture(); - U32 type = gPipeline.getPoolTypeFromTE(te, tex); - - F32 te_alpha = te->getColor().mV[3]; - - if (te->getGlow()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW); - } - - LLMaterial* mat = te->getMaterialParams().get(); - bool fullbright = te->getFullbright(); - - if (mat && LLPipeline::sRenderDeferred) - { - U8 alpha_mode = mat->getDiffuseAlphaMode(); - bool is_alpha = type == LLDrawPool::POOL_ALPHA && - (alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND || - te_alpha < 0.999f); - - if (is_alpha) - { //this face needs alpha blending, override alpha mode - alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND; - } - - if (fullbright && (alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE)) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); - } - else if (!is_alpha || te_alpha > 0.f) // //only add the face if it will actually be visible - { - U32 mask = mat->getShaderMask(alpha_mode); - pool->addRiggedFace(facep, mask); - } - - if(vobj->isAnimatedObject() && vobj->isRiggedMesh()) - { - pool->updateRiggedVertexBuffers(vobj->getAvatar()); - } - } - else if (mat) - { - bool is_alpha = type == LLDrawPool::POOL_ALPHA; - U8 mode = mat->getDiffuseAlphaMode(); - bool can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE || - mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE; - - if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK && te->getColor().mV[3] >= 0.999f) - { - pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE); - } - else if (is_alpha || (te->getColor().mV[3] < 0.999f)) - { - if (te->getColor().mV[3] > 0.f) - { - pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA : LLDrawPoolAvatar::RIGGED_ALPHA); - } - } - else if (gPipeline.canUseVertexShaders() - && LLPipeline::sRenderBump - && te->getShiny() - && can_be_shiny) - { - pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : LLDrawPoolAvatar::RIGGED_SHINY); - } - else - { - pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE); - } - } - else - { - if (type == LLDrawPool::POOL_ALPHA) - { - if (te->getColor().mV[3] > 0.f) - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA); - } - } - } - else if (te->getShiny()) - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY); - } - else - { - if (LLPipeline::sRenderDeferred) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY); - } - } - } - else - { - if (te->getFullbright()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE); - } - } - - - if (LLPipeline::sRenderDeferred) - { - if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright()) - { - if (te->getBumpmap()) - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP); - } - else - { - pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE); - } - } - } - } - } - - continue; - } - else - { - if (facep->isState(LLFace::RIGGED)) - { //face is not rigged but used to be, remove from rigged face pool - LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); - if (pool) - { - pool->removeRiggedFace(facep); - } - facep->clearState(LLFace::RIGGED); - } - } + if (rigged) + { + if (!facep->isState(LLFace::RIGGED)) + { //completely reset vertex buffer + facep->clearVertexBuffer(); + } + facep->setState(LLFace::RIGGED); + facep->mSkinInfo = (LLMeshSkinInfo*) skinInfo; // TODO -- fix ugly de-consting here + facep->mAvatar = avatar; + any_rigged_face = true; + } + else + { + if (facep->isState(LLFace::RIGGED)) + { + //face is not rigged but used to be, remove from rigged face pool + LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool(); + if (pool) + { + pool->removeFace(facep); + } + facep->clearState(LLFace::RIGGED); + facep->mAvatar = NULL; + facep->mSkinInfo = NULL; + } + } if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0) { @@ -5803,10 +5715,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) continue; } - cur_total += facep->getGeomCount(); - - if (facep->hasGeometry() && facep->getPixelArea() > FORCE_CULL_AREA) + if (facep->hasGeometry() && + (rigged || // <-- HACK FIXME -- getPixelArea might be incorrect for rigged objects + facep->getPixelArea() > FORCE_CULL_AREA)) // <-- don't render tiny faces { + cur_total += facep->getGeomCount(); + const LLTextureEntry* te = facep->getTextureEntry(); LLViewerTexture* tex = facep->getTexture(); @@ -5864,21 +5778,19 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (facep->canRenderAsMask()) { //can be treated as alpha mask - if (simple_count < MAX_FACE_COUNT) - { - sSimpleFaces[simple_count++] = facep; - } + add_face(sSimpleFaces, simple_count, facep); } else { - if (te->getColor().mV[3] > 0.f) - { //only treat as alpha in the pipeline if < 100% transparent - drawablep->setState(LLDrawable::HAS_ALPHA); - } - if (alpha_count < MAX_FACE_COUNT) - { - sAlphaFaces[alpha_count++] = facep; - } + if (te->getColor().mV[3] > 0.f || te->getGlow() > 0.f) + { //only treat as alpha in the pipeline if < 100% transparent + drawablep->setState(LLDrawable::HAS_ALPHA); + add_face(sAlphaFaces, alpha_count, facep); + } + else if (LLDrawPoolAlpha::sShowDebugAlpha) + { + add_face(sAlphaFaces, alpha_count, facep); + } } } else @@ -5898,81 +5810,51 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (mat->getSpecularID().notNull()) { //has normal and specular maps (needs texcoord1, texcoord2, and tangent) - if (normspec_count < MAX_FACE_COUNT) - { - sNormSpecFaces[normspec_count++] = facep; - } + add_face(sNormSpecFaces, normspec_count, facep); } else { //has normal map (needs texcoord1 and tangent) - if (norm_count < MAX_FACE_COUNT) - { - sNormFaces[norm_count++] = facep; - } + add_face(sNormFaces, norm_count, facep); } } else if (mat->getSpecularID().notNull()) { //has specular map but no normal map, needs texcoord2 - if (spec_count < MAX_FACE_COUNT) - { - sSpecFaces[spec_count++] = facep; - } + add_face(sSpecFaces, spec_count, facep); } else { //has neither specular map nor normal map, only needs texcoord0 - if (simple_count < MAX_FACE_COUNT) - { - sSimpleFaces[simple_count++] = facep; - } + add_face(sSimpleFaces, simple_count, facep); } } else if (te->getBumpmap()) { //needs normal + tangent - if (bump_count < MAX_FACE_COUNT) - { - sBumpFaces[bump_count++] = facep; - } + add_face(sBumpFaces, bump_count, facep); } else if (te->getShiny() || !te->getFullbright()) { //needs normal - if (simple_count < MAX_FACE_COUNT) - { - sSimpleFaces[simple_count++] = facep; - } + add_face(sSimpleFaces, simple_count, facep); } else { //doesn't need normal facep->setState(LLFace::FULLBRIGHT); - if (fullbright_count < MAX_FACE_COUNT) - { - sFullbrightFaces[fullbright_count++] = facep; - } + add_face(sFullbrightFaces, fullbright_count, facep); } } else { if (te->getBumpmap() && LLPipeline::sRenderBump) { //needs normal + tangent - if (bump_count < MAX_FACE_COUNT) - { - sBumpFaces[bump_count++] = facep; - } + add_face(sBumpFaces, bump_count, facep); } else if ((te->getShiny() && LLPipeline::sRenderBump) || !(te->getFullbright() || bake_sunlight)) { //needs normal - if (simple_count < MAX_FACE_COUNT) - { - sSimpleFaces[simple_count++] = facep; - } + add_face(sSimpleFaces, simple_count, facep); } else { //doesn't need normal facep->setState(LLFace::FULLBRIGHT); - if (fullbright_count < MAX_FACE_COUNT) - { - sFullbrightFaces[fullbright_count++] = facep; - } + add_face(sFullbrightFaces, fullbright_count, facep); } } } @@ -5988,6 +5870,11 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (!drawablep->isState(LLDrawable::RIGGED)) { drawablep->setState(LLDrawable::RIGGED); + LLDrawable* root = drawablep->getRoot(); + if (root != drawablep) + { + root->setState(LLDrawable::RIGGED_CHILD); + } //first time this is drawable is being marked as rigged, // do another LoD update to use avatar bounding box @@ -6027,6 +5914,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) BOOL batch_textures = LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1; + // add extra vertex data for deferred rendering (not necessarily for batching textures) if (batch_textures) { bump_mask = bump_mask | LLVertexBuffer::MAP_TANGENT; @@ -6039,13 +5927,24 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) U32 geometryBytes = 0; - geometryBytes += genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSimpleFaces, simple_count, FALSE, batch_textures, FALSE); - geometryBytes += genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sFullbrightFaces, fullbright_count, FALSE, batch_textures); - geometryBytes += genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sAlphaFaces, alpha_count, TRUE, batch_textures); - geometryBytes += genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sBumpFaces, bump_count, FALSE, FALSE); - geometryBytes += genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormFaces, norm_count, FALSE, FALSE); - geometryBytes += genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sSpecFaces, spec_count, FALSE, FALSE); - geometryBytes += genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, sNormSpecFaces, normspec_count, FALSE, FALSE); + // generate render batches for static geometry + U32 extra_mask = LLVertexBuffer::MAP_TEXTURE_INDEX; + BOOL alpha_sort = TRUE; + BOOL rigged = FALSE; + for (int i = 0; i < 2; ++i) //two sets, static and rigged) + { + geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[i], simple_count[i], FALSE, batch_textures, rigged); + geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[i], fullbright_count[i], FALSE, batch_textures, rigged); + geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[i], alpha_count[i], alpha_sort, batch_textures, rigged); + geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[i], bump_count[i], FALSE, FALSE, rigged); + geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[i], norm_count[i], FALSE, FALSE, rigged); + geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[i], spec_count[i], FALSE, FALSE, rigged); + geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[i], normspec_count[i], FALSE, FALSE, rigged); + + // for rigged set, add weights and disable alpha sorting (rigged items use depth buffer) + extra_mask |= LLVertexBuffer::MAP_WEIGHT4; + rigged = TRUE; + } group->mGeometryBytes = geometryBytes; @@ -6071,156 +5970,146 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) group->setState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); } - mFaceList.clear(); } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_MESH_FLUSH("Flush Mesh"); - void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; llassert(group); if (group && group->hasState(LLSpatialGroup::MESH_DIRTY) && !group->hasState(LLSpatialGroup::GEOM_DIRTY)) { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_VB); - LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); //make sure getgeometryvolume shows up in the right place in timers + { + LL_PROFILE_ZONE_NAMED("rebuildMesh - gen draw info"); - group->mBuilt = 1.f; + group->mBuilt = 1.f; - S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ; + S32 num_mapped_vertex_buffer = LLVertexBuffer::sMappedCount ; - const U32 MAX_BUFFER_COUNT = 4096; - LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT]; - - U32 buffer_count = 0; + const U32 MAX_BUFFER_COUNT = 4096; + LLVertexBuffer* locked_buffer[MAX_BUFFER_COUNT]; - for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) - { - LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); + U32 buffer_count = 0; - if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { - LLVOVolume* vobj = drawablep->getVOVolume(); - if (debugLoggingEnabled("AnimatedObjectsLinkset")) - { - if (vobj && vobj->isAnimatedObject() && vobj->isRiggedMesh()) - { - std::string vobj_name = llformat("Vol%p", vobj); - F32 est_tris = vobj->getEstTrianglesMax(); - LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL; - } - } - - if (!vobj || vobj->isNoLOD()) - { - continue; - } - - LLVolume* volume = vobj->getVolume(); + LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - if (!volume) - { - continue; - } + if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) ) + { + LLVOVolume* vobj = drawablep->getVOVolume(); + + if (!vobj) continue; + + if (debugLoggingEnabled("AnimatedObjectsLinkset")) + { + if (vobj->isAnimatedObject() && vobj->isRiggedMesh()) + { + std::string vobj_name = llformat("Vol%p", vobj); + F32 est_tris = vobj->getEstTrianglesMax(); + LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL; + } + } + if (vobj->isNoLOD()) continue; - vobj->preRebuild(); + vobj->preRebuild(); - if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) - { - vobj->updateRelativeXform(true); - } + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(true); + } - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) - { - LLFace* face = drawablep->getFace(i); - if (face) + LLVolume* volume = vobj->getVolume(); + if (!volume) continue; + for (S32 i = 0; i < drawablep->getNumFaces(); ++i) { - LLVertexBuffer* buff = face->getVertexBuffer(); - if (buff) + LLFace* face = drawablep->getFace(i); + if (face) { - llassert(!face->isState(LLFace::RIGGED)); + LLVertexBuffer* buff = face->getVertexBuffer(); + if (buff) + { + llassert(!face->isState(LLFace::RIGGED)); - if (!face->getGeometryVolume(*volume, face->getTEOffset(), - vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex())) - { //something's gone wrong with the vertex buffer accounting, rebuild this group - group->dirtyGeom(); - gPipeline.markRebuild(group, TRUE); - } + if (!face->getGeometryVolume(*volume, face->getTEOffset(), + vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex())) + { //something's gone wrong with the vertex buffer accounting, rebuild this group + group->dirtyGeom(); + gPipeline.markRebuild(group, TRUE); + } - if (buff->isLocked() && buffer_count < MAX_BUFFER_COUNT) - { - locked_buffer[buffer_count++] = buff; + if (buff->isLocked() && buffer_count < MAX_BUFFER_COUNT) + { + locked_buffer[buffer_count++] = buff; + } } } } + + if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + vobj->updateRelativeXform(); + } + + drawablep->clearState(LLDrawable::REBUILD_ALL); } + } - if (drawablep->isState(LLDrawable::ANIMATED_CHILD)) + { + LL_PROFILE_ZONE_NAMED("rebuildMesh - flush"); + for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter) { - vobj->updateRelativeXform(); + (*iter)->flush(); } - - drawablep->clearState(LLDrawable::REBUILD_ALL); + // don't forget alpha + if(group != NULL && + !group->mVertexBuffer.isNull() && + group->mVertexBuffer->isLocked()) + { + group->mVertexBuffer->flush(); + } } - } - - { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_MESH_FLUSH); - for (LLVertexBuffer** iter = locked_buffer, ** end_iter = locked_buffer+buffer_count; iter != end_iter; ++iter) - { - (*iter)->flush(); - } - - // don't forget alpha - if(group != NULL && - !group->mVertexBuffer.isNull() && - group->mVertexBuffer->isLocked()) - { - group->mVertexBuffer->flush(); - } - } - //if not all buffers are unmapped - if(num_mapped_vertex_buffer != LLVertexBuffer::sMappedCount) - { - LL_WARNS() << "Not all mapped vertex buffers are unmapped!" << LL_ENDL ; - for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) + //if not all buffers are unmapped + if(num_mapped_vertex_buffer != LLVertexBuffer::sMappedCount) { - LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); - if(!drawablep) - { - continue; - } - for (S32 i = 0; i < drawablep->getNumFaces(); ++i) + LL_WARNS() << "Not all mapped vertex buffers are unmapped!" << LL_ENDL ; + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { - LLFace* face = drawablep->getFace(i); - if (face) + LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); + if(!drawablep) { - LLVertexBuffer* buff = face->getVertexBuffer(); - if (buff && buff->isLocked()) + continue; + } + for (S32 i = 0; i < drawablep->getNumFaces(); ++i) + { + LLFace* face = drawablep->getFace(i); + if (face) { - buff->flush(); + LLVertexBuffer* buff = face->getVertexBuffer(); + if (buff && buff->isLocked()) + { + buff->flush(); + } } } } - } - } - - group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); - } + } -// llassert(!group || !group->isState(LLSpatialGroup::NEW_DRAWINFO)); + group->clearState(LLSpatialGroup::MESH_DIRTY | LLSpatialGroup::NEW_DRAWINFO); + } + } } -struct CompareBatchBreakerModified +struct CompareBatchBreaker { bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) { const LLTextureEntry* lte = lhs->getTextureEntry(); const LLTextureEntry* rte = rhs->getTextureEntry(); - if (lte->getBumpmap() != rte->getBumpmap()) + if (lte->getBumpmap() != rte->getBumpmap()) { return lte->getBumpmap() < rte->getBumpmap(); } @@ -6228,34 +6117,51 @@ struct CompareBatchBreakerModified { return lte->getFullbright() < rte->getFullbright(); } - else if (LLPipeline::sRenderDeferred && lte->getMaterialParams() != rte->getMaterialParams()) - { - return lte->getMaterialParams() < rte->getMaterialParams(); - } - else if (LLPipeline::sRenderDeferred && (lte->getMaterialParams() == rte->getMaterialParams()) && (lte->getShiny() != rte->getShiny())) + else if (LLPipeline::sRenderDeferred && lte->getMaterialID() != rte->getMaterialID()) + { + return lte->getMaterialID() < rte->getMaterialID(); + } + else if (lte->getShiny() != rte->getShiny()) { return lte->getShiny() < rte->getShiny(); } - else + else if (lhs->getTexture() != rhs->getTexture()) { return lhs->getTexture() < rhs->getTexture(); } + else + { + // all else being equal, maintain consistent draw order + return lhs->getDrawOrderIndex() < rhs->getDrawOrderIndex(); + } } }; -static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_SORT("Draw Info Face Sort"); -static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_FACE_SIZE("Face Sizing"); -static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_ALLOCATE("Allocate VB"); -static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_FIND_VB("Find VB"); -static LLTrace::BlockTimerStatHandle FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB"); - - - +struct CompareBatchBreakerRigged +{ + bool operator()(const LLFace* const& lhs, const LLFace* const& rhs) + { + if (lhs->mAvatar != rhs->mAvatar) + { + return lhs->mAvatar < rhs->mAvatar; + } + else if (lhs->mSkinInfo->mHash != rhs->mSkinInfo->mHash) + { + return lhs->mSkinInfo->mHash < rhs->mSkinInfo->mHash; + } + else + { + // "inherit" non-rigged behavior + CompareBatchBreaker comp; + return comp(lhs, rhs); + } + } +}; -U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL no_materials) +U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace** faces, U32 face_count, BOOL distance_sort, BOOL batch_textures, BOOL rigged) { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_VOLUME_GEN_DRAW_INFO); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; U32 geometryBytes = 0; U32 buffer_usage = group->mBufferUsage; @@ -6287,12 +6193,21 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace max_vertices = llmin(max_vertices, (U32) 65535); { - LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_SORT); - if (!distance_sort) - { - //sort faces by things that break batches - std::sort(faces, faces+face_count, CompareBatchBreakerModified()); - } + LL_PROFILE_ZONE_NAMED("genDrawInfo - sort"); + + if (rigged) + { + if (!distance_sort) // <--- alpha "sort" rigged faces by maintaining original draw order + { + //sort faces by things that break batches, including avatar and mesh id + std::sort(faces, faces + face_count, CompareBatchBreakerRigged()); + } + } + else if (!distance_sort) + { + //sort faces by things that break batches, not including avatar and mesh id + std::sort(faces, faces + face_count, CompareBatchBreaker()); + } else { //sort faces by distance @@ -6309,11 +6224,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace LLViewerTexture* last_tex = NULL; S32 buffer_index = 0; - if (distance_sort) - { - buffer_index = -1; - } - S32 texture_index_channels = 1; if (gGLManager.mGLSLVersionMajor > 1 || gGLManager.mGLSLVersionMinor >= 30) @@ -6325,6 +6235,11 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { texture_index_channels = gDeferredAlphaProgram.mFeatures.mIndexedTextureChannels; } + + if (distance_sort) + { + buffer_index = -1; + } static LLCachedControl<U32> max_texture_index(gSavedSettings, "RenderMaxTextureIndex", 16); texture_index_channels = llmin(texture_index_channels, (S32) max_texture_index); @@ -6339,7 +6254,9 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace //pull off next face LLFace* facep = *face_iter; LLViewerTexture* tex = facep->getTexture(); - LLMaterialPtr mat = facep->getTextureEntry()->getMaterialParams(); + const LLTextureEntry* te = facep->getTextureEntry(); + LLMaterialPtr mat = te->getMaterialParams(); + LLMaterialID matId = te->getMaterialID(); if (distance_sort) { @@ -6373,7 +6290,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace U32 texture_count = 0; { - LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_FACE_SIZE); + LL_PROFILE_ZONE_NAMED("genDrawInfo - face size"); if (batch_textures) { U8 cur_tex = 0; @@ -6462,11 +6379,14 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace while (i != end_faces && (LLPipeline::sTextureBindTest || (distance_sort || - ((*i)->getTexture() == tex && - ((*i)->getTextureEntry()->getMaterialParams() == mat))))) + ((*i)->getTexture() == tex)))) { facep = *i; - + const LLTextureEntry* nextTe = facep->getTextureEntry(); + if (nextTe->getMaterialID() != matId) + { + break; + } //face has no texture index facep->mDrawInfo = NULL; @@ -6496,7 +6416,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace LLPointer<LLVertexBuffer> buffer; { - LL_RECORD_BLOCK_TIME(FTM_GEN_DRAW_INFO_ALLOCATE); + LL_PROFILE_ZONE_NAMED("genDrawInfo - allocate"); buffer = createVertexBuffer(mask, buffer_usage); if(!buffer->allocateBuffer(geom_count, index_count, TRUE)) { @@ -6556,8 +6476,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace U32 te_idx = facep->getTEOffset(); - llassert(!facep->isState(LLFace::RIGGED)); - if (!facep->getGeometryVolume(*volume, te_idx, vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), index_offset,true)) { @@ -6654,10 +6572,6 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace } } } - else if (no_materials) - { - registerFace(group, facep, LLRenderPass::PASS_SIMPLE); - } else if (transparent) { registerFace(group, facep, LLRenderPass::PASS_ALPHA); @@ -6722,7 +6636,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { registerFace(group, facep, LLRenderPass::PASS_ALPHA); } - else if (gPipeline.canUseVertexShaders() + else if (gPipeline.shadersLoaded() && LLPipeline::sRenderBump && te->getShiny() && can_be_shiny) @@ -6757,7 +6671,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace registerFace(group, facep, LLRenderPass::PASS_ALPHA); } } - else if (gPipeline.canUseVertexShaders() + else if (gPipeline.shadersLoaded() && LLPipeline::sRenderBump && te->getShiny() && can_be_shiny) @@ -6838,7 +6752,7 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace } - if (!gPipeline.canUseVertexShaders() && + if (!gPipeline.shadersLoaded() && !is_alpha && te->getShiny() && LLPipeline::sRenderBump) @@ -6882,16 +6796,41 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace return geometryBytes; } +void LLVolumeGeometryManager::addGeometryCount(LLSpatialGroup* group, U32& vertex_count, U32& index_count) +{ + //initialize to default usage for this partition + U32 usage = group->getSpatialPartition()->mBufferUsage; + + //for each drawable + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) + { + LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); + + if (!drawablep || drawablep->isDead()) + { + continue; + } + + if (drawablep->isAnimating()) + { //fall back to stream draw for animating verts + usage = GL_STREAM_DRAW_ARB; + } + } + + group->mBufferUsage = usage; +} + void LLGeometryManager::addGeometryCount(LLSpatialGroup* group, U32 &vertex_count, U32 &index_count) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + //initialize to default usage for this partition U32 usage = group->getSpatialPartition()->mBufferUsage; - //clear off any old faces - mFaceList.clear(); + //clear off any old faces + mFaceList.clear(); //for each drawable - for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 73eeec813c..4cb7a5481c 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -295,6 +295,9 @@ public: BOOL setIsFlexible(BOOL is_flexible); const LLMeshSkinInfo* getSkinInfo() const; + + //convenience accessor for mesh ID (which is stored in sculpt id for legacy reasons) + const LLUUID& getMeshID() const { return getVolume()->getParams().getSculptID(); } // Extended Mesh Properties U32 getExtendedMeshFlags() const; @@ -410,6 +413,7 @@ private: S32 mLOD; BOOL mLODChanged; BOOL mSculptChanged; + BOOL mColorChanged; F32 mSpotLightPriority; LLMatrix4 mRelativeXform; LLMatrix3 mRelativeXformInvTrans; diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index 12def24a0d..089a7712c0 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -114,11 +114,9 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) return mDrawable; } -static LLTrace::BlockTimerStatHandle FTM_UPDATE_WATER("Update Water"); - BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_WATER); + LL_PROFILE_ZONE_SCOPED; LLFace *face; if (drawable->getNumFaces() < 1) @@ -145,7 +143,7 @@ BOOL LLVOWater::updateGeometry(LLDrawable *drawable) static const unsigned int vertices_per_quad = 4; static const unsigned int indices_per_quad = 6; - const S32 size = LLPipeline::sRenderTransparentWater && LLGLSLShader::sNoFixedFunction ? 16 : 1; + const S32 size = LLPipeline::sRenderTransparentWater ? 16 : 1; const S32 num_quads = size * size; face->setSize(vertices_per_quad * num_quads, diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp index d428cb1568..d1f584cbca 100644 --- a/indra/newview/llvowlsky.cpp +++ b/indra/newview/llvowlsky.cpp @@ -36,8 +36,8 @@ #include "llenvironment.h" #include "llsettingssky.h" -static const U32 MIN_SKY_DETAIL = 8; -static const U32 MAX_SKY_DETAIL = 180; +constexpr U32 MIN_SKY_DETAIL = 8; +constexpr U32 MAX_SKY_DETAIL = 180; inline U32 LLVOWLSky::getNumStacks(void) { @@ -97,13 +97,14 @@ LLDrawable * LLVOWLSky::createDrawable(LLPipeline * pipeline) return mDrawable; } -inline F32 LLVOWLSky::calcPhi(U32 i) +// a tiny helper function for controlling the sky dome tesselation. +inline F32 calcPhi(const U32 &i, const F32 &reciprocal_num_stacks) { // Calc: PI/8 * 1-((1-t^4)*(1-t^4)) { 0<t<1 } // Demos: \pi/8*\left(1-((1-x^{4})*(1-x^{4}))\right)\ \left\{0<x\le1\right\} // i should range from [0..SKY_STACKS] so t will range from [0.f .. 1.f] - F32 t = float(i) / float(getNumStacks()); + F32 t = float(i) * reciprocal_num_stacks; //SL-16127: remove: / float(getNumStacks()); // ^4 the parameter of the tesselation to bias things toward 0 (the dome's apex) t *= t; @@ -141,11 +142,9 @@ void LLVOWLSky::restoreGL() gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } -static LLTrace::BlockTimerStatHandle FTM_GEO_SKY("Windlight Sky Geometry"); - BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) { - LL_RECORD_BLOCK_TIME(FTM_GEO_SKY); + LL_PROFILE_ZONE_SCOPED; LLStrider<LLVector3> vertices; LLStrider<LLVector2> texCoords; LLStrider<U16> indices; @@ -189,6 +188,8 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) } { + const F32 dome_radius = LLEnvironment::instance().getCurrentSky()->getDomeRadius(); + const U32 max_buffer_bytes = gSavedSettings.getS32("RenderMaxVBOSize")*1024; const U32 data_mask = LLDrawPoolWLSky::SKY_VERTEX_DATA_MASK; const U32 max_verts = max_buffer_bytes / LLVertexBuffer::calcVertexSize(data_mask); @@ -204,12 +205,14 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) // round up to a whole number of segments const U32 strips_segments = (total_stacks+stacks_per_seg-1) / stacks_per_seg; - LL_INFOS() << "WL Skydome strips in " << strips_segments << " batches." << LL_ENDL; - mStripsVerts.resize(strips_segments, NULL); +#if RELEASE_SHOW_DEBUG + LL_INFOS() << "WL Skydome strips in " << strips_segments << " batches." << LL_ENDL; + LLTimer timer; timer.start(); +#endif for (U32 i = 0; i < strips_segments ;++i) { @@ -234,34 +237,42 @@ BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) const U32 num_indices_this_seg = 1+num_stacks_this_seg*(2+2*verts_per_stack); llassert(num_indices_this_seg * sizeof(U16) <= max_buffer_bytes); - if (!segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE)) + bool allocated = segment->allocateBuffer(num_verts_this_seg, num_indices_this_seg, TRUE); +#if RELEASE_SHOW_WARNS + if( !allocated ) { LL_WARNS() << "Failed to allocate Vertex Buffer on update to " << num_verts_this_seg << " vertices and " << num_indices_this_seg << " indices" << LL_ENDL; } +#else + (void) allocated; +#endif // lock the buffer BOOL success = segment->getVertexStrider(vertices) && segment->getTexCoord0Strider(texCoords) && segment->getIndexStrider(indices); - if(!success) +#if RELEASE_SHOW_DEBUG + if(!success) { LL_ERRS() << "Failed updating WindLight sky geometry." << LL_ENDL; } - - U32 vertex_count = 0; - U32 index_count = 0; +#else + (void) success; +#endif // fill it - buildStripsBuffer(begin_stack, end_stack, vertex_count, index_count, vertices, texCoords, indices); + buildStripsBuffer(begin_stack, end_stack, vertices, texCoords, indices, dome_radius, verts_per_stack, total_stacks); // and unlock the buffer segment->flush(); } +#if RELEASE_SHOW_DEBUG LL_INFOS() << "completed in " << llformat("%.2f", timer.getElapsedTimeF32().value()) << "seconds" << LL_ENDL; +#endif } updateStarColors(); @@ -366,23 +377,16 @@ void LLVOWLSky::initStars() void LLVOWLSky::buildStripsBuffer(U32 begin_stack, U32 end_stack, - U32& vertex_count, - U32& index_count, - LLStrider<LLVector3> & vertices, - LLStrider<LLVector2> & texCoords, - LLStrider<U16> & indices) + LLStrider<LLVector3> & vertices, + LLStrider<LLVector2> & texCoords, + LLStrider<U16> & indices, + const F32 dome_radius, + const U32& num_slices, + const U32& num_stacks) { - const F32 RADIUS = LLEnvironment::instance().getCurrentSky()->getDomeRadius(); - - U32 i, j, num_slices, num_stacks; + U32 i, j; F32 phi0, theta, x0, y0, z0; - - // paranoia checking for SL-55986/SL-55833 - U32 count_verts = 0; - U32 count_indices = 0; - - num_slices = getNumSlices(); - num_stacks = getNumStacks(); + const F32 reciprocal_num_stacks = 1.f / num_stacks; llassert(end_stack <= num_stacks); @@ -393,7 +397,7 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, for(i = begin_stack + 1; i <= end_stack+1; ++i) #endif { - phi0 = calcPhi(i); + phi0 = calcPhi(i, reciprocal_num_stacks); for(j = 0; j < num_slices; ++j) { @@ -406,24 +410,22 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, z0 = sin(phi0) * sin(theta); #if NEW_TESS - *vertices++ = LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS); + *vertices++ = LLVector3(x0 * dome_radius, y0 * dome_radius, z0 * dome_radius); #else if (i == num_stacks-2) { - *vertices++ = LLVector3(x0*RADIUS, y0*RADIUS-1024.f*2.f, z0*RADIUS); + *vertices++ = LLVector3(x0*dome_radius, y0*dome_radius-1024.f*2.f, z0*dome_radius); } else if (i == num_stacks-1) { - *vertices++ = LLVector3(0, y0*RADIUS-1024.f*2.f, 0); + *vertices++ = LLVector3(0, y0*dome_radius-1024.f*2.f, 0); } else { - *vertices++ = LLVector3(x0 * RADIUS, y0 * RADIUS, z0 * RADIUS); + *vertices++ = LLVector3(x0 * dome_radius, y0 * dome_radius, z0 * dome_radius); } #endif - ++count_verts; - // generate planar uv coordinates // note: x and z are transposed in order for things to animate // correctly in the global coordinate system where +x is east and @@ -434,12 +436,11 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, //build triangle strip... *indices++ = 0 ; - count_indices++ ; + S32 k = 0 ; for(i = 1; i <= end_stack - begin_stack; ++i) { *indices++ = i * num_slices + k ; - count_indices++ ; k = (k+1) % num_slices ; for(j = 0; j < num_slices ; ++j) @@ -447,8 +448,6 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, *indices++ = (i-1) * num_slices + k ; *indices++ = i * num_slices + k ; - count_indices += 2 ; - k = (k+1) % num_slices ; } @@ -458,11 +457,7 @@ void LLVOWLSky::buildStripsBuffer(U32 begin_stack, } *indices++ = i * num_slices + k ; - count_indices++ ; } - - vertex_count = count_verts; - index_count = count_indices; } void LLVOWLSky::updateStarColors() diff --git a/indra/newview/llvowlsky.h b/indra/newview/llvowlsky.h index 2b7ebe75dd..3853dd2c70 100644 --- a/indra/newview/llvowlsky.h +++ b/indra/newview/llvowlsky.h @@ -55,8 +55,6 @@ public: void restoreGL(); private: - // a tiny helper function for controlling the sky dome tesselation. - static F32 calcPhi(U32 i); // helper function for initializing the stars. void initStars(); @@ -66,11 +64,12 @@ private: // begin_stack is the first stack to be included, end_stack is the first // stack not to be included. static void buildStripsBuffer(U32 begin_stack, U32 end_stack, - U32& vertex_count, - U32& index_count, - LLStrider<LLVector3> & vertices, - LLStrider<LLVector2> & texCoords, - LLStrider<U16> & indices); + LLStrider<LLVector3> & vertices, + LLStrider<LLVector2> & texCoords, + LLStrider<U16> & indices, + const F32 RADIUS, + const U32& num_slices, + const U32& num_stacks); // helper function for updating the stars colors. void updateStarColors(); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 81511ac555..8abb49fba8 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -113,7 +113,7 @@ LLWorld::LLWorld() : } -void LLWorld::destroyClass() +void LLWorld::resetClass() { mHoleWaterObjects.clear(); gObjectList.destroy(); @@ -884,6 +884,7 @@ void LLWorld::waterHeightRegionInfo(std::string const& sim_name, F32 water_heigh void LLWorld::precullWaterObjects(LLCamera& camera, LLCullResult* cull, bool include_void_water) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; if (!gAgent.getRegion()) { return; @@ -1077,6 +1078,7 @@ void LLWorld::updateWaterObjects() void LLWorld::shiftRegions(const LLVector3& offset) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; for (region_list_t::const_iterator i = getRegionList().begin(); i != getRegionList().end(); ++i) { LLViewerRegion* region = *i; @@ -1147,11 +1149,9 @@ void LLWorld::disconnectRegions() } } -static LLTrace::BlockTimerStatHandle FTM_ENABLE_SIMULATOR("Enable Sim"); - void process_enable_simulator(LLMessageSystem *msg, void **user_data) { - LL_RECORD_BLOCK_TIME(FTM_ENABLE_SIMULATOR); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; // enable the appropriate circuit for this simulator and // add its values into the gSimulator structure U64 handle; @@ -1237,12 +1237,11 @@ public: } }; -static LLTrace::BlockTimerStatHandle FTM_DISABLE_REGION("Disable Region"); // disable the circuit to this simulator // Called in response to "DisableSimulator" message. void process_disable_simulator(LLMessageSystem *mesgsys, void **user_data) { - LL_RECORD_BLOCK_TIME(FTM_DISABLE_REGION); + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK; LLHost host = mesgsys->getSender(); @@ -1304,6 +1303,7 @@ void send_agent_pause() void send_agent_resume() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_NETWORK // Note: used to check for LLWorld initialization before it became a singleton. // Rather than just remove this check I'm changing it to assure that the message // system has been initialized. -MG diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 98552bc4d1..5c43cdf4e2 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -59,11 +59,14 @@ class LLVOAvatar; // as simulators are connected to, viewer_regions are popped off the stack and connected as required // as simulators are removed, they are pushed back onto the stack -class LLWorld : public LLSingleton<LLWorld> +class LLWorld : public LLSimpleton<LLWorld> { - LLSINGLETON(LLWorld); public: - void destroyClass(); + LLWorld(); + + // Clear any objects, regions + // Prepares class to be reused or destroyed + void resetClass(); LLViewerRegion* addRegion(const U64 ®ion_handle, const LLHost &host); // safe to call if already present, does the "right thing" if diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp index 8be340de4c..e4a9f9afdb 100644 --- a/indra/newview/llworldmapmessage.cpp +++ b/indra/newview/llworldmapmessage.cpp @@ -150,6 +150,10 @@ void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 // public static void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) { + if (gNonInteractive) + { + return; + } U32 agent_flags; msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index a6df079223..59ac4554d7 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -321,22 +321,19 @@ void LLWorldMapView::draw() // Clear the background alpha to 0 gGL.flush(); gGL.setColorMask(false, true); - gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f); + gGL.flush(); gGL.setSceneBlendType(LLRender::BT_REPLACE); gGL.color4f(0.0f, 0.0f, 0.0f, 0.0f); gl_rect_2d(0, height, width, 0); } gGL.flush(); - - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.setColorMask(true, true); // Draw the image tiles drawMipmap(width, height); gGL.flush(); - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.setColorMask(true, true); // Draw per sim overlayed information (names, mature, offline...) @@ -480,13 +477,13 @@ void LLWorldMapView::draw() LLGLSUIDefault gls_ui; { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f); + gGL.flush(); gGL.blendFunc(LLRender::BF_ONE_MINUS_DEST_ALPHA, LLRender::BF_DEST_ALPHA); gGL.color4fv( mBackgroundColor.mV ); gl_rect_2d(0, height, width, 0); } - gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.flush(); gGL.setSceneBlendType(LLRender::BT_ALPHA); // Draw item infos if we're not zoomed out too much and there's something to draw diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index d797b64731..20d6fe39e3 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -142,7 +142,6 @@ bool gShiftFrame = false; //cached settings -bool LLPipeline::RenderAvatarVP; bool LLPipeline::WindLightUseAtmosShaders; bool LLPipeline::RenderDeferred; F32 LLPipeline::RenderDeferredSunWash; @@ -238,7 +237,6 @@ const LLMatrix4* gGLLastMatrix = NULL; LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY("Render Geometry"); LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS("Grass"); LLTrace::BlockTimerStatHandle FTM_RENDER_INVISIBLE("Invisible"); -LLTrace::BlockTimerStatHandle FTM_RENDER_OCCLUSION("Occlusion"); LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY("Shiny"); LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE("Simple"); LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN("Terrain"); @@ -253,14 +251,12 @@ LLTrace::BlockTimerStatHandle FTM_RENDER_MATERIALS("Render Materials"); LLTrace::BlockTimerStatHandle FTM_RENDER_FULLBRIGHT("Fullbright"); LLTrace::BlockTimerStatHandle FTM_RENDER_GLOW("Glow"); LLTrace::BlockTimerStatHandle FTM_GEO_UPDATE("Geo Update"); -LLTrace::BlockTimerStatHandle FTM_PIPELINE_CREATE("Pipeline Create"); LLTrace::BlockTimerStatHandle FTM_POOLRENDER("RenderPool"); LLTrace::BlockTimerStatHandle FTM_POOLS("Pools"); LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLRENDER("RenderPool (Deferred)"); LLTrace::BlockTimerStatHandle FTM_DEFERRED_POOLS("Pools (Deferred)"); LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLRENDER("RenderPool (Post)"); LLTrace::BlockTimerStatHandle FTM_POST_DEFERRED_POOLS("Pools (Post)"); -LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM_FBO("First FBO"); LLTrace::BlockTimerStatHandle FTM_STATESORT("Sort Draw State"); LLTrace::BlockTimerStatHandle FTM_PIPELINE("Pipeline"); LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY("Client Copy"); @@ -269,11 +265,8 @@ LLTrace::BlockTimerStatHandle FTM_RENDER_DEFERRED("Deferred Shading"); LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD("HUD"); LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D("3D"); LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D("2D"); -LLTrace::BlockTimerStatHandle FTM_RENDER_UI_DEBUG_TEXT("Debug Text"); -LLTrace::BlockTimerStatHandle FTM_RENDER_UI_SCENE_MON("Scene Mon"); static LLTrace::BlockTimerStatHandle FTM_STATESORT_DRAWABLE("Sort Drawables"); -static LLTrace::BlockTimerStatHandle FTM_STATESORT_POSTSORT("Post Sort"); static LLStaticHashedString sTint("tint"); static LLStaticHashedString sAmbiance("ambiance"); @@ -338,7 +331,6 @@ S32 LLPipeline::sUseOcclusion = 0; bool LLPipeline::sDelayVBUpdate = true; bool LLPipeline::sAutoMaskAlphaDeferred = true; bool LLPipeline::sAutoMaskAlphaNonDeferred = false; -bool LLPipeline::sDisableShaders = false; bool LLPipeline::sRenderTransparentWater = true; bool LLPipeline::sRenderBump = true; bool LLPipeline::sBakeSunlight = false; @@ -359,7 +351,6 @@ bool LLPipeline::sRenderAttachedLights = true; bool LLPipeline::sRenderAttachedParticles = true; bool LLPipeline::sRenderDeferred = false; S32 LLPipeline::sVisibleLightCount = 0; -F32 LLPipeline::sMinRenderSize = 0.f; bool LLPipeline::sRenderingHUDs; F32 LLPipeline::sDistortionWaterClipPlaneMargin = 1.0125f; @@ -370,10 +361,12 @@ static LLCullResult* sCull = NULL; void validate_framebuffer_object(); - -bool addDeferredAttachments(LLRenderTarget& target) +// Add color attachments for deferred rendering +// target -- RenderTarget to add attachments to +// for_impostor -- whether or not these render targets are for an impostor (if true, avoids implicit sRGB conversions) +bool addDeferredAttachments(LLRenderTarget& target, bool for_impostor = false) { - return target.addColorAttachment(GL_SRGB8_ALPHA8) && //specular + return target.addColorAttachment(for_impostor ? GL_RGBA : GL_SRGB8_ALPHA8) && //specular target.addColorAttachment(GL_RGB10_A2); //normal+z } @@ -385,8 +378,7 @@ LLPipeline::LLPipeline() : mNumVisibleFaces(0), mInitialized(false), - mVertexShadersEnabled(false), - mVertexShadersLoaded(0), + mShadersLoaded(false), mTransformFeedbackPrimitives(0), mRenderDebugFeatureMask(0), mRenderDebugMask(0), @@ -487,6 +479,10 @@ void LLPipeline::init() { clearAllRenderTypes(); } + else if (gNonInteractive) + { + clearAllRenderTypes(); + } else { setAllRenderTypes(); // By default, all rendering types start enabled @@ -541,7 +537,6 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("RenderAvatarMaxNonImpostors"); connectRefreshCachedSettingsSafe("RenderDelayVBUpdate"); connectRefreshCachedSettingsSafe("UseOcclusion"); - connectRefreshCachedSettingsSafe("RenderAvatarVP"); connectRefreshCachedSettingsSafe("WindLightUseAtmosShaders"); connectRefreshCachedSettingsSafe("RenderDeferred"); connectRefreshCachedSettingsSafe("RenderDeferredSunWash"); @@ -725,8 +720,6 @@ void LLPipeline::destroyGL() } } -static LLTrace::BlockTimerStatHandle FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture"); - void LLPipeline::requestResizeScreenTexture() { gResizeScreenTexture = TRUE; @@ -746,8 +739,7 @@ void LLPipeline::resizeShadowTexture() void LLPipeline::resizeScreenTexture() { - LL_RECORD_BLOCK_TIME(FTM_RESIZE_SCREEN_TEXTURE); - if (gPipeline.canUseVertexShaders() && assertInitialized()) + if (gPipeline.shadersLoaded()) { GLuint resX = gViewerWindow->getWorldViewWidthRaw(); GLuint resY = gViewerWindow->getWorldViewHeightRaw(); @@ -758,8 +750,8 @@ void LLPipeline::resizeScreenTexture() releaseShadowTargets(); allocateScreenBuffer(resX,resY); gResizeScreenTexture = FALSE; - } - } + } + } } void LLPipeline::allocatePhysicsBuffer() @@ -900,7 +892,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (!addDeferredAttachments(mDeferredScreen)) return false; GLuint screenFormat = GL_RGBA16; - if (gGLManager.mIsATI) + if (gGLManager.mIsAMD) { screenFormat = GL_RGBA12; } @@ -1054,8 +1046,6 @@ void LLPipeline::updateRenderDeferred() RenderDeferred && LLRenderTarget::sUseFBO && LLPipeline::sRenderBump && - LLPipeline::sRenderTransparentWater && - RenderAvatarVP && WindLightUseAtmosShaders && (bool) LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"); } @@ -1072,12 +1062,10 @@ void LLPipeline::refreshCachedSettings() LLPipeline::sUseOcclusion = (!gUseWireframe - && LLGLSLShader::sNoFixedFunction && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) ? 2 : 0; - RenderAvatarVP = gSavedSettings.getBOOL("RenderAvatarVP"); WindLightUseAtmosShaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); RenderDeferred = gSavedSettings.getBOOL("RenderDeferred"); RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash"); @@ -1153,6 +1141,12 @@ void LLPipeline::refreshCachedSettings() RenderAutoHideSurfaceAreaLimit = gSavedSettings.getF32("RenderAutoHideSurfaceAreaLimit"); RenderSpotLight = nullptr; updateRenderDeferred(); + + if (gNonInteractive) + { + LLVOAvatar::sMaxNonImpostors = 1; + LLVOAvatar::updateImpostorRendering(LLVOAvatar::sMaxNonImpostors); + } } void LLPipeline::releaseGLBuffers() @@ -1232,7 +1226,8 @@ void LLPipeline::releaseShadowTargets() void LLPipeline::createGLBuffers() { - stop_glerror(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + stop_glerror(); assertInitialized(); updateRenderDeferred(); @@ -1370,10 +1365,7 @@ void LLPipeline::restoreGL() { assertInitialized(); - if (mVertexShadersEnabled) - { - LLViewerShaderMgr::instance()->setShaders(); - } + LLViewerShaderMgr::instance()->setShaders(); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -1385,31 +1377,19 @@ void LLPipeline::restoreGL() if (part) { part->restoreGL(); - } + } } } } - -bool LLPipeline::canUseVertexShaders() +bool LLPipeline::shadersLoaded() { - if (sDisableShaders || - !gGLManager.mHasVertexShader || - !gGLManager.mHasFragmentShader || - (assertInitialized() && mVertexShadersLoaded != 1) ) - { - return false; - } - else - { - return true; - } + return (assertInitialized() && mShadersLoaded); } bool LLPipeline::canUseWindLightShaders() const { - return (!LLPipeline::sDisableShaders && - gWLSkyProgram.mProgramObject != 0 && + return (gWLSkyProgram.mProgramObject != 0 && LLViewerShaderMgr::instance()->getShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1); } @@ -1427,8 +1407,7 @@ bool LLPipeline::canUseAntiAliasing() const void LLPipeline::unloadShaders() { LLViewerShaderMgr::instance()->unloadShaders(); - - mVertexShadersLoaded = 0; + mShadersLoaded = false; } void LLPipeline::assertInitializedDoError() @@ -1514,6 +1493,7 @@ public: // Called when a texture changes # of channels (causes faces to move to alpha pool) void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; assertInitialized(); // *TODO: This is inefficient and causes frame spikes; need a better way to do this @@ -1725,15 +1705,9 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj) } -static LLTrace::BlockTimerStatHandle FTM_UNLINK("Unlink"); -static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_MOVE_LIST("Movelist"); -static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition"); -static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_LIGHT_SET("Light Set"); -static LLTrace::BlockTimerStatHandle FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set"); - void LLPipeline::unlinkDrawable(LLDrawable *drawable) { - LL_RECORD_BLOCK_TIME(FTM_UNLINK); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; assertInitialized(); @@ -1742,7 +1716,6 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) // Based on flags, remove the drawable from the queues that it's on. if (drawablep->isState(LLDrawable::ON_MOVE_LIST)) { - LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_MOVE_LIST); LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep); if (iter != mMovedList.end()) { @@ -1752,7 +1725,6 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) if (drawablep->getSpatialGroup()) { - LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_SPATIAL_PARTITION); if (!drawablep->getSpatialGroup()->getSpatialPartition()->remove(drawablep, drawablep->getSpatialGroup())) { #ifdef LL_RELEASE_FOR_DOWNLOAD @@ -1763,30 +1735,24 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) } } - { - LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_LIGHT_SET); - mLights.erase(drawablep); + mLights.erase(drawablep); - for (light_set_t::iterator iter = mNearbyLights.begin(); - iter != mNearbyLights.end(); iter++) + for (light_set_t::iterator iter = mNearbyLights.begin(); + iter != mNearbyLights.end(); iter++) + { + if (iter->drawable == drawablep) { - if (iter->drawable == drawablep) - { - mNearbyLights.erase(iter); - break; - } + mNearbyLights.erase(iter); + break; } } - { - LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_HIGHLIGHT_SET); - HighlightItem item(drawablep); - mHighlightSet.erase(item); + HighlightItem item(drawablep); + mHighlightSet.erase(item); - if (mHighlightObject == drawablep) - { - mHighlightObject = NULL; - } + if (mHighlightObject == drawablep) + { + mHighlightObject = NULL; } for (U32 i = 0; i < 2; ++i) @@ -1801,14 +1767,12 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) mTargetShadowSpotLight[i] = NULL; } } - - } //static void LLPipeline::removeMutedAVsLights(LLVOAvatar* muted_avatar) { - LL_RECORD_BLOCK_TIME(FTM_REMOVE_FROM_LIGHT_SET); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; for (light_set_t::iterator iter = gPipeline.mNearbyLights.begin(); iter != gPipeline.mNearbyLights.end(); iter++) { @@ -1836,7 +1800,7 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) void LLPipeline::createObjects(F32 max_dtime) { - LL_RECORD_BLOCK_TIME(FTM_PIPELINE_CREATE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; LLTimer update_timer; @@ -1860,6 +1824,7 @@ void LLPipeline::createObjects(F32 max_dtime) void LLPipeline::createObject(LLViewerObject* vobj) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; LLDrawable* drawablep = vobj->mDrawable; if (!drawablep) @@ -1897,6 +1862,7 @@ void LLPipeline::createObject(LLViewerObject* vobj) void LLPipeline::resetFrameStats() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; assertInitialized(); sCompiles = 0; @@ -1912,6 +1878,7 @@ void LLPipeline::resetFrameStats() //external functions for asynchronous updating void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep) { + LL_PROFILE_ZONE_SCOPED; if (FreezeTime) { return; @@ -1942,6 +1909,7 @@ void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep) void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep) { + LL_PROFILE_ZONE_SCOPED; if (FreezeTime) { return; @@ -1972,6 +1940,7 @@ void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep) void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) { + LL_PROFILE_ZONE_SCOPED; for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin(); iter != moved_list.end(); ) { @@ -2005,14 +1974,9 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) } } -static LLTrace::BlockTimerStatHandle FTM_OCTREE_BALANCE("Balance Octree"); -static LLTrace::BlockTimerStatHandle FTM_UPDATE_MOVE("Update Move"); -static LLTrace::BlockTimerStatHandle FTM_RETEXTURE("Retexture"); -static LLTrace::BlockTimerStatHandle FTM_MOVED_LIST("Moved List"); - void LLPipeline::updateMove() { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_MOVE); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; if (FreezeTime) { @@ -2021,49 +1985,38 @@ void LLPipeline::updateMove() assertInitialized(); + for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); + iter != mRetexturedList.end(); ++iter) { - LL_RECORD_BLOCK_TIME(FTM_RETEXTURE); - - for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin(); - iter != mRetexturedList.end(); ++iter) + LLDrawable* drawablep = *iter; + if (drawablep && !drawablep->isDead()) { - LLDrawable* drawablep = *iter; - if (drawablep && !drawablep->isDead()) - { - drawablep->updateTexture(); - } + drawablep->updateTexture(); } - mRetexturedList.clear(); } + mRetexturedList.clear(); - { - LL_RECORD_BLOCK_TIME(FTM_MOVED_LIST); - updateMovedList(mMovedList); - } + updateMovedList(mMovedList); //balance octrees + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { - LL_RECORD_BLOCK_TIME(FTM_OCTREE_BALANCE); - - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->mOctree->balance(); - } + part->mOctree->balance(); } + } - //balance the VO Cache tree - LLVOCachePartition* vo_part = region->getVOCachePartition(); - if(vo_part) - { - vo_part->mOctree->balance(); - } + //balance the VO Cache tree + LLVOCachePartition* vo_part = region->getVOCachePartition(); + if(vo_part) + { + vo_part->mOctree->balance(); } } } @@ -2125,6 +2078,7 @@ void LLPipeline::grabReferences(LLCullResult& result) void LLPipeline::clearReferences() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; sCull = NULL; mGroupSaveQ1.clear(); } @@ -2372,20 +2326,28 @@ bool LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling"); -void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip, LLPlane* planep) +void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, LLPlane* planep) { static LLCachedControl<bool> use_occlusion(gSavedSettings,"UseOcclusion"); - static bool can_use_occlusion = LLGLSLShader::sNoFixedFunction - && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") + static bool can_use_occlusion = LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && gGLManager.mHasOcclusionQuery; - LL_RECORD_BLOCK_TIME(FTM_CULL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_CULL); + + if (planep != nullptr) + { + camera.setUserClipPlane(*planep); + } + else + { + camera.disableUserClipPlane(); + } grabReferences(result); sCull->clear(); - bool to_texture = LLPipeline::sUseOcclusion > 1 && gPipeline.canUseVertexShaders(); + bool to_texture = LLPipeline::sUseOcclusion > 1 && gPipeline.shadersLoaded(); if (to_texture) { @@ -2419,7 +2381,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl LLGLDepthTest depth(GL_TRUE, GL_FALSE); bool bound_shader = false; - if (gPipeline.canUseVertexShaders() && LLGLSLShader::sCurBoundShader == 0) + if (gPipeline.shadersLoaded() && LLGLSLShader::sCurBoundShader == 0) { //if no shader is currently bound, use the occlusion shader instead of fixed function if we can // (shadow render uses a special shader that clamps to clip planes) bound_shader = true; @@ -2435,11 +2397,6 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX); } - if (!sReflectionRender) - { - camera.disableUserClipPlane(); - } - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { @@ -2461,8 +2418,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl LLVOCachePartition* vo_part = region->getVOCachePartition(); if(vo_part) { - bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe && 0 > water_clip /* && !gViewerWindow->getProgressView()->getVisible()*/; - do_occlusion_cull &= !sReflectionRender; + bool do_occlusion_cull = can_use_occlusion && use_occlusion && !gUseWireframe; vo_part->cull(camera, do_occlusion_cull); } } @@ -2546,20 +2502,6 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera) group->updateDistance(camera); } - const F32 MINIMUM_PIXEL_AREA = 16.f; - - if (group->mPixelArea < MINIMUM_PIXEL_AREA) - { - return; - } - - const LLVector4a* bounds = group->getBounds(); - if (sMinRenderSize > 0.f && - llmax(llmax(bounds[1][0], bounds[1][1]), bounds[1][2]) < sMinRenderSize) - { - return; - } - assertInitialized(); if (!group->getSpatialPartition()->mRenderByGroup) @@ -2669,7 +2611,8 @@ void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderT void LLPipeline::doOcclusion(LLCamera& camera) { - if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + if (LLPipeline::sUseOcclusion > 1 && !LLSpatialPartition::sTeleportRequested && (sCull->hasOcclusionGroups() || LLVOCachePartition::sNeedsOcclusionCheck)) { LLVertexBuffer::unbind(); @@ -2690,7 +2633,7 @@ void LLPipeline::doOcclusion(LLCamera& camera) LLGLDisable cull(GL_CULL_FACE); - bool bind_shader = LLGLSLShader::sNoFixedFunction && LLGLSLShader::sCurBoundShader == 0; + bool bind_shader = (LLGLSLShader::sCurBoundShader == 0); if (bind_shader) { if (LLPipeline::sShadowRender) @@ -2753,14 +2696,10 @@ bool LLPipeline::updateDrawableGeom(LLDrawable* drawablep, bool priority) return update_complete; } -static LLTrace::BlockTimerStatHandle FTM_SEED_VBO_POOLS("Seed VBO Pool"); - -static LLTrace::BlockTimerStatHandle FTM_UPDATE_GL("Update GL"); - void LLPipeline::updateGL() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; { - LL_RECORD_BLOCK_TIME(FTM_UPDATE_GL); while (!LLGLUpdate::sGLQ.empty()) { LLGLUpdate* glu = LLGLUpdate::sGLQ.front(); @@ -2771,15 +2710,13 @@ void LLPipeline::updateGL() } { //seed VBO Pools - LL_RECORD_BLOCK_TIME(FTM_SEED_VBO_POOLS); LLVertexBuffer::seedPools(); } } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_PRIORITY_GROUPS("Rebuild Priority Groups"); - void LLPipeline::clearRebuildGroups() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; LLSpatialGroup::sg_vector_t hudGroups; mGroupQ1Locked = true; @@ -2884,7 +2821,7 @@ void LLPipeline::clearRebuildDrawables() void LLPipeline::rebuildPriorityGroups() { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_PRIORITY_GROUPS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; LLTimer update_timer; assertInitialized(); @@ -2906,8 +2843,6 @@ void LLPipeline::rebuildPriorityGroups() } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_GROUPS("Rebuild Groups"); - void LLPipeline::rebuildGroups() { if (mGroupQ2.empty()) @@ -2915,7 +2850,7 @@ void LLPipeline::rebuildGroups() return; } - LL_RECORD_BLOCK_TIME(FTM_REBUILD_GROUPS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; mGroupQ2Locked = true; // Iterate through some drawables on the non-priority build queue S32 size = (S32) mGroupQ2.size(); @@ -3161,12 +3096,9 @@ void LLPipeline::markShift(LLDrawable *drawablep) } } -static LLTrace::BlockTimerStatHandle FTM_SHIFT_DRAWABLE("Shift Drawable"); -static LLTrace::BlockTimerStatHandle FTM_SHIFT_OCTREE("Shift Octree"); -static LLTrace::BlockTimerStatHandle FTM_SHIFT_HUD("Shift HUD"); - void LLPipeline::shiftObjects(const LLVector3 &offset) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; assertInitialized(); glClear(GL_DEPTH_BUFFER_BIT); @@ -3175,46 +3107,36 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) LLVector4a offseta; offseta.load3(offset.mV); + for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); + iter != mShiftList.end(); iter++) { - LL_RECORD_BLOCK_TIME(FTM_SHIFT_DRAWABLE); - - for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin(); - iter != mShiftList.end(); iter++) + LLDrawable *drawablep = *iter; + if (drawablep->isDead()) { - LLDrawable *drawablep = *iter; - if (drawablep->isDead()) - { - continue; - } - drawablep->shiftPos(offseta); - drawablep->clearState(LLDrawable::ON_SHIFT_LIST); - } - mShiftList.resize(0); + continue; + } + drawablep->shiftPos(offseta); + drawablep->clearState(LLDrawable::ON_SHIFT_LIST); } - + mShiftList.resize(0); + for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { - LL_RECORD_BLOCK_TIME(FTM_SHIFT_OCTREE); - for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); - iter != LLWorld::getInstance()->getRegionList().end(); ++iter) + LLViewerRegion* region = *iter; + for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) { - LLViewerRegion* region = *iter; - for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++) + LLSpatialPartition* part = region->getSpatialPartition(i); + if (part) { - LLSpatialPartition* part = region->getSpatialPartition(i); - if (part) - { - part->shift(offseta); - } + part->shift(offseta); } } } - { - LL_RECORD_BLOCK_TIME(FTM_SHIFT_HUD); - LLHUDText::shiftAll(offset); - LLHUDNameTag::shiftAll(offset); - } + LLHUDText::shiftAll(offset); + LLHUDNameTag::shiftAll(offset); + display_update_camera(); } @@ -3245,10 +3167,9 @@ void LLPipeline::markPartitionMove(LLDrawable* drawable) } } -static LLTrace::BlockTimerStatHandle FTM_PROCESS_PARTITIONQ("PartitionQ"); void LLPipeline::processPartitionQ() { - LL_RECORD_BLOCK_TIME(FTM_PROCESS_PARTITIONQ); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; for (LLDrawable::drawable_list_t::iterator iter = mPartitionQ.begin(); iter != mPartitionQ.end(); ++iter) { LLDrawable* drawable = *iter; @@ -3348,10 +3269,10 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f } } -static LLTrace::BlockTimerStatHandle FTM_RESET_DRAWORDER("Reset Draw Order"); - void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::RENDER_TYPE_CONTROL_AV, LLPipeline::RENDER_TYPE_GROUND, @@ -3363,12 +3284,9 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) LLPipeline::END_RENDER_TYPES)) { //clear faces from face pools - LL_RECORD_BLOCK_TIME(FTM_RESET_DRAWORDER); gPipeline.resetDrawOrders(); } - LL_RECORD_BLOCK_TIME(FTM_STATESORT); - //LLVertexBuffer::unbind(); grabReferences(result); @@ -3453,7 +3371,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } { - LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE); + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWABLE("stateSort"); // LL_RECORD_BLOCK_TIME(FTM_STATESORT_DRAWABLE); for (LLCullResult::drawable_iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) { @@ -3483,12 +3401,12 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) group->mLastUpdateDistance = group->mDistance; } } - } void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed) { - if (bridge->getSpatialGroup()->changeLOD() || fov_changed) + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + if (bridge->getSpatialGroup()->changeLOD() || fov_changed) { bool force_update = false; bridge->updateDistance(camera, force_update); @@ -3497,7 +3415,8 @@ void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_c void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) { - if (!drawablep + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + if (!drawablep || drawablep->isDead() || !hasRenderType(drawablep->getRenderType())) { @@ -3790,9 +3709,36 @@ void renderSoundHighlights(LLDrawable* drawablep) } } +void LLPipeline::touchTexture(LLViewerTexture* tex, F32 vsize) +{ + if (tex) + { + LLImageGL* gl_tex = tex->getGLTexture(); + if (gl_tex && gl_tex->updateBindStats(gl_tex->mTextureMemory)) + { + tex->setActive(); + tex->addTextureStats(vsize); + } + } + + +} +void LLPipeline::touchTextures(LLDrawInfo* info) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + for (int i = 0; i < info->mTextureList.size(); ++i) + { + touchTexture(info->mTextureList[i], info->mTextureListVSize[i]); + } + + touchTexture(info->mTexture, info->mVSize); + touchTexture(info->mSpecularMap, info->mVSize); + touchTexture(info->mNormalMap, info->mVSize); +} + void LLPipeline::postSort(LLCamera& camera) { - LL_RECORD_BLOCK_TIME(FTM_STATESORT_POSTSORT); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; assertInitialized(); @@ -3842,20 +3788,14 @@ void LLPipeline::postSort(LLCamera& camera) for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k) { - if (sMinRenderSize > 0.f) - { - LLVector4a bounds; - bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]); - - if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize) - { - sCull->pushDrawInfo(j->first, *k); - } - } - else - { - sCull->pushDrawInfo(j->first, *k); - } + LLDrawInfo* info = *k; + + sCull->pushDrawInfo(j->first, info); + if (!sShadowRender && !sReflectionRender) + { + touchTextures(info); + addTrianglesDrawn(info->mCount, info->mDrawMode); + } } } @@ -3884,6 +3824,16 @@ void LLPipeline::postSort(LLCamera& camera) sCull->pushAlphaGroup(group); } } + + LLSpatialGroup::draw_map_t::iterator rigged_alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA_RIGGED); + + if (rigged_alpha != group->mDrawMap.end()) + { //store rigged alpha groups for LLDrawPoolAlpha prepass (skip distance update, rigged attachments use depth buffer) + if (hasRenderType(LLDrawPool::POOL_ALPHA)) + { + sCull->pushRiggedAlphaGroup(group); + } + } } } @@ -3994,7 +3944,10 @@ void LLPipeline::postSort(LLCamera& camera) { mSelectedFaces.clear(); - LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); + if (!gNonInteractive) + { + LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit()); + } // Draw face highlights for selected faces. if (LLSelectMgr::getInstance()->getTEMode()) @@ -4025,8 +3978,8 @@ void LLPipeline::postSort(LLCamera& camera) void render_hud_elements() { - LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); - gPipeline.disableLights(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); + gPipeline.disableLights(); LLGLDisable fog(GL_FOG); LLGLSUIDefault gls_ui; @@ -4038,10 +3991,7 @@ void render_hud_elements() gGL.color4f(1,1,1,1); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); LLGLDepthTest depth(GL_TRUE, GL_FALSE); if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) @@ -4052,8 +4002,11 @@ void render_hud_elements() // Draw the tracking overlays LLTracker::render3D(); - // Show the property lines - LLWorld::getInstance()->renderPropertyLines(); + if (LLWorld::instanceExists()) + { + // Show the property lines + LLWorld::getInstance()->renderPropertyLines(); + } LLViewerParcelMgr::getInstance()->render(); LLViewerParcelMgr::getInstance()->renderParcelCollision(); @@ -4070,10 +4023,7 @@ void render_hud_elements() LLHUDText::renderAllHUD(); } - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } + gUIProgram.unbind(); gGL.flush(); } @@ -4105,10 +4055,7 @@ void LLPipeline::renderHighlights() gGL.setColorMask(false, false); - if (LLGLSLShader::sNoFixedFunction) - { - gHighlightProgram.bind(); - } + gHighlightProgram.bind(); for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter) { @@ -4310,7 +4257,7 @@ U32 LLPipeline::sCurRenderPoolType = 0 ; void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) { - LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); assertInitialized(); @@ -4340,7 +4287,6 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) // Do verification of GL state LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); if (mRenderDebugMask & RENDER_DEBUG_VERIFY) { if (!verify()) @@ -4397,7 +4343,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) } { - LL_RECORD_BLOCK_TIME(FTM_POOLS); + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pools"); //LL_RECORD_BLOCK_TIME(FTM_POOLS); // HACK: don't calculate local lights if we're rendering the HUD! // Removing this check will cause bad flickering when there are @@ -4433,7 +4379,7 @@ void LLPipeline::renderGeom(LLCamera& camera, bool forceVBOUpdate) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) { - LL_RECORD_BLOCK_TIME(FTM_POOLRENDER); + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pool render"); //LL_RECORD_BLOCK_TIME(FTM_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -4563,98 +4509,104 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) { LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); - LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); - - LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_GEOMETRY); + { + // SL-15709 -- NOTE: Tracy only allows one ZoneScoped per function. + // Solutions are: + // 1. Use a new scope + // 2. Use named zones + // 3. Use transient zones + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pools"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLS); - LLGLEnable cull(GL_CULL_FACE); + LLGLEnable cull(GL_CULL_FACE); - for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) - { - LLDrawPool *poolp = *iter; - if (hasRenderType(poolp->getType())) + for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) { - poolp->prerender(); + LLDrawPool *poolp = *iter; + if (hasRenderType(poolp->getType())) + { + poolp->prerender(); + } } - } - LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); + LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0); - LLVertexBuffer::unbind(); + LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); - U32 cur_type = 0; + U32 cur_type = 0; - gGL.setColorMask(true, true); + gGL.setColorMask(true, true); - pool_set_t::iterator iter1 = mPools.begin(); + pool_set_t::iterator iter1 = mPools.begin(); - while ( iter1 != mPools.end() ) - { - LLDrawPool *poolp = *iter1; + while ( iter1 != mPools.end() ) + { + LLDrawPool *poolp = *iter1; - cur_type = poolp->getType(); + cur_type = poolp->getType(); - pool_set_t::iterator iter2 = iter1; - if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) - { - LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER); + pool_set_t::iterator iter2 = iter1; + if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred pool render"); //LL_RECORD_BLOCK_TIME(FTM_DEFERRED_POOLRENDER); - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); - for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ ) - { - LLVertexBuffer::unbind(); - poolp->beginDeferredPass(i); - for (iter2 = iter1; iter2 != mPools.end(); iter2++) + for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ ) { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) + LLVertexBuffer::unbind(); + poolp->beginDeferredPass(i); + for (iter2 = iter1; iter2 != mPools.end(); iter2++) { - break; + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } + + if ( !p->getSkipRenderFlag() ) { p->renderDeferred(i); } } - - if ( !p->getSkipRenderFlag() ) { p->renderDeferred(i); } - } - poolp->endDeferredPass(i); - LLVertexBuffer::unbind(); + poolp->endDeferredPass(i); + LLVertexBuffer::unbind(); - if (gDebugGL || gDebugPipeline) - { - LLGLState::checkStates(); + if (gDebugGL || gDebugPipeline) + { + LLGLState::checkStates(); + } } } - } - else - { - // Skip all pools of this type - for (iter2 = iter1; iter2 != mPools.end(); iter2++) + else { - LLDrawPool *p = *iter2; - if (p->getType() != cur_type) + // Skip all pools of this type + for (iter2 = iter1; iter2 != mPools.end(); iter2++) { - break; + LLDrawPool *p = *iter2; + if (p->getType() != cur_type) + { + break; + } } } + iter1 = iter2; + stop_glerror(); } - iter1 = iter2; - stop_glerror(); - } - gGLLastMatrix = NULL; - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.loadMatrix(gGLModelView); - gGL.setColorMask(true, false); + gGL.setColorMask(true, false); + + } // Tracy ZoneScoped } void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion) { - LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLS); U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -4688,7 +4640,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) { - LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER); + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("deferred poolrender"); //LL_RECORD_BLOCK_TIME(FTM_POST_DEFERRED_POOLRENDER); gGLLastMatrix = NULL; gGL.loadMatrix(gGLModelView); @@ -4749,7 +4701,8 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion) void LLPipeline::renderGeomShadow(LLCamera& camera) { - U32 cur_type = 0; + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -4814,6 +4767,7 @@ void LLPipeline::renderGeomShadow(LLCamera& camera) void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; assertInitialized(); S32 count = 0; if (render_type == LLRender::TRIANGLE_STRIP) @@ -4853,10 +4807,7 @@ void LLPipeline::renderPhysicsDisplay() gGL.setColorMask(true, false); - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.bind(); - } + gDebugProgram.bind(); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -4877,11 +4828,7 @@ void LLPipeline::renderPhysicsDisplay() gGL.flush(); - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.unbind(); - } - + gDebugProgram.unbind(); mPhysicsDisplay.flush(); } @@ -4908,13 +4855,10 @@ void LLPipeline::renderDebug() if ( pathfindingCharacter->getVisible() || gAgentCamera.cameraMouselook() ) { - if (LLGLSLShader::sNoFixedFunction) - { - gPathfindingProgram.bind(); - gPathfindingProgram.uniform1f(sTint, 1.f); - gPathfindingProgram.uniform1f(sAmbiance, 1.f); - gPathfindingProgram.uniform1f(sAlphaScale, 1.f); - } + gPathfindingProgram.bind(); + gPathfindingProgram.uniform1f(sTint, 1.f); + gPathfindingProgram.uniform1f(sAmbiance, 1.f); + gPathfindingProgram.uniform1f(sAlphaScale, 1.f); //Requried character physics capsule render parameters LLUUID id; @@ -4923,21 +4867,14 @@ void LLPipeline::renderDebug() if ( pathfindingCharacter->isPhysicsCapsuleEnabled( id, pos, rot ) ) { - if (LLGLSLShader::sNoFixedFunction) - { - //remove blending artifacts - gGL.setColorMask(false, false); - llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot ); - gGL.setColorMask(true, false); - LLGLEnable blend(GL_BLEND); - gPathfindingProgram.uniform1f(sAlphaScale, 0.90f); - llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot ); - gPathfindingProgram.bind(); - } - else - { - llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot ); - } + //remove blending artifacts + gGL.setColorMask(false, false); + llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot ); + gGL.setColorMask(true, false); + LLGLEnable blend(GL_BLEND); + gPathfindingProgram.uniform1f(sAlphaScale, 0.90f); + llPathingLibInstance->renderSimpleShapeCapsuleID( gGL, id, pos, rot ); + gPathfindingProgram.bind(); } } } @@ -4953,14 +4890,11 @@ void LLPipeline::renderDebug() { F32 ambiance = gSavedSettings.getF32("PathfindingAmbiance"); - if (LLGLSLShader::sNoFixedFunction) - { - gPathfindingProgram.bind(); + gPathfindingProgram.bind(); - gPathfindingProgram.uniform1f(sTint, 1.f); - gPathfindingProgram.uniform1f(sAmbiance, ambiance); - gPathfindingProgram.uniform1f(sAlphaScale, 1.f); - } + gPathfindingProgram.uniform1f(sTint, 1.f); + gPathfindingProgram.uniform1f(sAmbiance, ambiance); + gPathfindingProgram.uniform1f(sAlphaScale, 1.f); if ( !pathfindingConsole->isRenderWorld() ) { @@ -4992,18 +4926,11 @@ void LLPipeline::renderDebug() } //render edges - if (LLGLSLShader::sNoFixedFunction) - { - gPathfindingNoNormalsProgram.bind(); - gPathfindingNoNormalsProgram.uniform1f(sTint, 1.f); - gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, 1.f); - llPathingLibInstance->renderNavMeshEdges(); - gPathfindingProgram.bind(); - } - else - { - llPathingLibInstance->renderNavMeshEdges(); - } + gPathfindingNoNormalsProgram.bind(); + gPathfindingNoNormalsProgram.uniform1f(sTint, 1.f); + gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, 1.f); + llPathingLibInstance->renderNavMeshEdges(); + gPathfindingProgram.bind(); gGL.flush(); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); @@ -5014,53 +4941,31 @@ void LLPipeline::renderDebug() if ( LLPathfindingPathTool::getInstance()->isRenderPath() ) { //The path - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); - llPathingLibInstance->renderPath(); - gPathfindingProgram.bind(); - } - else - { - llPathingLibInstance->renderPath(); - } - //The bookends - if (LLGLSLShader::sNoFixedFunction) - { - //remove blending artifacts - gGL.setColorMask(false, false); - llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START ); - llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END ); + gUIProgram.bind(); + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); + llPathingLibInstance->renderPath(); + gPathfindingProgram.bind(); + + //The bookends + //remove blending artifacts + gGL.setColorMask(false, false); + llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START ); + llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END ); - gGL.setColorMask(true, false); - //render the bookends - LLGLEnable blend(GL_BLEND); - gPathfindingProgram.uniform1f(sAlphaScale, 0.90f); - llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START ); - llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END ); - gPathfindingProgram.bind(); - } - else - { - llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START ); - llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END ); - } - + gGL.setColorMask(true, false); + //render the bookends + LLGLEnable blend(GL_BLEND); + gPathfindingProgram.uniform1f(sAlphaScale, 0.90f); + llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_START ); + llPathingLibInstance->renderPathBookend( gGL, LLPathingLib::LLPL_END ); + gPathfindingProgram.bind(); } if ( pathfindingConsole->isRenderWaterPlane() ) { - if (LLGLSLShader::sNoFixedFunction) - { - LLGLEnable blend(GL_BLEND); - gPathfindingProgram.uniform1f(sAlphaScale, 0.90f); - llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() ); - } - else - { - llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() ); - } + LLGLEnable blend(GL_BLEND); + gPathfindingProgram.uniform1f(sAlphaScale, 0.90f); + llPathingLibInstance->renderSimpleShapes( gGL, gAgent.getRegion()->getWaterHeight() ); } //physics/exclusion shapes if ( pathfindingConsole->isRenderAnyShapes() ) @@ -5191,18 +5096,11 @@ void LLPipeline::renderDebug() } //render edges - if (LLGLSLShader::sNoFixedFunction) - { - gPathfindingNoNormalsProgram.bind(); - gPathfindingNoNormalsProgram.uniform1f(sTint, gSavedSettings.getF32("PathfindingXRayTint")); - gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, gSavedSettings.getF32("PathfindingXRayOpacity")); - llPathingLibInstance->renderNavMeshEdges(); - gPathfindingProgram.bind(); - } - else - { - llPathingLibInstance->renderNavMeshEdges(); - } + gPathfindingNoNormalsProgram.bind(); + gPathfindingNoNormalsProgram.uniform1f(sTint, gSavedSettings.getF32("PathfindingXRayTint")); + gPathfindingNoNormalsProgram.uniform1f(sAlphaScale, gSavedSettings.getF32("PathfindingXRayOpacity")); + llPathingLibInstance->renderNavMeshEdges(); + gPathfindingProgram.bind(); gGL.flush(); glLineWidth(1.0f); @@ -5211,10 +5109,7 @@ void LLPipeline::renderDebug() glPolygonOffset(0.f, 0.f); gGL.flush(); - if (LLGLSLShader::sNoFixedFunction) - { - gPathfindingProgram.unbind(); - } + gPathfindingProgram.unbind(); } } } @@ -5229,10 +5124,7 @@ void LLPipeline::renderDebug() if (!hud_only && !mDebugBlips.empty()) { //render debug blips - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep, true); @@ -5296,7 +5188,7 @@ void LLPipeline::renderDebug() } } - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION) && LLGLSLShader::sNoFixedFunction) + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION)) { //render visible selected group occlusion geometry gDebugProgram.bind(); LLGLDepthTest depth(GL_TRUE, GL_FALSE); @@ -5318,44 +5210,38 @@ void LLPipeline::renderDebug() visible_selected_groups.clear(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST) && !hud_only) { //draw crosshairs on particle intersection if (gDebugRaycastParticle) { - if (LLGLSLShader::sNoFixedFunction) - { //this debug display requires shaders - gDebugProgram.bind(); + gDebugProgram.bind(); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLVector3 center(gDebugRaycastParticleIntersection.getF32ptr()); - LLVector3 size(0.1f, 0.1f, 0.1f); + LLVector3 center(gDebugRaycastParticleIntersection.getF32ptr()); + LLVector3 size(0.1f, 0.1f, 0.1f); - LLVector3 p[6]; + LLVector3 p[6]; - p[0] = center + size.scaledVec(LLVector3(1,0,0)); - p[1] = center + size.scaledVec(LLVector3(-1,0,0)); - p[2] = center + size.scaledVec(LLVector3(0,1,0)); - p[3] = center + size.scaledVec(LLVector3(0,-1,0)); - p[4] = center + size.scaledVec(LLVector3(0,0,1)); - p[5] = center + size.scaledVec(LLVector3(0,0,-1)); + p[0] = center + size.scaledVec(LLVector3(1,0,0)); + p[1] = center + size.scaledVec(LLVector3(-1,0,0)); + p[2] = center + size.scaledVec(LLVector3(0,1,0)); + p[3] = center + size.scaledVec(LLVector3(0,-1,0)); + p[4] = center + size.scaledVec(LLVector3(0,0,1)); + p[5] = center + size.scaledVec(LLVector3(0,0,-1)); - gGL.begin(LLRender::LINES); - gGL.diffuseColor3f(1.f, 1.f, 0.f); - for (U32 i = 0; i < 6; i++) - { - gGL.vertex3fv(p[i].mV); - } - gGL.end(); - gGL.flush(); - - gDebugProgram.unbind(); + gGL.begin(LLRender::LINES); + gGL.diffuseColor3f(1.f, 1.f, 0.f); + for (U32 i = 0; i < 6; i++) + { + gGL.vertex3fv(p[i].mV); } + gGL.end(); + gGL.flush(); + + gDebugProgram.unbind(); } } @@ -5588,17 +5474,12 @@ void LLPipeline::renderDebug() } gGL.flush(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } + gUIProgram.unbind(); } -static LLTrace::BlockTimerStatHandle FTM_REBUILD_POOLS("Rebuild Pools"); - void LLPipeline::rebuildPools() { - LL_RECORD_BLOCK_TIME(FTM_REBUILD_POOLS); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; assertInitialized(); @@ -5942,6 +5823,7 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) void LLPipeline::resetDrawOrders() { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; assertInitialized(); // Iterate through all of the draw pools and rebuild them. for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter) @@ -6261,11 +6143,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) LLEnvironment& environment = LLEnvironment::instance(); LLSettingsSky::ptr_t psky = environment.getCurrentSky(); - if (!LLGLSLShader::sNoFixedFunction) - { - gGL.syncMatrices(); - } - // Ambient LLColor4 ambient = psky->getTotalAmbient(); gGL.setAmbientLightColor(ambient); @@ -6387,21 +6264,19 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) continue; } - LLVector3 light_pos(light->getRenderPosition()); - LLVector4 light_pos_gl(light_pos, 1.0f); - - F32 light_radius = llmax(light->getLightRadius(), 0.001f); - F32 size = light_radius * (sRenderDeferred ? 1.5f : 1.0f); + LLVector3 light_pos(light->getRenderPosition()); + LLVector4 light_pos_gl(light_pos, 1.0f); - if (size <= 0.001f) + F32 adjusted_radius = light->getLightRadius() * (sRenderDeferred ? 1.5f : 1.0f); + if (adjusted_radius <= 0.001f) { continue; } - F32 x = (3.f * (1.f + (light->getLightFalloff() * 2.0f))); // why this magic? probably trying to match a historic behavior. - F32 linatten = x / (light_radius); // % of brightness at radius + F32 x = (3.f * (1.f + (light->getLightFalloff() * 2.0f))); // why this magic? probably trying to match a historic behavior. + F32 linatten = x / adjusted_radius; // % of brightness at radius - mHWLightColors[cur_light] = light_color; + mHWLightColors[cur_light] = light_color; LLLightState* light_state = gGL.getLight(cur_light); light_state->setPosition(light_pos_gl); @@ -6410,7 +6285,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) light_state->setConstantAttenuation(0.f); if (sRenderDeferred) { - light_state->setLinearAttenuation(size); + light_state->setLinearAttenuation(linatten); light_state->setQuadraticAttenuation(light->getLightFalloff(DEFERRED_LIGHT_FALLOFF) + 1.f); // get falloff to match for forward deferred rendering lights } else @@ -6466,11 +6341,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) // prev site of forward (non-deferred) character light injection, removed by SL-13522 09/20 // Init GL state - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHTING); - } - for (S32 i = 0; i < 8; ++i) { gGL.getLight(i)->disable(); @@ -6489,13 +6359,6 @@ void LLPipeline::enableLights(U32 mask) if (mLightMask != mask) { stop_glerror(); - if (!mLightMask) - { - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHTING); - } - } if (mask) { stop_glerror(); @@ -6515,13 +6378,6 @@ void LLPipeline::enableLights(U32 mask) } stop_glerror(); } - else - { - if (!LLGLSLShader::sNoFixedFunction) - { - glDisable(GL_LIGHTING); - } - } mLightMask = mask; stop_glerror(); } @@ -6572,11 +6428,6 @@ void LLPipeline::enableLightsPreview() { disableLights(); - if (!LLGLSLShader::sNoFixedFunction) - { - glEnable(GL_LIGHTING); - } - LLColor4 ambient = PreviewAmbientColor; gGL.setAmbientLightColor(ambient); @@ -7358,8 +7209,6 @@ void LLPipeline::resetVertexBuffers() mResetVertexBuffers = true; } -static LLTrace::BlockTimerStatHandle FTM_RESET_VB("Reset VB"); - void LLPipeline::doResetVertexBuffers(bool forced) { if (!mResetVertexBuffers) @@ -7381,7 +7230,7 @@ void LLPipeline::doResetVertexBuffers(bool forced) } } - LL_RECORD_BLOCK_TIME(FTM_RESET_VB); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; mResetVertexBuffers = false; mCubeVB = NULL; @@ -7421,11 +7270,6 @@ void LLPipeline::doResetVertexBuffers(bool forced) SUBSYSTEM_CLEANUP(LLVertexBuffer); - //delete all name pool caches - LLGLNamePool::cleanupPools(); - - - if (LLVertexBuffer::sGLCount > 0) { LL_WARNS() << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << LL_ENDL; @@ -7451,32 +7295,91 @@ void LLPipeline::doResetVertexBuffers(bool forced) LLVOPartGroup::restoreGL(); } -void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_texture) +void LLPipeline::renderObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged) { assertInitialized(); gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; - mSimplePool->pushBatches(type, mask, texture, batch_texture); + if (rigged) + { + mSimplePool->pushRiggedBatches(type + 1, mask, texture, batch_texture); + } + else + { + mSimplePool->pushBatches(type, mask, texture, batch_texture); + } gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; } -void LLPipeline::renderMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture) +void LLPipeline::renderAlphaObjects(U32 mask, bool texture, bool batch_texture, bool rigged) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + assertInitialized(); + gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; + U32 type = LLRenderPass::PASS_ALPHA; + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i) + { + LLDrawInfo* pparams = *i; + if (pparams) + { + if (rigged) + { + if (pparams->mAvatar != nullptr) + { + if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash) + { + mSimplePool->uploadMatrixPalette(*pparams); + lastAvatar = pparams->mAvatar; + lastMeshId = pparams->mSkinInfo->mHash; + } + + mSimplePool->pushBatch(*pparams, mask | LLVertexBuffer::MAP_WEIGHT4, texture, batch_texture); + } + } + else if (pparams->mAvatar == nullptr) + { + mSimplePool->pushBatch(*pparams, mask, texture, batch_texture); + } + } + } + gGL.loadMatrix(gGLModelView); + gGLLastMatrix = NULL; +} + +void LLPipeline::renderMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged) { assertInitialized(); gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; - mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture); + if (rigged) + { + mAlphaMaskPool->pushRiggedMaskBatches(type+1, mask, texture, batch_texture); + } + else + { + mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture); + } gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; } -void LLPipeline::renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture) +void LLPipeline::renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture, bool batch_texture, bool rigged) { assertInitialized(); gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; - mFullbrightAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture); + if (rigged) + { + mFullbrightAlphaMaskPool->pushRiggedMaskBatches(type+1, mask, texture, batch_texture); + } + else + { + mFullbrightAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture); + } gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; } @@ -7581,11 +7484,8 @@ void LLPipeline::renderFinalize() if (sRenderGlow) { - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); - mGlow[2].bindTarget(); - mGlow[2].clear(); - } + mGlow[2].bindTarget(); + mGlow[2].clear(); gGlowExtractProgram.bind(); F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f); @@ -7651,11 +7551,8 @@ void LLPipeline::renderFinalize() for (S32 i = 0; i < kernel; i++) { - { - LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM_FBO); - mGlow[i % 2].bindTarget(); - mGlow[i % 2].clear(); - } + mGlow[i % 2].bindTarget(); + mGlow[i % 2].clear(); if (i == 0) { @@ -8080,18 +7977,7 @@ void LLPipeline::renderFinalize() LLGLDisable blend(GL_BLEND); - if (LLGLSLShader::sNoFixedFunction) - { - gGlowCombineProgram.bind(); - } - else - { - // tex unit 0 - gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR); - // tex unit 1 - gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, - LLTexUnit::TBS_PREV_COLOR); - } + gGlowCombineProgram.bind(); gGL.getTexUnit(0)->bind(&mGlow[1]); gGL.getTexUnit(1)->bind(&mScreen); @@ -8101,28 +7987,14 @@ void LLPipeline::renderFinalize() buff->setBuffer(mask); buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3); - if (LLGLSLShader::sNoFixedFunction) - { - gGlowCombineProgram.unbind(); - } - else - { - gGL.getTexUnit(1)->disable(); - gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT); - - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - } + gGlowCombineProgram.unbind(); } gGL.setSceneBlendType(LLRender::BT_ALPHA); if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_PHYSICS_SHAPES)) { - if (LLGLSLShader::sNoFixedFunction) - { - gSplatTextureRectProgram.bind(); - } + gSplatTextureRectProgram.bind(); gGL.setColorMask(true, false); @@ -8148,10 +8020,7 @@ void LLPipeline::renderFinalize() gGL.end(); gGL.flush(); - if (LLGLSLShader::sNoFixedFunction) - { - gSplatTextureRectProgram.unbind(); - } + gSplatTextureRectProgram.unbind(); } if (LLRenderTarget::sUseFBO) @@ -8172,11 +8041,9 @@ void LLPipeline::renderFinalize() LLGLState::checkTextureChannels(); } -static LLTrace::BlockTimerStatHandle FTM_BIND_DEFERRED("Bind Deferred"); - void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target) { - LL_RECORD_BLOCK_TIME(FTM_BIND_DEFERRED); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; LLRenderTarget* deferred_target = &mDeferredScreen; LLRenderTarget* deferred_depth_target = &mDeferredDepth; @@ -8418,8 +8285,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_ LLEnvironment& environment = LLEnvironment::instance(); LLSettingsSky::ptr_t sky = environment.getCurrentSky(); - - static_cast<LLSettingsVOSky*>(sky.get())->updateShader(&shader); } LLColor3 pow3f(LLColor3 v, F32 f) @@ -8438,19 +8303,9 @@ LLVector4 pow4fsrgb(LLVector4 v, F32 f) return v; } -static LLTrace::BlockTimerStatHandle FTM_GI_TRACE("Trace"); -static LLTrace::BlockTimerStatHandle FTM_GI_GATHER("Gather"); -static LLTrace::BlockTimerStatHandle FTM_SUN_SHADOW("Shadow Map"); -static LLTrace::BlockTimerStatHandle FTM_SOFTEN_SHADOW("Shadow Soften"); -static LLTrace::BlockTimerStatHandle FTM_EDGE_DETECTION("Find Edges"); -static LLTrace::BlockTimerStatHandle FTM_LOCAL_LIGHTS("Local Lights"); -static LLTrace::BlockTimerStatHandle FTM_ATMOSPHERICS("Atmospherics"); -static LLTrace::BlockTimerStatHandle FTM_FULLSCREEN_LIGHTS("Fullscreen Lights"); -static LLTrace::BlockTimerStatHandle FTM_PROJECTORS("Projectors"); -static LLTrace::BlockTimerStatHandle FTM_POST("Post"); - void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; if (!sCull) { return; @@ -8461,7 +8316,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) LLRenderTarget *deferred_light_target = &mDeferredLight; { - LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED); + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("deferred"); //LL_RECORD_BLOCK_TIME(FTM_RENDER_DEFERRED); LLViewerCamera *camera = LLViewerCamera::getInstance(); { LLGLDepthTest depth(GL_TRUE); @@ -8527,7 +8382,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) { deferred_light_target->bindTarget(); { // paint shadow/SSAO light map (direct lighting lightmap) - LL_RECORD_BLOCK_TIME(FTM_SUN_SHADOW); + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - sun shadow"); bindDeferredShader(gDeferredSunProgram, deferred_light_target); mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); glClearColor(1, 1, 1, 1); @@ -8573,7 +8428,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) if (RenderDeferredSSAO) { // soften direct lighting lightmap - LL_RECORD_BLOCK_TIME(FTM_SOFTEN_SHADOW); + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - soften shadow"); // blur lightmap screen_target->bindTarget(); glClearColor(1, 1, 1, 1); @@ -8651,7 +8506,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) { // apply sunlight contribution LLGLSLShader &soften_shader = LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram; - LL_RECORD_BLOCK_TIME(FTM_ATMOSPHERICS); + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - atmospherics"); bindDeferredShader(soften_shader); LLEnvironment &environment = LLEnvironment::instance(); @@ -8717,6 +8572,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) LLVertexBuffer::unbind(); { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - local lights"); bindDeferredShader(gDeferredLightProgram); if (mCubeVB.isNull()) @@ -8787,7 +8643,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) continue; } - LL_RECORD_BLOCK_TIME(FTM_LOCAL_LIGHTS); gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c); gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s); gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV); @@ -8823,6 +8678,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) if (!spot_lights.empty()) { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - projectors"); LLGLDepthTest depth(GL_TRUE, GL_FALSE); bindDeferredShader(gDeferredSpotLightProgram); @@ -8832,7 +8688,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter) { - LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); LLDrawable *drawablep = *iter; LLVOVolume *volume = drawablep->getVOVolume(); @@ -8868,6 +8723,7 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) vert[2].set(3, 1, 0); { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - fullscreen lights"); LLGLDepthTest depth(GL_FALSE); // full screen blit @@ -8887,7 +8743,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) while (!fullscreen_lights.empty()) { - LL_RECORD_BLOCK_TIME(FTM_FULLSCREEN_LIGHTS); light[count] = fullscreen_lights.front(); fullscreen_lights.pop_front(); col[count] = light_colors.front(); @@ -8919,7 +8774,6 @@ void LLPipeline::renderDeferredLighting(LLRenderTarget *screen_target) for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter) { - LL_RECORD_BLOCK_TIME(FTM_PROJECTORS); LLDrawable *drawablep = *iter; LLVOVolume *volume = drawablep->getVOVolume(); LLVector3 center = drawablep->getPositionAgent(); @@ -9263,8 +9117,19 @@ inline float sgn(float a) void LLPipeline::generateWaterReflection(LLCamera& camera_in) { - if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + + if (!assertInitialized()) + { + return; + } + + if (LLPipeline::sWaterReflections && LLDrawPoolWater::sNeedsReflectionUpdate) { + //disable occlusion culling for reflection/refraction passes (save setting to restore later) + S32 occlude = LLPipeline::sUseOcclusion; + LLPipeline::sUseOcclusion = 0; + bool skip_avatar_update = false; if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) { @@ -9301,26 +9166,19 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) //plane params LLPlane plane; LLVector3 pnorm; - S32 water_clip = 0; - if (!camera_is_underwater) + + if (camera_is_underwater) { - //camera is above water, clip plane points up - pnorm.setVec(0,0,1); - plane.setVec(pnorm, -water_height); - water_clip = 1; + //camera is below water, cull above water + pnorm.setVec(0, 0, 1); } else { - //camera is below water, clip plane points down - pnorm = LLVector3(0,0,-1); - plane.setVec(pnorm, water_height); - water_clip = -1; + //camera is above water, cull below water + pnorm = LLVector3(0, 0, -1); } - S32 occlusion = LLPipeline::sUseOcclusion; - - //disable occlusion culling for reflection map for now - LLPipeline::sUseOcclusion = 0; + plane.setVec(LLVector3(0, 0, water_height), pnorm); if (!camera_is_underwater) { @@ -9419,7 +9277,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) LLGLUserClipPlane clip_plane(plane, mReflectionModelView, saved_projection); LLGLDisable cull(GL_CULL_FACE); - updateCull(camera, mReflectedObjects, -water_clip, &plane); + updateCull(camera, mReflectedObjects, &plane); stateSort(camera, mReflectedObjects); renderGeom(camera); } @@ -9437,8 +9295,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) set_current_modelview(saved_modelview); } - //LLPipeline::sUseOcclusion = occlusion; - camera.setOrigin(camera_in.getOrigin()); //render distortion map static bool last_update = true; @@ -9477,7 +9333,11 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) LLColor3 col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor(); glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f); - LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; + // HACK FIX -- pretend underwater camera is the world camera to fix weird visibility artifacts + // during distortion render (doesn't break main render because the camera is the same perspective + // as world camera and occlusion culling is disabled for this pass) + //LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1; + LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; mWaterDis.bindTarget(); mWaterDis.getViewport(gGLViewport); @@ -9486,41 +9346,47 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) mWaterDis.clear(); gGL.setColorMask(true, false); - F32 water_dist = water_height * LLPipeline::sDistortionWaterClipPlaneMargin; + F32 water_dist = water_height; //clip out geometry on the same side of water as the camera w/ enough margin to not include the water geo itself, // but not so much as to clip out parts of avatars that should be seen under the water in the distortion map - LLPlane plane(-pnorm, water_dist); + LLPlane plane; + + if (camera_is_underwater) + { + //nudge clip plane below water to avoid visible holes in objects intersecting water surface + water_dist /= LLPipeline::sDistortionWaterClipPlaneMargin; + //camera is below water, clip plane points up + pnorm.setVec(0, 0, -1); + } + else + { + //nudge clip plane above water to avoid visible holes in objects intersecting water surface + water_dist *= LLPipeline::sDistortionWaterClipPlaneMargin; + //camera is above water, clip plane points down + pnorm = LLVector3(0, 0, 1); + } + + plane.setVec(LLVector3(0, 0, water_dist), pnorm); + LLGLUserClipPlane clip_plane(plane, saved_modelview, saved_projection); gGL.setColorMask(true, true); mWaterDis.clear(); gGL.setColorMask(true, false); - // ignore clip plane if we're underwater and viewing distortion map of objects above waterline - if (camera_is_underwater) - { - clip_plane.disable(); - } - if (reflection_detail >= WATER_REFLECT_NONE_WATER_TRANSPARENT) { - updateCull(camera, mRefractedObjects, water_clip, &plane); + updateCull(camera, mRefractedObjects, &plane); stateSort(camera, mRefractedObjects); renderGeom(camera); } - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.bind(); - } + gUIProgram.bind(); LLWorld::getInstance()->renderPropertyLines(); - if (LLGLSLShader::sNoFixedFunction) - { - gUIProgram.unbind(); - } + gUIProgram.unbind(); mWaterDis.flush(); } @@ -9533,7 +9399,6 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) gPipeline.popRenderTypeMask(); - LLPipeline::sUseOcclusion = occlusion; LLPipeline::sUnderWaterRender = false; LLPipeline::sReflectionRender = false; @@ -9555,6 +9420,32 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) } LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; + + // restore occlusion culling + LLPipeline::sUseOcclusion = occlude; + } + else + { + // Initial sky pass is still needed even if water reflection is not rendering + bool camera_is_underwater = LLViewerCamera::getInstance()->cameraUnderWater(); + if (!camera_is_underwater) + { + gPipeline.pushRenderTypeMask(); + { + gPipeline.andRenderTypeMask( + LLPipeline::RENDER_TYPE_SKY, + LLPipeline::RENDER_TYPE_WL_SKY, + LLPipeline::END_RENDER_TYPES); + + LLCamera camera = camera_in; + camera.setFar(camera_in.getFar() * 0.75f); + + updateCull(camera, mSky); + stateSort(camera, mSky); + renderGeom(camera, TRUE); + } + gPipeline.popRenderTypeMask(); + } } } @@ -9635,204 +9526,212 @@ static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_TREE("Alpha Tree"); static LLTrace::BlockTimerStatHandle FTM_SHADOW_ALPHA_GRASS("Alpha Grass"); static LLTrace::BlockTimerStatHandle FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED("Fullbright Alpha Masked"); -void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, bool use_shader, bool use_occlusion, U32 target_width) +void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult& result, bool use_shader, bool use_occlusion, U32 target_width) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_SHADOW_RENDER); - //clip out geometry on the same side of water as the camera - S32 occlude = LLPipeline::sUseOcclusion; - if (!use_occlusion) - { - LLPipeline::sUseOcclusion = 0; - } - LLPipeline::sShadowRender = true; - - static const U32 types[] = { - LLRenderPass::PASS_SIMPLE, - LLRenderPass::PASS_FULLBRIGHT, - LLRenderPass::PASS_SHINY, - LLRenderPass::PASS_BUMP, - LLRenderPass::PASS_FULLBRIGHT_SHINY , - LLRenderPass::PASS_MATERIAL, - LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, - LLRenderPass::PASS_SPECMAP, - LLRenderPass::PASS_SPECMAP_EMISSIVE, - LLRenderPass::PASS_NORMMAP, - LLRenderPass::PASS_NORMMAP_EMISSIVE, - LLRenderPass::PASS_NORMSPEC, - LLRenderPass::PASS_NORMSPEC_EMISSIVE, - }; + //disable occlusion culling for shadow passes (save setting to restore later) + S32 occlude = LLPipeline::sUseOcclusion; + if (!use_occlusion) + { + LLPipeline::sUseOcclusion = 0; + } + LLPipeline::sShadowRender = true; + + static const U32 types[] = { + LLRenderPass::PASS_SIMPLE, + LLRenderPass::PASS_FULLBRIGHT, + LLRenderPass::PASS_SHINY, + LLRenderPass::PASS_BUMP, + LLRenderPass::PASS_FULLBRIGHT_SHINY , + LLRenderPass::PASS_MATERIAL, + LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, + LLRenderPass::PASS_SPECMAP, + LLRenderPass::PASS_SPECMAP_EMISSIVE, + LLRenderPass::PASS_NORMMAP, + LLRenderPass::PASS_NORMMAP_EMISSIVE, + LLRenderPass::PASS_NORMSPEC, + LLRenderPass::PASS_NORMSPEC_EMISSIVE, + }; + + LLGLEnable cull(GL_CULL_FACE); + + //enable depth clamping if available + LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0); + + if (use_shader) + { + gDeferredShadowCubeProgram.bind(); + } - LLGLEnable cull(GL_CULL_FACE); + LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID - 1]; - //enable depth clamping if available - LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0); + occlusion_target.bindTarget(); + updateCull(shadow_cam, result); + occlusion_target.flush(); - if (use_shader) - { - gDeferredShadowCubeProgram.bind(); - } + stateSort(shadow_cam, result); - LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID-1]; - occlusion_target.bindTarget(); - updateCull(shadow_cam, result); - occlusion_target.flush(); + //generate shadow map + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadMatrix(proj.m); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadMatrix(view.m); - stateSort(shadow_cam, result); - - - //generate shadow map - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.pushMatrix(); - gGL.loadMatrix(proj.m); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.pushMatrix(); - gGL.loadMatrix(view.m); + stop_glerror(); + gGLLastMatrix = NULL; - stop_glerror(); - gGLLastMatrix = NULL; + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + stop_glerror(); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - stop_glerror(); - LLEnvironment& environment = LLEnvironment::instance(); - LLVertexBuffer::unbind(); + LLVertexBuffer::unbind(); - { - if (!use_shader) - { //occlusion program is general purpose depth-only no-textures - gOcclusionProgram.bind(); - } - else - { - gDeferredShadowProgram.bind(); - gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - } + for (int j = 0; j < 2; ++j) // 0 -- static, 1 -- rigged + { + bool rigged = j == 1; + if (!use_shader) + { //occlusion program is general purpose depth-only no-textures + gOcclusionProgram.bind(rigged); + } + else + { + gDeferredShadowProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); + } - gGL.diffuseColor4f(1,1,1,1); + gGL.diffuseColor4f(1, 1, 1, 1); S32 shadow_detail = gSavedSettings.getS32("RenderShadowDetail"); // if not using VSM, disable color writes if (shadow_detail <= 2) { - gGL.setColorMask(false, false); + gGL.setColorMask(false, false); } - - LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE); - - gGL.getTexUnit(0)->disable(); - for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) - { - renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE); - } - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - if (!use_shader) - { - gOcclusionProgram.unbind(); - } - } - - if (use_shader) - { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM); - gDeferredShadowProgram.unbind(); - renderGeomShadow(shadow_cam); - gDeferredShadowProgram.bind(); - gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - } - else - { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM); + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow simple"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_SIMPLE); - renderGeomShadow(shadow_cam); - } + gGL.getTexUnit(0)->disable(); + for (U32 i = 0; i < sizeof(types) / sizeof(U32); ++i) + { + renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE, FALSE, rigged); + } + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + if (!use_shader) + { + gOcclusionProgram.unbind(); + } - { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA); - gDeferredShadowAlphaMaskProgram.bind(); - gDeferredShadowAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - gDeferredShadowAlphaMaskProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); + } - U32 mask = LLVertexBuffer::MAP_VERTEX | - LLVertexBuffer::MAP_TEXCOORD0 | - LLVertexBuffer::MAP_COLOR | - LLVertexBuffer::MAP_TEXTURE_INDEX; + if (use_shader) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM); - { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED); - renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE); - } + gDeferredShadowProgram.unbind(); + renderGeomShadow(shadow_cam); + gDeferredShadowProgram.bind(); + gDeferredShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); + } + else + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow geom"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_GEOM); - { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND); - gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f); - renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE); - } + renderGeomShadow(shadow_cam); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA); + for (int i = 0; i < 2; ++i) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED); - gDeferredShadowFullbrightAlphaMaskProgram.bind(); - gDeferredShadowFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - gDeferredShadowFullbrightAlphaMaskProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE); - } + bool rigged = i == 1; - mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX; + gDeferredShadowAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_TREE); - gDeferredTreeShadowProgram.bind(); - gDeferredTreeShadowProgram.uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, mask); - renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, mask); - renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, mask); - renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, mask); + U32 mask = LLVertexBuffer::MAP_VERTEX | + LLVertexBuffer::MAP_TEXCOORD0 | + LLVertexBuffer::MAP_COLOR | + LLVertexBuffer::MAP_TEXTURE_INDEX; + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha masked"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_MASKED); + renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE, rigged); + } + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha blend"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_BLEND); + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f); + renderAlphaObjects(mask, TRUE, TRUE, rigged); + } + + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow fullbright alpha masked"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_FULLBRIGHT_ALPHA_MASKED); + gDeferredShadowFullbrightAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); + renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE, rigged); + } + + + { + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha grass"); //LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS); + gDeferredTreeShadowProgram.bind(rigged); + if (i == 0) + { + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f); + renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); + } + + U32 no_idx_mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX; + renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, no_idx_mask, true, false, rigged); + renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, no_idx_mask, true, false, rigged); + renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, no_idx_mask, true, false, rigged); + renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, no_idx_mask, true, false, rigged); + } } - - { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_ALPHA_GRASS); - gDeferredTreeShadowProgram.setMinimumAlpha(0.598f); - renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE); - } } - //glCullFace(GL_BACK); + //glCullFace(GL_BACK); - gDeferredShadowCubeProgram.bind(); - gGLLastMatrix = NULL; - gGL.loadMatrix(gGLModelView); + gDeferredShadowCubeProgram.bind(); + gGLLastMatrix = NULL; + gGL.loadMatrix(gGLModelView); - LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID-1]; + LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID - 1]; - doOcclusion(shadow_cam, occlusion_source, occlusion_target); + doOcclusion(shadow_cam, occlusion_source, occlusion_target); - if (use_shader) - { - gDeferredShadowProgram.unbind(); - } - - gGL.setColorMask(true, true); - - gGL.matrixMode(LLRender::MM_PROJECTION); - gGL.popMatrix(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - gGL.popMatrix(); - gGLLastMatrix = NULL; + if (use_shader) + { + gDeferredShadowProgram.unbind(); + } - LLPipeline::sUseOcclusion = occlude; - LLPipeline::sShadowRender = false; + gGL.setColorMask(true, true); + + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); + gGLLastMatrix = NULL; + + LLPipeline::sUseOcclusion = occlude; + LLPipeline::sShadowRender = false; } -static LLTrace::BlockTimerStatHandle FTM_VISIBLE_CLOUD("Visible Cloud"); bool LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir) { - LL_RECORD_BLOCK_TIME(FTM_VISIBLE_CLOUD); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //get point cloud of intersection of frust and min, max if (getVisibleExtents(camera, min, max)) @@ -10044,10 +9943,7 @@ void LLPipeline::generateHighlight(LLCamera& camera) gGL.setColorMask(true, true); mHighlight.clear(); - if (LLGLSLShader::sNoFixedFunction) - { - gHighlightProgram.bind(); - } + gHighlightProgram.bind(); gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ) @@ -10089,9 +9985,6 @@ LLRenderTarget* LLPipeline::getShadowTarget(U32 i) } static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW("Gen Sun Shadow"); -static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SETUP("Sun Shadow Setup"); -static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_RENDER_DIRECTIONAL("Render Dir"); -static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_SETUP("Spot Shadow Setup"); static LLTrace::BlockTimerStatHandle FTM_GEN_SUN_SHADOW_SPOT_RENDER("Spot Shadow Render"); void LLPipeline::generateSunShadow(LLCamera& camera) @@ -10101,7 +9994,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) return; } - LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_GEN_SUN_SHADOW); bool skip_avatar_update = false; if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK || !LLVOAvatar::sVisibleInFirstPerson) @@ -10161,6 +10054,29 @@ void LLPipeline::generateSunShadow(LLCamera& camera) LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND, LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK, LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE, + LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK_RIGGED, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, + LLPipeline::RENDER_TYPE_PASS_SIMPLE_RIGGED, + LLPipeline::RENDER_TYPE_PASS_BUMP_RIGGED, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_RIGGED, + LLPipeline::RENDER_TYPE_PASS_SHINY_RIGGED, + LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY_RIGGED, + LLPipeline::RENDER_TYPE_PASS_MATERIAL_RIGGED, + LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_RIGGED, + LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK_RIGGED, + LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, + LLPipeline::RENDER_TYPE_PASS_SPECMAP_RIGGED, + LLPipeline::RENDER_TYPE_PASS_SPECMAP_BLEND_RIGGED, + LLPipeline::RENDER_TYPE_PASS_SPECMAP_MASK_RIGGED, + LLPipeline::RENDER_TYPE_PASS_SPECMAP_EMISSIVE_RIGGED, + LLPipeline::RENDER_TYPE_PASS_NORMMAP_RIGGED, + LLPipeline::RENDER_TYPE_PASS_NORMMAP_BLEND_RIGGED, + LLPipeline::RENDER_TYPE_PASS_NORMMAP_MASK_RIGGED, + LLPipeline::RENDER_TYPE_PASS_NORMMAP_EMISSIVE_RIGGED, + LLPipeline::RENDER_TYPE_PASS_NORMSPEC_RIGGED, + LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND_RIGGED, + LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK_RIGGED, + LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE_RIGGED, END_RENDER_TYPES); gGL.setColorMask(false, false); @@ -10887,17 +10803,28 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool textu } } -static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_MARK_VISIBLE("Impostor Mark Visible"); -static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_SETUP("Impostor Setup"); -static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_BACKGROUND("Impostor Background"); -static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_ALLOCATE("Impostor Allocate"); -static LLTrace::BlockTimerStatHandle FTM_IMPOSTOR_RESIZE("Impostor Resize"); +void LLPipeline::renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture) +{ + for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i) + { + LLSpatialGroup* group = *i; + if (!group->isDead() && + (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && + gPipeline.hasRenderType(group->getSpatialPartition()->mDrawableType) && + group->mDrawMap.find(type) != group->mDrawMap.end()) + { + pass->renderRiggedGroup(group, type, mask, texture); + } + } +} + +static LLTrace::BlockTimerStatHandle FTM_GENERATE_IMPOSTOR("Generate Impostor"); -void LLPipeline::generateImpostor(LLVOAvatar* avatar) +void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) { + LL_RECORD_BLOCK_TIME(FTM_GENERATE_IMPOSTOR); LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); static LLCullResult result; result.clear(); @@ -10912,11 +10839,12 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) assertInitialized(); - bool visually_muted = avatar->isVisuallyMuted(); + // previews can't be muted or impostered + bool visually_muted = !preview_avatar && avatar->isVisuallyMuted(); LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " is " << ( visually_muted ? "" : "not ") << "visually muted" << LL_ENDL; - bool too_complex = avatar->isTooComplex(); + bool too_complex = !preview_avatar && avatar->isTooComplex(); LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " is " << ( too_complex ? "" : "not ") << "too complex" << LL_ENDL; @@ -10925,37 +10853,31 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) if (visually_muted || too_complex) { + // only show jelly doll geometry andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::RENDER_TYPE_CONTROL_AV, END_RENDER_TYPES); } else { - andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA, - LLPipeline::RENDER_TYPE_FULLBRIGHT, - LLPipeline::RENDER_TYPE_VOLUME, - LLPipeline::RENDER_TYPE_GLOW, - LLPipeline::RENDER_TYPE_BUMP, - LLPipeline::RENDER_TYPE_PASS_SIMPLE, - LLPipeline::RENDER_TYPE_PASS_ALPHA, - LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_BUMP, - LLPipeline::RENDER_TYPE_PASS_POST_BUMP, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK, - LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY, - LLPipeline::RENDER_TYPE_PASS_GLOW, - LLPipeline::RENDER_TYPE_PASS_GRASS, - LLPipeline::RENDER_TYPE_PASS_SHINY, - LLPipeline::RENDER_TYPE_PASS_INVISIBLE, - LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY, - LLPipeline::RENDER_TYPE_AVATAR, - LLPipeline::RENDER_TYPE_CONTROL_AV, - LLPipeline::RENDER_TYPE_ALPHA_MASK, - LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, - LLPipeline::RENDER_TYPE_INVISIBLE, - LLPipeline::RENDER_TYPE_SIMPLE, - END_RENDER_TYPES); + //hide world geometry + clearRenderTypeMask( + RENDER_TYPE_SKY, + RENDER_TYPE_WL_SKY, + RENDER_TYPE_GROUND, + RENDER_TYPE_TERRAIN, + RENDER_TYPE_GRASS, + RENDER_TYPE_CONTROL_AV, // Animesh + RENDER_TYPE_TREE, + RENDER_TYPE_VOIDWATER, + RENDER_TYPE_WATER, + RENDER_TYPE_PASS_GRASS, + RENDER_TYPE_HUD, + RENDER_TYPE_PARTICLES, + RENDER_TYPE_CLOUDS, + RENDER_TYPE_HUD_PARTICLES, + END_RENDER_TYPES + ); } S32 occlusion = sUseOcclusion; @@ -10969,7 +10891,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) LLViewerCamera* viewer_camera = LLViewerCamera::getInstance(); { - LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_MARK_VISIBLE); markVisible(avatar->mDrawable, *viewer_camera); LLVOAvatar::attachment_map_t::iterator iter; @@ -10997,8 +10918,8 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) U32 resY = 0; U32 resX = 0; + if (!preview_avatar) { - LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_SETUP); const LLVector4a* ext = avatar->mDrawable->getSpatialExtents(); LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset()); @@ -11055,17 +10976,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) if (!avatar->mImpostor.isComplete()) { - LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_ALLOCATE); - + avatar->mImpostor.allocate(resX, resY, GL_RGBA, TRUE, FALSE); if (LLPipeline::sRenderDeferred) { - avatar->mImpostor.allocate(resX,resY,GL_SRGB8_ALPHA8,TRUE,FALSE); - addDeferredAttachments(avatar->mImpostor); - } - else - { - avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE); + addDeferredAttachments(avatar->mImpostor, true); } gGL.getTexUnit(0)->bind(&avatar->mImpostor); @@ -11074,7 +10989,6 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) } else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight()) { - LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_RESIZE); avatar->mImpostor.resize(resX,resY); } @@ -11088,7 +11002,20 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) LLDrawPoolAvatar::sMinimumAlpha = 0.f; } - if (LLPipeline::sRenderDeferred) + if (preview_avatar) + { + // previews don't care about imposters + if (LLPipeline::sRenderDeferred) + { + renderGeomDeferred(camera); + renderGeomPostDeferred(camera); + } + else + { + renderGeom(camera); + } + } + else if (LLPipeline::sRenderDeferred) { avatar->mImpostor.clear(); renderGeomDeferred(camera); @@ -11136,10 +11063,10 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) LLDrawPoolAvatar::sMinimumAlpha = old_alpha; { //create alpha mask based on depth buffer (grey out if muted) - LL_RECORD_BLOCK_TIME(FTM_IMPOSTOR_BACKGROUND); if (LLPipeline::sRenderDeferred) { GLuint buff = GL_COLOR_ATTACHMENT0; + LL_PROFILER_GPU_ZONEC( "gl.DrawBuffersARB", 0x8000FF ); glDrawBuffersARB(1, &buff); } @@ -11168,11 +11095,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) static const F32 clip_plane = 0.99999f; - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.bind(); - } - + gDebugProgram.bind(); if (visually_muted) { // Visually muted avatar @@ -11180,13 +11103,12 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " MUTED set solid color " << muted_color << LL_ENDL; gGL.diffuseColor4fv( muted_color.mV ); } - else + else if (!preview_avatar) { //grey muted avatar LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " MUTED set grey" << LL_ENDL; gGL.diffuseColor4fv(LLColor4::pink.mV ); } - { gGL.begin(LLRender::QUADS); gGL.vertex3f(-1, -1, clip_plane); gGL.vertex3f(1, -1, clip_plane); @@ -11194,21 +11116,19 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) gGL.vertex3f(-1, 1, clip_plane); gGL.end(); gGL.flush(); - } - if (LLGLSLShader::sNoFixedFunction) - { - gDebugProgram.unbind(); - } + gDebugProgram.unbind(); gGL.popMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); } - avatar->mImpostor.flush(); - - avatar->setImpostorDim(tdim); + if (!preview_avatar) + { + avatar->mImpostor.flush(); + avatar->setImpostorDim(tdim); + } sUseOcclusion = occlusion; sReflectionRender = false; @@ -11221,14 +11141,16 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar) gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); - avatar->mNeedsImpostorUpdate = FALSE; - avatar->cacheImpostorValues(); - avatar->mLastImpostorUpdateFrameTime = gFrameTimeSeconds; + if (!preview_avatar) + { + avatar->mNeedsImpostorUpdate = FALSE; + avatar->cacheImpostorValues(); + avatar->mLastImpostorUpdateFrameTime = gFrameTimeSeconds; + } LLVertexBuffer::unbind(); LLGLState::checkStates(); LLGLState::checkTextureChannels(); - LLGLState::checkClientArrays(); } bool LLPipeline::hasRenderBatches(const U32 type) const @@ -11256,6 +11178,16 @@ LLCullResult::sg_iterator LLPipeline::endAlphaGroups() return sCull->endAlphaGroups(); } +LLCullResult::sg_iterator LLPipeline::beginRiggedAlphaGroups() +{ + return sCull->beginRiggedAlphaGroups(); +} + +LLCullResult::sg_iterator LLPipeline::endRiggedAlphaGroups() +{ + return sCull->endRiggedAlphaGroups(); +} + bool LLPipeline::hasRenderType(const U32 type) const { // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render" diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 0eaa6b141d..62d3ae7a39 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -66,7 +66,6 @@ bool setup_hud_matrices(const LLRect& screen_region); // specify portion of scre extern LLTrace::BlockTimerStatHandle FTM_RENDER_GEOMETRY; extern LLTrace::BlockTimerStatHandle FTM_RENDER_GRASS; extern LLTrace::BlockTimerStatHandle FTM_RENDER_INVISIBLE; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_OCCLUSION; extern LLTrace::BlockTimerStatHandle FTM_RENDER_SHINY; extern LLTrace::BlockTimerStatHandle FTM_RENDER_SIMPLE; extern LLTrace::BlockTimerStatHandle FTM_RENDER_TERRAIN; @@ -87,8 +86,6 @@ extern LLTrace::BlockTimerStatHandle FTM_CLIENT_COPY; extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_HUD; extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_3D; extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_2D; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_DEBUG_TEXT; -extern LLTrace::BlockTimerStatHandle FTM_RENDER_UI_SCENE_MON; class LLPipeline { @@ -137,7 +134,7 @@ public: void allocatePhysicsBuffer(); void resetVertexBuffers(LLDrawable* drawable); - void generateImpostor(LLVOAvatar* avatar); + void generateImpostor(LLVOAvatar* avatar, bool preview_avatar = false); void bindScreenToTexture(); void renderFinalize(); @@ -228,9 +225,7 @@ public: S32 getLightingDetail() const { return mLightingDetail; } S32 getMaxLightingDetail() const; - void setUseVertexShaders(bool use_shaders); - bool getUseVertexShaders() const { return mVertexShadersEnabled; } - bool canUseVertexShaders(); + bool shadersLoaded(); bool canUseWindLightShaders() const; bool canUseWindLightShadersOnObjects() const; bool canUseAntiAliasing() const; @@ -245,7 +240,7 @@ public: bool visibleObjectsInFrustum(LLCamera& camera); bool getVisibleExtents(LLCamera& camera, LLVector3 &min, LLVector3& max); bool getVisiblePointCloud(LLCamera& camera, LLVector3 &min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir = LLVector3(0,0,0)); - void updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip = 0, LLPlane* plane = NULL); //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane + void updateCull(LLCamera& camera, LLCullResult& result, LLPlane* plane = NULL); //if water_clip is 0, ignore water plane, 1, cull to above plane, -1, cull to below plane void createObjects(F32 max_dtime); void createObject(LLViewerObject* vobj); void processPartitionQ(); @@ -265,13 +260,20 @@ public: void stateSort(LLSpatialBridge* bridge, LLCamera& camera, BOOL fov_changed = FALSE); void stateSort(LLDrawable* drawablep, LLCamera& camera); void postSort(LLCamera& camera); + + //update stats for textures in given DrawInfo + void touchTextures(LLDrawInfo* info); + void touchTexture(LLViewerTexture* tex, F32 vsize); + void forAllVisibleDrawables(void (*func)(LLDrawable*)); - void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false); - void renderMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false); - void renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false); + void renderObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false); + void renderAlphaObjects(U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false); + void renderMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false); + void renderFullbrightMaskedObjects(U32 type, U32 mask, bool texture = true, bool batch_texture = false, bool rigged = false); void renderGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture); + void renderRiggedGroups(LLRenderPass* pass, U32 type, U32 mask, bool texture); void grabReferences(LLCullResult& result); void clearReferences(); @@ -336,6 +338,8 @@ public: LLCullResult::drawinfo_iterator endRenderMap(U32 type); LLCullResult::sg_iterator beginAlphaGroups(); LLCullResult::sg_iterator endAlphaGroups(); + LLCullResult::sg_iterator beginRiggedAlphaGroups(); + LLCullResult::sg_iterator endRiggedAlphaGroups(); void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES); @@ -458,34 +462,61 @@ public: RENDER_TYPE_ALPHA = LLDrawPool::POOL_ALPHA, RENDER_TYPE_GLOW = LLDrawPool::POOL_GLOW, RENDER_TYPE_PASS_SIMPLE = LLRenderPass::PASS_SIMPLE, + RENDER_TYPE_PASS_SIMPLE_RIGGED = LLRenderPass::PASS_SIMPLE_RIGGED, RENDER_TYPE_PASS_GRASS = LLRenderPass::PASS_GRASS, RENDER_TYPE_PASS_FULLBRIGHT = LLRenderPass::PASS_FULLBRIGHT, + RENDER_TYPE_PASS_FULLBRIGHT_RIGGED = LLRenderPass::PASS_FULLBRIGHT, RENDER_TYPE_PASS_INVISIBLE = LLRenderPass::PASS_INVISIBLE, + RENDER_TYPE_PASS_INVISIBLE_RIGGED = LLRenderPass::PASS_INVISIBLE_RIGGED, RENDER_TYPE_PASS_INVISI_SHINY = LLRenderPass::PASS_INVISI_SHINY, + RENDER_TYPE_PASS_INVISI_SHINY_RIGGED = LLRenderPass::PASS_INVISI_SHINY_RIGGED, RENDER_TYPE_PASS_FULLBRIGHT_SHINY = LLRenderPass::PASS_FULLBRIGHT_SHINY, + RENDER_TYPE_PASS_FULLBRIGHT_SHINY_RIGGED = LLRenderPass::PASS_FULLBRIGHT_SHINY_RIGGED, RENDER_TYPE_PASS_SHINY = LLRenderPass::PASS_SHINY, + RENDER_TYPE_PASS_SHINY_RIGGED = LLRenderPass::PASS_SHINY_RIGGED, RENDER_TYPE_PASS_BUMP = LLRenderPass::PASS_BUMP, + RENDER_TYPE_PASS_BUMP_RIGGED = LLRenderPass::PASS_BUMP_RIGGED, RENDER_TYPE_PASS_POST_BUMP = LLRenderPass::PASS_POST_BUMP, + RENDER_TYPE_PASS_POST_BUMP_RIGGED = LLRenderPass::PASS_POST_BUMP_RIGGED, RENDER_TYPE_PASS_GLOW = LLRenderPass::PASS_GLOW, + RENDER_TYPE_PASS_GLOW_RIGGED = LLRenderPass::PASS_GLOW_RIGGED, RENDER_TYPE_PASS_ALPHA = LLRenderPass::PASS_ALPHA, RENDER_TYPE_PASS_ALPHA_MASK = LLRenderPass::PASS_ALPHA_MASK, + RENDER_TYPE_PASS_ALPHA_MASK_RIGGED = LLRenderPass::PASS_ALPHA_MASK_RIGGED, RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK = LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, + RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK_RIGGED = LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK_RIGGED, RENDER_TYPE_PASS_MATERIAL = LLRenderPass::PASS_MATERIAL, + RENDER_TYPE_PASS_MATERIAL_RIGGED = LLRenderPass::PASS_MATERIAL_RIGGED, RENDER_TYPE_PASS_MATERIAL_ALPHA = LLRenderPass::PASS_MATERIAL_ALPHA, + RENDER_TYPE_PASS_MATERIAL_ALPHA_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_RIGGED, RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK = LLRenderPass::PASS_MATERIAL_ALPHA_MASK, + RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_MASK_RIGGED, RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE= LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, + RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED = LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE_RIGGED, RENDER_TYPE_PASS_SPECMAP = LLRenderPass::PASS_SPECMAP, + RENDER_TYPE_PASS_SPECMAP_RIGGED = LLRenderPass::PASS_SPECMAP_RIGGED, RENDER_TYPE_PASS_SPECMAP_BLEND = LLRenderPass::PASS_SPECMAP_BLEND, + RENDER_TYPE_PASS_SPECMAP_BLEND_RIGGED = LLRenderPass::PASS_SPECMAP_BLEND_RIGGED, RENDER_TYPE_PASS_SPECMAP_MASK = LLRenderPass::PASS_SPECMAP_MASK, + RENDER_TYPE_PASS_SPECMAP_MASK_RIGGED = LLRenderPass::PASS_SPECMAP_MASK_RIGGED, RENDER_TYPE_PASS_SPECMAP_EMISSIVE = LLRenderPass::PASS_SPECMAP_EMISSIVE, + RENDER_TYPE_PASS_SPECMAP_EMISSIVE_RIGGED = LLRenderPass::PASS_SPECMAP_EMISSIVE_RIGGED, RENDER_TYPE_PASS_NORMMAP = LLRenderPass::PASS_NORMMAP, + RENDER_TYPE_PASS_NORMMAP_RIGGED = LLRenderPass::PASS_NORMMAP_RIGGED, RENDER_TYPE_PASS_NORMMAP_BLEND = LLRenderPass::PASS_NORMMAP_BLEND, + RENDER_TYPE_PASS_NORMMAP_BLEND_RIGGED = LLRenderPass::PASS_NORMMAP_BLEND_RIGGED, RENDER_TYPE_PASS_NORMMAP_MASK = LLRenderPass::PASS_NORMMAP_MASK, + RENDER_TYPE_PASS_NORMMAP_MASK_RIGGED = LLRenderPass::PASS_NORMMAP_MASK_RIGGED, RENDER_TYPE_PASS_NORMMAP_EMISSIVE = LLRenderPass::PASS_NORMMAP_EMISSIVE, + RENDER_TYPE_PASS_NORMMAP_EMISSIVE_RIGGED = LLRenderPass::PASS_NORMMAP_EMISSIVE_RIGGED, RENDER_TYPE_PASS_NORMSPEC = LLRenderPass::PASS_NORMSPEC, + RENDER_TYPE_PASS_NORMSPEC_RIGGED = LLRenderPass::PASS_NORMSPEC_RIGGED, RENDER_TYPE_PASS_NORMSPEC_BLEND = LLRenderPass::PASS_NORMSPEC_BLEND, + RENDER_TYPE_PASS_NORMSPEC_BLEND_RIGGED = LLRenderPass::PASS_NORMSPEC_BLEND_RIGGED, RENDER_TYPE_PASS_NORMSPEC_MASK = LLRenderPass::PASS_NORMSPEC_MASK, + RENDER_TYPE_PASS_NORMSPEC_MASK_RIGGED = LLRenderPass::PASS_NORMSPEC_MASK_RIGGED, RENDER_TYPE_PASS_NORMSPEC_EMISSIVE = LLRenderPass::PASS_NORMSPEC_EMISSIVE, + RENDER_TYPE_PASS_NORMSPEC_EMISSIVE_RIGGED = LLRenderPass::PASS_NORMSPEC_EMISSIVE_RIGGED, // Following are object types (only used in drawable mRenderType) RENDER_TYPE_HUD = LLRenderPass::NUM_RENDER_TYPES, RENDER_TYPE_VOLUME, @@ -574,7 +605,6 @@ public: static bool sDelayVBUpdate; static bool sAutoMaskAlphaDeferred; static bool sAutoMaskAlphaNonDeferred; - static bool sDisableShaders; // if true, rendering will be done without shaders static bool sRenderTransparentWater; static bool sRenderBump; static bool sBakeSunlight; @@ -597,7 +627,6 @@ public: static bool sRenderAttachedParticles; static bool sRenderDeferred; static S32 sVisibleLightCount; - static F32 sMinRenderSize; static bool sRenderingHUDs; static F32 sDistortionWaterClipPlaneMargin; @@ -676,8 +705,7 @@ public: LLVector4 mTransformedMoonDir; bool mInitialized; - bool mVertexShadersEnabled; - S32 mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed + bool mShadersLoaded; U32 mTransformFeedbackPrimitives; //number of primitives expected to be generated by transform feedback protected: @@ -878,7 +906,6 @@ public: //cached settings static bool WindLightUseAtmosShaders; - static bool RenderAvatarVP; static bool RenderDeferred; static F32 RenderDeferredSunWash; static U32 RenderFSAASamples; diff --git a/indra/newview/skins/default/xui/da/floater_about.xml b/indra/newview/skins/default/xui/da/floater_about.xml index 7654f0dcd6..b322e67bb7 100644 --- a/indra/newview/skins/default/xui/da/floater_about.xml +++ b/indra/newview/skins/default/xui/da/floater_about.xml @@ -60,7 +60,6 @@ DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 20 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org). GL Copyright (C) 1999-2004 Brian Paul. -GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/skins/default/xui/de/floater_about.xml b/indra/newview/skins/default/xui/de/floater_about.xml index 42e23b2089..b2708f7141 100644 --- a/indra/newview/skins/default/xui/de/floater_about.xml +++ b/indra/newview/skins/default/xui/de/floater_about.xml @@ -19,7 +19,6 @@ mit Open-Source-Beiträgen von:</text> expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm und Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. - GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University sowie David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW). diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml index 71f4d81195..eb07425dfe 100644 --- a/indra/newview/skins/default/xui/en/floater_about.xml +++ b/indra/newview/skins/default/xui/en/floater_about.xml @@ -101,11 +101,11 @@ Dummy Name replaced at run time expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. - GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) jpeglib Copyright (C) 1991-1998, Thomas G. Lane. + meshoptimizer Copyright (c) 2016-2021 Arseny Kapoulkine ogg/vorbis Copyright (C) 2002, Xiphophorus OpenSSL Copyright (C) 1998-2008 The OpenSSL Project. PCRE Copyright (c) 1997-2012 University of Cambridge diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml index f4cf2cb512..e499ddbc2f 100644 --- a/indra/newview/skins/default/xui/en/floater_model_preview.xml +++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml @@ -34,7 +34,7 @@ <string name="mesh_status_missing_lod">Missing required level of detail.</string> <string name="mesh_status_invalid_material_list">LOD materials are not a subset of reference model.</string> <string name="phys_status_vertex_limit_exceeded">Some physical hulls exceed vertex limitations.</string> - <string name="phys_status_degenerate_triangles">The physics mesh too dense remove the small thin triangles (see preview)</string> + <string name="phys_status_degenerate_triangles">The physics mesh is too dense or contains degenerate triangles. Use Analyze/Simplify to resolve.</string> <string name="layer_all">All</string> <!-- Text to display in physics layer combo box for "all layers" --> <string name="decomposing">Analyzing...</string> <string name="simplifying">Simplifying...</string> @@ -45,7 +45,21 @@ <string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string> <string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string> <string name="ModelLoaded">Model [MODEL_NAME] loaded</string> + <string name="IncompleteTC">Texture coordinates data is not complete.</string> + <string name="PositionNaN">Found NaN while loading position data from DAE-Model, invalid model.</string> + <string name="NormalsNaN">Found NaN while loading normals from DAE-Model, invalid model.</string> + <string name="NegativeScaleTrans">Negative scale detected, unsupported transform. domInstance_geometry: [LABEL]</string> + <string name="NegativeScaleNormTrans">Negative scale detected, unsupported post-normalization transform. domInstance_geometry: [LABEL]</string> + <string name="CantResolveGeometryUrl">Unable to resolve geometry URL.</string> + <string name="ParsingErrorBadElement">Bad element</string> + <string name="ParsingErrorCantParseScene">Scene could not be parsed</string> + <string name="ParsingErrorCorrupt">Error with dae - traditionally indicates a corrupt file.</string> + <string name="ParsingErrorNoController">Could not verify controller</string> + <string name="ParsingErrorNoDoc">Can't find internal doc</string> + <string name="ParsingErrorNoRoot">Document has no root</string> + <string name="ParsingErrorNoScene">Document has no visual_scene</string> + <string name="ParsingErrorPositionInvalidModel">Unable to process mesh without position data. Invalid model.</string> <panel follows="top|left" @@ -173,9 +187,17 @@ label="Load from file" value="Load from file" /> <item - name="Generate" - label="Generate" - value="Generate" /> + name="MeshOpt Auto" + label="Generate Auto" + value="MeshOpt Auto" /> + <item + name="MeshOptCombine" + label="Generate Precise" + value="MeshOptCombine" /> + <item + name="MeshOptSloppy" + label="Generate Sloppy" + value="MeshOptSloppy" /> </combo_box> <line_editor follows="left|top" @@ -302,9 +324,17 @@ label="Load from file" value="Load from file" /> <item - name="Generate" - label="Generate" - value="Generate" /> + name="MeshOpt Auto" + label="Generate Auto" + value="MeshOpt Auto" /> + <item + name="MeshOptCombine" + label="Generate Precise" + value="MeshOptCombine" /> + <item + name="MeshOptSloppy" + label="Generate Sloppy" + value="MeshOptSloppy" /> <item name="Use LoD above" label="Use LoD above" @@ -435,9 +465,17 @@ label="Load from file" value="Load from file" /> <item - name="Generate" - label="Generate" - value="Generate" /> + name="MeshOpt Auto" + label="Generate Auto" + value="MeshOpt Auto" /> + <item + name="MeshOptCombine" + label="Generate Precise" + value="MeshOptCombine" /> + <item + name="MeshOptSloppy" + label="Generate Sloppy" + value="MeshOptSloppy" /> <item name="Use LoD above" label="Use LoD above" @@ -568,9 +606,17 @@ label="Load from file" value="Load from file" /> <item - name="Generate" - label="Generate" - value="Generate" /> + name="MeshOpt Auto" + label="Generate Auto" + value="MeshOpt Auto" /> + <item + name="MeshOptCombine" + label="Generate Precise" + value="MeshOptCombine" /> + <item + name="MeshOptSloppy" + label="Generate Sloppy" + value="MeshOptSloppy" /> <item name="Use LoD above" label="Use LoD above" diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 7786ba8a1c..d1e167df64 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -102,6 +102,18 @@ Low </text> + <check_box + control_name="RenderVSyncEnable" + height="16" + initial_value="true" + label="Enable VSync" + layout="topleft" + left="30" + top_delta="16" + name="vsync" + tool_tip="Synchronizes the frame rate to the refresh rate of the monitor, which results in smooth performance." + width="315" /> + <text type="string" length="1" @@ -334,18 +346,6 @@ width="256" /> <check_box - control_name="RenderVBOEnable" - height="16" - initial_value="true" - label="Enable OpenGL Vertex Buffer Objects" - layout="topleft" - left="30" - top_delta="16" - name="vbo" - tool_tip="Enabling this on modern hardware gives a performance gain. However, older hardware often has poor implementations of VBOs and you may get crashes when this is enabled." - width="315" /> - - <check_box control_name="RenderCompressTextures" height="16" initial_value="true" @@ -661,20 +661,6 @@ </text> <check_box - control_name="RenderAvatarVP" - height="16" - initial_value="true" - label="Avatar Hardware skinning" - layout="topleft" - left="440" - name="AvatarVertexProgram" - top_delta="16" - width="280"> - <check_box.commit_callback - function="Pref.RenderOptionUpdate" /> - </check_box> - - <check_box control_name="RenderAvatarCloth" height="16" initial_value="true" @@ -885,7 +871,7 @@ layout="topleft" left="13" name="horiz_border" - top_pad="5" + top_pad="21" top_delta="5" width="774"/> <button diff --git a/indra/newview/skins/default/xui/en/floater_stats.xml b/indra/newview/skins/default/xui/en/floater_stats.xml index f9d44b2c69..b9ca0108b6 100644 --- a/indra/newview/skins/default/xui/en/floater_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_stats.xml @@ -35,6 +35,25 @@ decimal_digits="1" show_bar="true" show_history="true"/> + <stat_bar name="frame_mean" + label="frame (mean)" + unit_label="ms" + stat="frametime" + decimal_digits="1" + show_bar="false" + show_history="false"/> + <stat_bar name="frame_median" + label="frame (median)" + unit_label="ms" + stat="frametime" + show_median="true" + decimal_digits="1" + show_bar="false" + show_history="false"/> + <stat_bar name="framet_jitter" + label="jitter" + decimal_digits="1" + stat="frametimejitter"/> <stat_bar name="bandwidth" label="UDP Data Received" stat="activemessagedatareceived" diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index d4ccfd55ff..e1f6dde6ff 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -8787,13 +8787,6 @@ See SecondLife.log for details type="alert"> Error while requesting mesh upload permissons. </notification> - - <notification - name="MeshUploadProfilerError" - icon="alert.tga" - type="alert"> -Mesh uploader is incompatible with RenderGLCoreProfile, please turn RenderGLCoreProfile off in debug settings and restart the viewer. - </notification> <notification name="RegionCapabilityRequestError" diff --git a/indra/newview/skins/default/xui/es/floater_about.xml b/indra/newview/skins/default/xui/es/floater_about.xml index 8f143cf072..f59f534908 100644 --- a/indra/newview/skins/default/xui/es/floater_about.xml +++ b/indra/newview/skins/default/xui/es/floater_about.xml @@ -19,7 +19,6 @@ con contribuciones de código abierto de:</text> expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm y Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. - GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University y David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/skins/default/xui/fr/floater_about.xml b/indra/newview/skins/default/xui/fr/floater_about.xml index 1e2a14ab3e..df6b61e293 100644 --- a/indra/newview/skins/default/xui/fr/floater_about.xml +++ b/indra/newview/skins/default/xui/fr/floater_about.xml @@ -19,7 +19,6 @@ avec les contributions Open Source de :</text> expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm et Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. - GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University, et David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/skins/default/xui/it/floater_about.xml b/indra/newview/skins/default/xui/it/floater_about.xml index 9603238b66..edb334e13e 100644 --- a/indra/newview/skins/default/xui/it/floater_about.xml +++ b/indra/newview/skins/default/xui/it/floater_about.xml @@ -19,7 +19,6 @@ con contributi open source da:</text> expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm e Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. - GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University e David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/skins/default/xui/ja/floater_about.xml b/indra/newview/skins/default/xui/ja/floater_about.xml index cf5e97bd8d..6a39d057e2 100644 --- a/indra/newview/skins/default/xui/ja/floater_about.xml +++ b/indra/newview/skins/default/xui/ja/floater_about.xml @@ -19,7 +19,6 @@ DBus/dbus-glib Copyright (C) 2002, 2003 CodeFactory AB / Copyright (C) 2003, 20 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. -GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/skins/default/xui/pt/floater_about.xml b/indra/newview/skins/default/xui/pt/floater_about.xml index 65c457f822..3c0ca332ac 100644 --- a/indra/newview/skins/default/xui/pt/floater_about.xml +++ b/indra/newview/skins/default/xui/pt/floater_about.xml @@ -19,7 +19,6 @@ com contribuições de código aberto de:</text> expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. - GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University e David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/skins/default/xui/ru/floater_about.xml b/indra/newview/skins/default/xui/ru/floater_about.xml index ee9f82847d..44216e0430 100644 --- a/indra/newview/skins/default/xui/ru/floater_about.xml +++ b/indra/newview/skins/default/xui/ru/floater_about.xml @@ -19,7 +19,6 @@ expat (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType (C) 1996-2002, 2006 David Turner, Robert Wilhelm и Werner Lemberg. GL (C) 1999-2004 Brian Paul. - GLOD (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Университет Джона Гопкинса и David Luebke, Brenden Schubert, Университет Вирджинии. google-perftools (c) 2005, Google Inc. Havok.com(TM) (C) 1999-2001, Telekinesys Research Limited. jpeg2000 (C) 2001, David Taubman, Университет Нового Южного Уэльса (UNSW) diff --git a/indra/newview/skins/default/xui/tr/floater_about.xml b/indra/newview/skins/default/xui/tr/floater_about.xml index b91575954b..faa504a996 100644 --- a/indra/newview/skins/default/xui/tr/floater_about.xml +++ b/indra/newview/skins/default/xui/tr/floater_about.xml @@ -19,7 +19,6 @@ açık kaynak kod katkısında bulunanlar şunlardır:</text> expat Telif Hakkı (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Telif Hakkı (C) 1996-2002, 2006 David Turner, Robert Wilhelm ve Werner Lemberg. GL Telif Hakkı (C) 1999-2004 Brian Paul. - GLOD Telif Hakkı (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University ve David Luebke, Brenden Schubert, University of Virginia. google-perftools Telif Hakkı (c) 2005, Google Inc. Havok.com(TM) Telif Hakkı (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Telif Hakkı (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/skins/default/xui/zh/floater_about.xml b/indra/newview/skins/default/xui/zh/floater_about.xml index 9f6b4421a9..d7d2a52750 100644 --- a/indra/newview/skins/default/xui/zh/floater_about.xml +++ b/indra/newview/skins/default/xui/zh/floater_about.xml @@ -19,7 +19,6 @@ expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd. FreeType Copyright (C) 1996-2002, 2006 David Turner, Robert Wilhelm, and Werner Lemberg. GL Copyright (C) 1999-2004 Brian Paul. - GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. google-perftools Copyright (c) 2005, Google Inc. Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited. jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index c9aa82f7d4..76160b73ba 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -505,14 +505,6 @@ class WindowsManifest(ViewerManifest): # Get shared libs from the shared libs staging directory with self.prefix(src=os.path.join(self.args['build'], os.pardir, 'sharedlibs', self.args['configuration'])): - - # Mesh 3rd party libs needed for auto LOD and collada reading - try: - self.path("glod.dll") - except RuntimeError as err: - print(err.message) - print("Skipping GLOD library (assumming linked statically)") - # Get fmodstudio dll if needed if self.args['fmodstudio'] == 'ON': if(self.args['configuration'].lower() == 'debug'): @@ -1023,7 +1015,6 @@ class DarwinManifest(ViewerManifest): "libapr-1.0.dylib", "libaprutil-1.0.dylib", "libexpat.1.dylib", - "libGLOD.dylib", # libnghttp2.dylib is a symlink to # libnghttp2.major.dylib, which is a symlink to # libnghttp2.version.dylib. Get all of them. @@ -1500,7 +1491,6 @@ class Linux_i686_Manifest(LinuxManifest): self.path("libaprutil-1.so.0.4.1") self.path("libdb*.so") self.path("libexpat.so.*") - self.path("libGLOD.so") self.path("libuuid.so*") self.path("libSDL-1.2.so.*") self.path("libdirectfb-1.*.so.*") diff --git a/indra/test/test.cpp b/indra/test/test.cpp index 87c4a8d8a3..bb48216b2b 100644 --- a/indra/test/test.cpp +++ b/indra/test/test.cpp @@ -112,6 +112,7 @@ public: virtual void recordMessage(LLError::ELevel level, const std::string& message) { + LL_PROFILE_ZONE_SCOPED mFile << message << std::endl; } |