diff options
59 files changed, 2178 insertions, 1618 deletions
diff --git a/.gitignore b/.gitignore index 4af34870cf..3619681d82 100755 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,7 @@ build-vc120-32/ build-vc120-64/ build-vc150-32/ build-vc150-64/ +build-vc160-64/ indra/CMakeFiles indra/build-vc[0-9]* indra/lib/mono/1.0/*.dll diff --git a/doc/contributions.txt b/doc/contributions.txt index a8deb9c2ae..537df59c8c 100755 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -271,6 +271,7 @@ Beq Janus SL-14766 SL-14927 SL-15709 + SL-16021 Beth Walcher Bezilon Kasei Biancaluce Robbiani diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 46ddb9d15b..75601ddfcb 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -97,6 +97,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) 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..ba821667c7 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, @@ -123,6 +124,7 @@ protected: // explicit transformation members LLXformMatrix mXform; + LLMatrix4a mWorldMatrix; LLVector3 mDefaultPosition; LLVector3 mDefaultScale; @@ -259,6 +261,8 @@ public: const LLMatrix4 &getWorldMatrix(); void setWorldMatrix( const LLMatrix4& mat ); + const LLMatrix4a& getWorldMatrix4a(); + void updateWorldMatrixChildren(); void updateWorldMatrixParent(); diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 8355df9045..f7af181927 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 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 if (LLError::getAlwaysFlush()) { mFile << message << std::endl; @@ -208,6 +210,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED static std::string s_ansi_error = createANSI("31"); // red static std::string s_ansi_warn = createANSI("34"); // blue static std::string s_ansi_debug = createANSI("35"); // magenta @@ -220,7 +223,8 @@ namespace { } else { - fprintf(stderr, "%s\n", message.c_str()); + LL_PROFILE_ZONE_NAMED("fprintf"); + fprintf(stderr, "%s\n", message.c_str()); } } @@ -229,6 +233,7 @@ namespace { LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) { + LL_PROFILE_ZONE_SCOPED static std::string s_ansi_bold = createANSI("1"); // bold static std::string s_ansi_reset = createANSI("0"); // reset // ANSI color code escape sequence, message, and reset in one fprintf call @@ -265,6 +270,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED mBuffer->addLine(message); } @@ -291,6 +297,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { + LL_PROFILE_ZONE_SCOPED debugger_print(message); } }; @@ -1178,6 +1185,7 @@ namespace void writeToRecorders(const LLError::CallSite& site, const std::string& message) { + LL_PROFILE_ZONE_SCOPED LLError::ELevel level = site.mLevel; LLError::SettingsConfigPtr s = LLError::Settings::getInstance()->getSettingsConfig(); @@ -1311,6 +1319,7 @@ namespace LLError bool Log::shouldLog(CallSite& site) { + LL_PROFILE_ZONE_SCOPED LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5); if (!lock.isLocked()) { @@ -1354,6 +1363,7 @@ namespace LLError void Log::flush(const std::ostringstream& out, const CallSite& site) { + LL_PROFILE_ZONE_SCOPED 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/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/llmutex.cpp b/indra/llcommon/llmutex.cpp index 4d73c04d07..a49002b5dc 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -44,6 +44,7 @@ LLMutex::~LLMutex() void LLMutex::lock() { + LL_PROFILE_ZONE_SCOPED if(isSelfLocked()) { //redundant lock mCount++; @@ -65,6 +66,7 @@ void LLMutex::lock() void LLMutex::unlock() { + LL_PROFILE_ZONE_SCOPED if (mCount > 0) { //not the root unlock mCount--; @@ -85,6 +87,7 @@ void LLMutex::unlock() bool LLMutex::isLocked() { + LL_PROFILE_ZONE_SCOPED if (!mMutex.try_lock()) { return true; @@ -108,6 +111,7 @@ LLThread::id_t LLMutex::lockingThread() const bool LLMutex::trylock() { + LL_PROFILE_ZONE_SCOPED if(isSelfLocked()) { //redundant lock mCount++; @@ -146,17 +150,20 @@ LLCondition::~LLCondition() void LLCondition::wait() { + LL_PROFILE_ZONE_SCOPED std::unique_lock< std::mutex > lock(mMutex); mCond.wait(lock); } void LLCondition::signal() { + LL_PROFILE_ZONE_SCOPED mCond.notify_one(); } void LLCondition::broadcast() { + LL_PROFILE_ZONE_SCOPED mCond.notify_all(); } @@ -166,6 +173,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex) : mMutex(mutex), mLocked(false) { + LL_PROFILE_ZONE_SCOPED 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 if (!mMutex) return; @@ -188,6 +197,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms) LLMutexTrylock::~LLMutexTrylock() { + LL_PROFILE_ZONE_SCOPED if (mMutex && mLocked) mMutex->unlock(); } @@ -199,6 +209,7 @@ LLMutexTrylock::~LLMutexTrylock() // LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex) { + LL_PROFILE_ZONE_SCOPED if(mutex) { mutex->lock(); @@ -217,6 +228,7 @@ LLScopedLock::~LLScopedLock() void LLScopedLock::unlock() { + LL_PROFILE_ZONE_SCOPED if(mLocked) { mMutex->unlock(); diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 4e61fb8a58..6d5d043e8d 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -861,6 +861,7 @@ LLSD LLMemoryInfo::getStatsMap() const LLMemoryInfo& LLMemoryInfo::refresh() { + LL_PROFILE_ZONE_SCOPED mStatsMap = loadStatsMap(); LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n"; diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index a8cc750437..11f5a015f1 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -333,6 +333,7 @@ bool LLThread::runCondition(void) // Stop thread execution if requested until unpaused. void LLThread::checkPause() { + LL_PROFILE_ZONE_SCOPED mDataLock->lock(); // This is in a while loop because the pthread API allows for spurious wakeups. @@ -364,17 +365,20 @@ void LLThread::setQuitting() // static LLThread::id_t LLThread::currentID() { + LL_PROFILE_ZONE_SCOPED return std::this_thread::get_id(); } // static void LLThread::yield() { + LL_PROFILE_ZONE_SCOPED std::this_thread::yield(); } void LLThread::wake() { + LL_PROFILE_ZONE_SCOPED mDataLock->lock(); if(!shouldSleep()) { @@ -385,6 +389,7 @@ void LLThread::wake() void LLThread::wakeLocked() { + LL_PROFILE_ZONE_SCOPED if(!shouldSleep()) { mRunCondition->signal(); @@ -393,11 +398,13 @@ void LLThread::wakeLocked() void LLThread::lockData() { + LL_PROFILE_ZONE_SCOPED mDataLock->lock(); } void LLThread::unlockData() { + LL_PROFILE_ZONE_SCOPED mDataLock->unlock(); } 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/llmath/llmatrix4a.h b/indra/llmath/llmatrix4a.h index 7ba347062f..5291a05607 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,6 +64,14 @@ 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]); @@ -105,7 +133,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 +179,8 @@ public: { affineTransformSSE(v,res); } + + const LLVector4a& getTranslation() const { return mMatrix[3]; } }; inline LLVector4a rowMul(const LLVector4a &row, const LLMatrix4a &mat) @@ -176,6 +206,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/llvector4a.h b/indra/llmath/llvector4a.h index 27abf39537..5a02928374 100644 --- a/indra/llmath/llvector4a.h +++ b/indra/llmath/llvector4a.h @@ -46,10 +46,9 @@ 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 LLVector4a { 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 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/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/llprimitive/lldaeloader.cpp b/indra/llprimitive/lldaeloader.cpp index dfa29fb539..8343de0cbc 100644 --- a/indra/llprimitive/lldaeloader.cpp +++ b/indra/llprimitive/lldaeloader.cpp @@ -1173,17 +1173,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); } @@ -1401,7 +1403,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)); } } } @@ -1475,9 +1477,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 { diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp index 702a1b5238..a23b991f1d 100644 --- a/indra/llprimitive/llmodel.cpp +++ b/indra/llprimitive/llmodel.cpp @@ -1396,7 +1396,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) } } - mInvBindMatrix.push_back(mat); + mInvBindMatrix.push_back(LLMatrix4a(mat)); } if (mJointNames.size() != mInvBindMatrix.size()) @@ -1410,13 +1410,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")) @@ -1432,7 +1434,7 @@ void LLMeshSkinInfo::fromLLSD(LLSD& skin) } } - mAlternateBindMatrix.push_back(mat); + mAlternateBindMatrix.push_back(LLMatrix4a(mat)); } } diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h index 51fa2f8079..96d4582b4f 100644 --- a/indra/llprimitive/llmodel.h +++ b/indra/llprimitive/llmodel.h @@ -33,6 +33,8 @@ #include "m4math.h" #include <queue> +#include <boost/align/aligned_allocator.hpp> + class daeElement; class domMesh; @@ -49,10 +51,11 @@ public: 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; - LLMatrix4 mBindShapeMatrix; + LLMatrix4a mBindShapeMatrix; float mPelvisOffset; bool mLockScaleIfJointPosition; bool mInvalidJointsScrubbed; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 4351f6e2c8..9ab38d25a9 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -126,6 +126,7 @@ struct LLGLSLShaderCompareTimeElapsed //static void LLGLSLShader::finishProfile(bool emit_report) { + LL_PROFILE_ZONE_SCOPED sProfileEnabled = false; if (emit_report) @@ -1346,6 +1347,7 @@ 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; if (mProgramObject) { if (mUniform.size() <= index) diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 0151d20128..276fa55e15 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1304,7 +1304,10 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt } stop_glerror(); - glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); + { + LL_PROFILE_ZONE_NAMED("glTexImage2D"); + glTexImage2D(target, miplevel, intformat, width, height, 0, pixformat, pixtype, use_scratch ? scratch : pixels); + } stop_glerror(); if (use_scratch) diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 03b6aac20c..43b4441ea8 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -1848,6 +1848,7 @@ LLLightState* LLRender::getLight(U32 index) void LLRender::setAmbientLightColor(const LLColor4& color) { + LL_PROFILE_ZONE_SCOPED if (color != mAmbientLightColor) { ++mLightHash; diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index b69b644ebc..0449ac392c 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 - 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 if (gGLManager.mInited) { LLVertexBuffer::unbind(); @@ -152,6 +159,7 @@ LLVBOPool::LLVBOPool(U32 vboUsage, U32 vboType) volatile U8* LLVBOPool::allocate(U32& name, U32 size, bool for_seed) { + LL_PROFILE_ZONE_SCOPED llassert(vbo_block_size(size) == size); volatile U8* ret = NULL; @@ -267,10 +275,12 @@ void LLVBOPool::release(U32 name, volatile U8* buffer, U32 size) void LLVBOPool::seedPool() { + LL_PROFILE_ZONE_SCOPED U32 dummy_name = 0; if (mFreeList.size() < LL_VBO_POOL_SEED_COUNT) { + LL_PROFILE_ZONE_NAMED("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 sStreamVBOPool.seedPool(); sDynamicVBOPool.seedPool(); sDynamicCopyVBOPool.seedPool(); diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index dbe1a3687f..1d60970df4 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -89,6 +89,9 @@ public: 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; }; @@ -127,7 +130,7 @@ public: static LLVBOPool sDynamicCopyVBOPool; static LLVBOPool sStreamIBOPool; static LLVBOPool sDynamicIBOPool; - + static std::list<U32> sAvailableVAOName; static U32 sCurVAOName; diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 1b8881cc86..4ce7c30bef 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -28,6 +28,8 @@ #if LL_WINDOWS && !LL_MESA_HEADLESS +#define LL_WINDOW_SINGLE_THREADED 0 + #include "llwindowwin32.h" // LLWindow library includes @@ -45,6 +47,7 @@ #include "lldir.h" #include "llsdutil.h" #include "llglslshader.h" +#include "llthreadsafequeue.h" // System includes #include <commdlg.h> @@ -79,6 +82,18 @@ const F32 ICON_FLASH_TIME = 0.5f; extern BOOL gDebugWindowProc; +static std::thread::id sWindowThreadId; +static std::thread::id sMainThreadId; + +#if 1 || LL_WINDOW_SINGLE_THREADED +#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; @@ -294,7 +309,7 @@ LLWinImm::LLWinImm() : mHImmDll(NULL) // static -BOOL LLWinImm::isIME(HKL hkl) +BOOL LLWinImm::isIME(HKL hkl) { if ( sTheInstance.mImmIsIME ) return sTheInstance.mImmIsIME(hkl); @@ -326,7 +341,7 @@ BOOL LLWinImm::getOpenStatus(HIMC himc) } // static -BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) +BOOL LLWinImm::setOpenStatus(HIMC himc, BOOL status) { if ( sTheInstance.mImmSetOpenStatus ) return sTheInstance.mImmSetOpenStatus(himc, status); @@ -454,6 +469,8 @@ private: static LLMonitorInfo sMonitorInfo; + + LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, const std::string& title, const std::string& name, S32 x, S32 y, S32 width, S32 height, U32 flags, @@ -463,7 +480,11 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, U32 fsaa_samples) : LLWindow(callbacks, fullscreen, flags) { - + sMainThreadId = LLThread::currentID(); + mWindowThread = new LLWindowWin32Thread(this); +#if !LL_WINDOW_SINGLE_THREADED + mWindowThread->start(); +#endif //MAINT-516 -- force a load of opengl32.dll just in case windows went sideways LoadLibrary(L"opengl32.dll"); @@ -784,7 +805,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, disable_vsync, &windowPos)) { return; } @@ -811,6 +832,8 @@ LLWindowWin32::~LLWindowWin32() delete [] mWindowClassName; mWindowClassName = NULL; + + delete mWindowThread; } void LLWindowWin32::show() @@ -930,26 +953,35 @@ 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 + 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; + + mWindowThread->mFinished = true; + }); + + while (!mWindowThread->isStopped()) { - // 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; + std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - - mWindowHandle = NULL; } BOOL LLWindowWin32::isValid() @@ -1090,171 +1122,203 @@ BOOL LLWindowWin32::setSizeImpl(const LLCoordWindow size) } // 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 disable_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)) + + auto oldHandle = mWindowHandle; + + //zero out mWindowHandle and mhDC before destroying window so window thread falls back to peekmessage + mWindowHandle = 0; + mhDC = 0; + + if (oldHandle && !destroy_window_handler(oldHandle)) { 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); + } + + mWindowHandle = NULL; + mhDC = 0; + + mWindowThread->post( + [this, window_rect, dw_ex_style, dw_style]() + { + 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); + + if (mWindowHandle) + { + mhDC = GetDC(mWindowHandle); + } + } + ); + + // HACK wait for above handle to become populated + // TODO: use a future + int count = 1024; + while (!mhDC && count > 0) + { + Sleep(10); + --count; + } if (mWindowHandle) { @@ -1288,7 +1352,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 +1646,48 @@ const S32 max_format = (S32)num_formats - 1; mhDC = 0; // Zero The Device Context } + auto oldHandle = mWindowHandle; + mWindowHandle = NULL; + mhDC = 0; + // Destroy The Window - if (mWindowHandle && !destroy_window_handler(mWindowHandle)) + if (oldHandle && !destroy_window_handler(oldHandle)) { 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); + mWindowThread->post( + [this, window_rect, dw_ex_style, dw_style]() + { + 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); + + if (mWindowHandle) + { + mhDC = GetDC(mWindowHandle); + } + } + ); + // HACK wait for above handle to become populated + // TODO: use a future + int count = 1024; + while (!mhDC && count > 0) + { + PostMessage(oldHandle, WM_USER + 8, 0x1717, 0x3b3b); + Sleep(10); + --count; + } if (mWindowHandle) { @@ -1612,7 +1699,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); @@ -1766,6 +1853,7 @@ const S32 max_format = (S32)num_formats - 1; else { LL_DEBUGS("Window") << "Keeping vertical sync" << LL_ENDL; + wglSwapIntervalEXT(1); } SetWindowLongPtr(mWindowHandle, GWLP_USERDATA, (LONG_PTR)this); @@ -1815,31 +1903,41 @@ void LLWindowWin32::moveWindow( const LLCoordScreen& position, const LLCoordScre BOOL LLWindowWin32::setCursorPosition(const LLCoordWindow position) { - mMousePositionModified = TRUE; + ASSERT_MAIN_THREAD(); + if (!mWindowHandle) { return FALSE; } - - // Inform the application of the new mouse position (needed for per-frame + // 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); + mMousePositionModified = TRUE; + LLCoordScreen screen_pos(position.convert()); + + mWindowThread->post([=] + { + SetCursorPos(screen_pos.mX, screen_pos.mY); + // 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)) + { + } + + mMousePositionModified = FALSE; + }); + + return TRUE; } BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) { + ASSERT_MAIN_THREAD(); POINT cursor_point; if (!mWindowHandle @@ -1855,21 +1953,35 @@ BOOL LLWindowWin32::getCursorPosition(LLCoordWindow *position) 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; + + 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 +2083,8 @@ void LLWindowWin32::initCursors() void LLWindowWin32::updateCursor() { + ASSERT_MAIN_THREAD(); + LL_PROFILE_ZONE_SCOPED if (mNextCursor == UI_CURSOR_ARROW && mBusyCount > 0) { @@ -1980,7 +2094,11 @@ void LLWindowWin32::updateCursor() if( mCurrentCursor != mNextCursor ) { mCurrentCursor = mNextCursor; - SetCursor( mCursor[mNextCursor] ); + auto nextCursor = mCursor[mNextCursor]; + mWindowThread->post([=]() + { + SetCursor(nextCursor); + }); } } @@ -1996,13 +2114,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; ReleaseCapture(); - mCallbacks->handleResumeWatchdog(this); } @@ -2011,1003 +2124,1129 @@ void LLWindowWin32::delayInputProcessing() mInputProcessingPaused = TRUE; } + void LLWindowWin32::gatherInput() { - MSG msg; - int msg_count = 0; + ASSERT_MAIN_THREAD(); + LL_PROFILE_ZONE_SCOPED + MSG msg; - while ((msg_count < MAX_MESSAGE_PER_UPDATE) && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) - { - mCallbacks->handlePingWatchdog(this, "Main:TranslateGatherInput"); - TranslateMessage(&msg); +#if LL_WINDOW_SINGLE_THREADED + int msg_count = 0; - // turn watchdog off in here to not fail if windows is doing something wacky - mCallbacks->handlePauseWatchdog(this); - DispatchMessage(&msg); - mCallbacks->handleResumeWatchdog(this); - msg_count++; + while ((msg_count < MAX_MESSAGE_PER_UPDATE)) + { + LL_PROFILE_ZONE_NAMED("gi - loop"); + ++msg_count; + { + LL_PROFILE_ZONE_NAMED("gi - PeekMessage"); + if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + break; + } + } - if ( mInputProcessingPaused ) - { - break; - } - /* Attempted workaround for problem where typing fast and hitting - return would result in only part of the text being sent. JC + { + LL_PROFILE_ZONE_NAMED("gi - translate"); + TranslateMessage(&msg); + } - BOOL key_posted = TranslateMessage(&msg); - DispatchMessage(&msg); - msg_count++; + { + LL_PROFILE_ZONE_NAMED("gi - dispatch"); + DispatchMessage(&msg); + } - // 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); - } - } + if (mInputProcessingPaused) + { + break; + } + + // For async host by name support. Really hacky. + if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) + { + LL_PROFILE_ZONE_NAMED("gi - callback"); + gAsyncMsgCallback(msg); + } + } +#else //multi-threaded window impl + { + if (mWindowThread->mFunctionQueue.size() > 0) + { + LL_PROFILE_ZONE_NAMED("gi - PostMessage"); + if (mWindowHandle) + { // 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 + PostMessage(mWindowHandle, WM_USER + 0x0017, 0xB0B0, 0x1337); + } + } + + while (mWindowThread->mMessageQueue.tryPopBack(msg)) + { + LL_PROFILE_ZONE_NAMED("gi - message queue"); + if (mInputProcessingPaused) + { + continue; + } + + // For async host by name support. Really hacky. + if (gAsyncMsgCallback && (LL_WM_HOST_RESOLVED == msg.message)) + { + LL_PROFILE_ZONE_NAMED("gi - callback"); + gAsyncMsgCallback(msg); + } + } + } + + { + LL_PROFILE_ZONE_NAMED("gi - function queue"); + //process any pending functions + std::function<void()> curFunc; + while (mFunctionQueue.tryPopBack(curFunc)) + { + curFunc(); + } + } +#endif 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"); +#if LL_WINDOW_SINGLE_THREADED +#define WINDOW_IMP_POST(x) x +#else +#define WINDOW_IMP_POST(x) window_imp->post([=]() { x; }) +#endif + 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; - - 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); + ASSERT_WINDOW_THREAD(); + LL_PROFILE_ZONE_SCOPED; - BOOL minimized = BOOL(HIWORD(w_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; - 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; - } + // 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; - case WM_QUERYOPEN: - // TODO: use this to return a nice icon - break; + LLWindowWin32* window_imp = (LLWindowWin32*)GetWindowLongPtr(h_wnd, GWLP_USERDATA); - 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; + bool debug_window_proc = false; // gDebugWindowProc || debugLoggingEnabled("Window"); - 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; - - 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; - - 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; - - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_KEYUP"); - LL_RECORD_BLOCK_TIME(FTM_KEYHANDLER); - - 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; - } + if (NULL != window_imp) + { + // Has user provided their own window callback? + if (NULL != window_imp->mWndProc) + { + LL_PROFILE_ZONE_NAMED("mwp - WndProc"); + if (!window_imp->mWndProc(h_wnd, u_msg, w_param, l_param)) + { + // user has handled window message + return 0; + } + } - // 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; + // 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; + // This doesn't work, as LOWORD returns unsigned short. + //LLCoordWindow window_coord(LOWORD(l_param), HIWORD(l_param)); + LLCoordGL gl_coord; - 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; + // pass along extended flag in mask + MASK mask = (l_param >> 16 & KF_EXTENDED) ? MASK_EXTENDED : 0x0; + BOOL eat_keystroke = TRUE; - 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; + switch (u_msg) + { + RECT update_rect; + S32 update_width; + S32 update_height; - 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_TIMER: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_TIMER"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleTimerEvent(window_imp)); + 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_DEVICECHANGE: + { + LL_PROFILE_ZONE_NAMED("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_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_PAINT: + { + LL_PROFILE_ZONE_NAMED("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_LBUTTONDOWN: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONDOWN"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); - sHandleLeftMouseUp = true; + case WM_SETCURSOR: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_SETCURSOR"); + // This message is sent whenever the cursor is moved in a window. + // You need to set the appropriate cursor appearance. - if (LLWinImm::isAvailable() && window_imp->mPreeditor) - { - window_imp->interruptLanguageTextInput(); - } + // 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("mwp - WM_ENTERMENULOOP"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowBlock(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_EXITMENULOOP: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_EXITMENULOOP"); + WINDOW_IMP_POST(window_imp->mCallbacks->handleWindowUnblock(window_imp)); + 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_ACTIVATEAPP: + { + LL_PROFILE_ZONE_NAMED("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("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; + } - if (!sHandleDoubleClick) - { - sHandleDoubleClick = true; - break; - } + case WM_QUERYOPEN: + // TODO: use this to return a nice icon + 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_SYSCOMMAND: + { + LL_PROFILE_ZONE_NAMED("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("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("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("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("mwp - WM_SYSKEYDOWN"); + // allow system keys, such as ALT-F4 to be processed by Windows + eat_keystroke = FALSE; + } + case WM_KEYDOWN: + { + LL_PROFILE_ZONE_NAMED("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); + } + }); + return eat_keystroke; + } + case WM_SYSKEYUP: + eat_keystroke = FALSE; + case WM_KEYUP: + { + LL_PROFILE_ZONE_NAMED("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); + } + }); + return eat_keystroke; + } + case WM_IME_SETCONTEXT: + { + LL_PROFILE_ZONE_NAMED("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("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("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("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("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("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("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("mwp - WM_LBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + window_imp->post([=]() + { + auto glc = gl_coord; + sHandleLeftMouseUp = true; + + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + // 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); + glc = cursor_coord_window.convert(); + } + else + { + glc = window_coord.convert(); + } + MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, glc, mask); + window_imp->mCallbacks->handleMouseDown(window_imp, glc, mask); + }); + + return 0; + } + break; + } - case WM_LBUTTONUP: - { - window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_LBUTTONUP"); - LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + case WM_LBUTTONDBLCLK: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONDBLCLK"); + //RN: ignore right button double clicks for now + //case WM_RBUTTONDBLCLK: + if (!sHandleDoubleClick) + { + sHandleDoubleClick = true; + return 0; + } - 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; + // 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->post([=]() + { + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + window_imp->mCallbacks->handleDoubleClick(window_imp, gl_coord, mask); + }); + return 0; + } + case WM_LBUTTONUP: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_LBUTTONUP"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + + if (!sHandleLeftMouseUp) + { + sHandleLeftMouseUp = true; + return 0; + } + sHandleDoubleClick = true; + window_imp->post([=]() + { + auto glc = gl_coord; + + //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); + glc = cursor_coord_window.convert(); + } + else + { + glc = window_coord.convert(); + } + MASK mask = gKeyboard->currentMask(TRUE); + // generate move event to update mouse coordinates + window_imp->mCallbacks->handleMouseMove(window_imp, glc, mask); + window_imp->mCallbacks->handleMouseUp(window_imp, glc, mask); + }); + } + return 0; + } + case WM_RBUTTONDBLCLK: + case WM_RBUTTONDOWN: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_RBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + WINDOW_IMP_POST(window_imp->interruptLanguageTextInput()); + } + + // 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->post([=]() + { + window_imp->mCallbacks->handleMouseMove(window_imp, gl_coord, mask); + window_imp->mCallbacks->handleRightMouseDown(window_imp, gl_coord, mask); + }); + } + return 0; + } + 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_RBUTTONUP: + { + LL_PROFILE_ZONE_NAMED("mwp - 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; - // 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_MBUTTONDOWN: + // case WM_MBUTTONDBLCLK: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_MBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + // 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_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; + case WM_MBUTTONUP: + { + LL_PROFILE_ZONE_NAMED("mwp - 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: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONDOWN"); + { + LL_RECORD_BLOCK_TIME(FTM_MOUSEHANDLER); + S32 button = GET_XBUTTON_WPARAM(w_param); + if (LLWinImm::isAvailable() && window_imp->mPreeditor) + { + window_imp->interruptLanguageTextInput(); + } + + // 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; - 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(); - } + case WM_XBUTTONUP: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_XBUTTONUP"); + { + 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; - // 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("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) + { + 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: + { + LL_PROFILE_ZONE_NAMED("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("mwp - WM_MOUSEMOVE"); + if (!window_imp->mMousePositionModified) + { + MASK mask = gKeyboard->currentMask(TRUE); + WINDOW_IMP_POST(window_imp->mCallbacks->handleMouseMove(window_imp, window_coord.convert(), mask)); + } + 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("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_SIZE: + { + LL_PROFILE_ZONE_NAMED("mwp - WM_SIZE"); + 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("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("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("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("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("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; - - 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); - } + //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_MOVE: + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + break; + + default: + { + LL_PROFILE_ZONE_NAMED("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("mwp - DefWindowProc"); + ret = DefWindowProc(h_wnd, u_msg, w_param, l_param); + } + return ret; } BOOL LLWindowWin32::convertCoords(LLCoordGL from, LLCoordWindow *to) @@ -3186,6 +3425,8 @@ BOOL LLWindowWin32::copyTextToClipboard(const LLWString& wstr) // Constrains the mouse to the window. void LLWindowWin32::setMouseClipping( BOOL b ) { + LL_PROFILE_ZONE_SCOPED; + ASSERT_MAIN_THREAD(); if( b != mIsMouseClipping ) { BOOL success = FALSE; @@ -3262,6 +3503,7 @@ F32 LLWindowWin32::getGamma() BOOL LLWindowWin32::restoreGamma() { + ASSERT_MAIN_THREAD(); if (mCustomGammaSet != FALSE) { LL_DEBUGS("Window") << "Restoring gamma" << LL_ENDL; @@ -3273,6 +3515,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 +3554,7 @@ BOOL LLWindowWin32::setGamma(const F32 gamma) void LLWindowWin32::setFSAASamples(const U32 fsaa_samples) { + ASSERT_MAIN_THREAD(); mFSAASamples = fsaa_samples; } @@ -3321,6 +3565,7 @@ U32 LLWindowWin32::getFSAASamples() LLWindow::LLWindowResolution* LLWindowWin32::getSupportedResolutions(S32 &num_resolutions) { + ASSERT_MAIN_THREAD(); if (!mSupportedResolutions) { mSupportedResolutions = new LLWindowResolution[MAX_NUM_RESOLUTIONS]; @@ -3475,6 +3720,7 @@ BOOL LLWindowWin32::resetDisplayResolution() void LLWindowWin32::swapBuffers() { + ASSERT_MAIN_THREAD(); SwapBuffers(mhDC); LL_PROFILER_GPU_COLLECT @@ -3950,6 +4196,7 @@ void LLWindowWin32::updateLanguageTextInputArea() void LLWindowWin32::interruptLanguageTextInput() { + ASSERT_MAIN_THREAD(); if (mPreeditor && LLWinImm::isAvailable()) { HIMC himc = LLWinImm::getContext(mWindowHandle); @@ -4152,6 +4399,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 ); } @@ -4200,6 +4448,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; @@ -4407,3 +4656,79 @@ std::vector<std::string> LLWindowWin32::getDynamicFallbackFontList() #endif // LL_WINDOWS + +inline LLWindowWin32Thread::LLWindowWin32Thread(LLWindowWin32* window) + : LLThread("Window Thread"), + mWindow(window), + mFunctionQueue(MAX_QUEUE_SIZE) +{ + +} + +inline void LLWindowWin32Thread::run() +{ + sWindowThreadId = getID(); + while (!mFinished) + { + LL_PROFILE_ZONE_SCOPED; + + + if (mWindow && mWindow->mWindowHandle != 0) + { + MSG msg; + BOOL status; + if (mWindow->mhDC == 0) + { + LL_PROFILE_ZONE_NAMED("w32t - PeekMessage"); + status = PeekMessage(&msg, mWindow->mWindowHandle, 0, 0, PM_REMOVE); + } + else + { + LL_PROFILE_ZONE_NAMED("w32t - GetMessage"); + status = GetMessage(&msg, mWindow->mWindowHandle, 0, 0); + } + if (status > 0) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + + mMessageQueue.pushFront(msg); + } + } + + { + LL_PROFILE_ZONE_NAMED("w32t - Function Queue"); + //process any pending functions + std::function<void()> curFunc; + while (mFunctionQueue.tryPopBack(curFunc)) + { + curFunc(); + } + } + +#if 0 + { + LL_PROFILE_ZONE_NAMED("w32t - Sleep"); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } +#endif + } +} + +void LLWindowWin32Thread::post(const std::function<void()>& func) +{ +#if LL_WINDOW_SINGLE_THREADED + func(); +#else + mFunctionQueue.pushFront(func); +#endif +} + +void LLWindowWin32::post(const std::function<void()>& func) +{ +#if LL_WINDOW_SINGLE_THREADED + func(); +#else + mFunctionQueue.pushFront(func); +#endif +}
\ No newline at end of file diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 0b3d14fb16..66647459b2 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -33,11 +33,46 @@ #include "llwindow.h" #include "llwindowcallbacks.h" #include "lldragdropwin32.h" +#include "llthread.h" +#include "llthreadsafequeue.h" // Hack for async host by name #define LL_WM_HOST_RESOLVED (WM_APP + 1) typedef void (*LLW32MsgCallback)(const MSG &msg); +class LLWindowWin32; + +// Thread that owns the Window Handle +class LLWindowWin32Thread : public LLThread +{ +public: + class Message + { + public: + LRESULT mMsg; + }; + + static const int MAX_QUEUE_SIZE = 2048; + + LLThreadSafeQueue<MSG> mMessageQueue; + LLThreadSafeQueue<std::function<void()>> mFunctionQueue; + + bool mFinished = false; + + LLWindowWin32Thread(LLWindowWin32* window); + + void run() override; + + void post(const std::function<void()>& func); + +private: + + // call PeekMessage and pull enqueue messages for later processing + void gatherInput(); + LLWindowWin32* mWindow = nullptr; + +}; + class LLWindowWin32 : public LLWindow { public: @@ -172,9 +207,9 @@ 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() @@ -221,7 +256,12 @@ protected: BOOL mMouseVanish; + LLWindowWin32Thread* mWindowThread = nullptr; + LLThreadSafeQueue<std::function<void()>> mFunctionQueue; + void post(const std::function<void()>& func); + friend class LLWindowManager; + friend class LLWindowWin32Thread; }; class LLSplashScreenWin32 : public LLSplashScreen diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index b1120c18b2..05c3fc3bfe 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> @@ -3366,13 +3355,13 @@ <key>DisableVerticalSync</key> <map> <key>Comment</key> - <string>Update frames as fast as possible (FALSE = update frames between display scans)</string> + <string>Update frames as fast as possible (FALSE = update frames between display scans). Requires restart.</string> <key>Persist</key> <integer>1</integer> <key>Type</key> <string>Boolean</string> <key>Value</key> - <integer>1</integer> + <integer>0</integer> </map> <key>EnableGroupChatPopups</key> <map> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 879cc6fc85..3d49a9eb78 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -694,8 +694,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) { @@ -1326,10 +1325,6 @@ 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(); @@ -1542,24 +1537,6 @@ bool LLAppViewer::doFrame() 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_SLEEP1); - LL_PROFILE_ZONE_WARN( "Sleep1" ) - // llclamp for when time function gets funky - U64 sleep_time = llclamp(mMinMicroSecPerFrame - elapsed_time, (U64)1, (U64)1e6); - - LL_PROFILE_ZONE_NUM( sleep_time ) - micro_sleep(sleep_time, 0); - } - } - last_call = LLTimer::getTotalTime(); - { LL_PROFILE_ZONE_NAMED( "df Snapshot" ) pingMainloopTimeout("Main:Snapshot"); @@ -2524,12 +2501,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); @@ -5657,19 +5629,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 0afb70958c..64e7caa36b 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -262,8 +262,6 @@ private: void sendLogoutRequest(); void disconnectViewer(); - bool onChangeFrameLimit(LLSD const & evt); - // *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; @@ -319,10 +317,7 @@ private: // llcorehttp library init/shutdown helper LLAppCoreHttp mAppCoreHttp; - bool mIsFirstRun; - U64 mMinMicroSecPerFrame; // frame throttling - - + bool mIsFirstRun; }; // consts from viewer.h diff --git a/indra/newview/llcontrolavatar.cpp b/indra/newview/llcontrolavatar.cpp index fab249f988..606e670805 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); diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 4f615d6107..02ab316256 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -169,6 +169,7 @@ void LLDrawPoolAvatar::prerender() { LLVOAvatar* avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); updateRiggedVertexBuffers(avatarp); + updateSkinInfoMatrixPalettes(avatarp); } } } @@ -454,221 +455,229 @@ S32 LLDrawPoolAvatar::getNumShadowPasses() void LLDrawPoolAvatar::beginShadowPass(S32 pass) { LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); + { + LL_PROFILE_ZONE_SCOPED; - if (pass == SHADOW_PASS_AVATAR_OPAQUE) - { - sVertexProgram = &gDeferredAvatarShadowProgram; - - if ((sShaderLevel > 0)) // for hardware blending - { - sRenderingSkinned = TRUE; - sVertexProgram->bind(); - } + if (pass == SHADOW_PASS_AVATAR_OPAQUE) + { + sVertexProgram = &gDeferredAvatarShadowProgram; - gGL.diffuseColor4f(1,1,1,1); - } - else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND) - { - sVertexProgram = &gDeferredAvatarAlphaShadowProgram; + if ((sShaderLevel > 0)) // for hardware blending + { + sRenderingSkinned = TRUE; + sVertexProgram->bind(); + } - // bind diffuse tex so we can reference the alpha channel... - S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); - sDiffuseChannel = 0; - if (loc != -1) + gGL.diffuseColor4f(1, 1, 1, 1); + } + else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND) { - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } + sVertexProgram = &gDeferredAvatarAlphaShadowProgram; - if ((sShaderLevel > 0)) // for hardware blending - { - sRenderingSkinned = TRUE; - sVertexProgram->bind(); - } + // 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); + } - gGL.diffuseColor4f(1,1,1,1); - } - else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK) - { - sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram; + if ((sShaderLevel > 0)) // for hardware blending + { + sRenderingSkinned = TRUE; + sVertexProgram->bind(); + } - // bind diffuse tex so we can reference the alpha channel... - S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); - sDiffuseChannel = 0; - if (loc != -1) + gGL.diffuseColor4f(1, 1, 1, 1); + } + else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK) { - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } + sVertexProgram = &gDeferredAvatarAlphaMaskShadowProgram; - if ((sShaderLevel > 0)) // for hardware blending - { - sRenderingSkinned = TRUE; - sVertexProgram->bind(); - } + // 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); + } - gGL.diffuseColor4f(1,1,1,1); - } - else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND) - { - sVertexProgram = &gDeferredAttachmentAlphaShadowProgram; + if ((sShaderLevel > 0)) // for hardware blending + { + sRenderingSkinned = TRUE; + sVertexProgram->bind(); + } - // bind diffuse tex so we can reference the alpha channel... - S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); - sDiffuseChannel = 0; - if (loc != -1) + gGL.diffuseColor4f(1, 1, 1, 1); + } + else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_BLEND) { - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - - if ((sShaderLevel > 0)) // for hardware blending - { - sRenderingSkinned = TRUE; - sVertexProgram->bind(); - } + sVertexProgram = &gDeferredAttachmentAlphaShadowProgram; - 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(); + } - // bind diffuse tex so we can reference the alpha channel... - S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); - sDiffuseChannel = 0; - if (loc != -1) + gGL.diffuseColor4f(1, 1, 1, 1); + } + else if (pass == SHADOW_PASS_ATTACHMENT_ALPHA_MASK) { - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } + sVertexProgram = &gDeferredAttachmentAlphaMaskShadowProgram; - if ((sShaderLevel > 0)) // for hardware blending - { - sRenderingSkinned = TRUE; - sVertexProgram->bind(); - } + // 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); + } - 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) + if ((sShaderLevel > 0)) // for hardware blending + { + sRenderingSkinned = TRUE; + sVertexProgram->bind(); + } + + gGL.diffuseColor4f(1, 1, 1, 1); + } + else // SHADOW_PASS_ATTACHMENT_OPAQUE { - sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); - } - sVertexProgram->bind(); - } + sVertexProgram = &gDeferredAttachmentShadowProgram; + S32 loc = sVertexProgram->getUniformLocation(LLViewerShaderMgr::DIFFUSE_MAP); + sDiffuseChannel = 0; + if (loc != -1) + { + sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); + } + sVertexProgram->bind(); + } + } } void LLDrawPoolAvatar::endShadowPass(S32 pass) { LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); + { + LL_PROFILE_ZONE_SCOPED; - if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE) - { - LLVertexBuffer::unbind(); - } + if (pass == SHADOW_PASS_ATTACHMENT_OPAQUE) + { + LLVertexBuffer::unbind(); + } - if (sShaderLevel > 0) - { - sVertexProgram->unbind(); - } - sVertexProgram = NULL; - sRenderingSkinned = FALSE; - LLDrawPoolAvatar::sShadowPass = -1; + if (sShaderLevel > 0) + { + sVertexProgram->unbind(); + } + sVertexProgram = NULL; + sRenderingSkinned = FALSE; + LLDrawPoolAvatar::sShadowPass = -1; + } } void LLDrawPoolAvatar::renderShadow(S32 pass) { - LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); + LL_RECORD_BLOCK_TIME(FTM_SHADOW_AVATAR); + { + LL_PROFILE_ZONE_SCOPED; - if (mDrawFace.empty()) - { - return; - } + if (mDrawFace.empty()) + { + return; + } - const LLFace *facep = mDrawFace[0]; - if (!facep->getDrawable()) - { - return; - } - LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); + const LLFace *facep = mDrawFace[0]; + if (!facep->getDrawable()) + { + return; + } + LLVOAvatar *avatarp = (LLVOAvatar *)facep->getDrawable()->getVObj().get(); - if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull()) - { - return; - } - LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); - BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); - if (oa == LLVOAvatar::AOA_INVISIBLE || - (impostor && oa == LLVOAvatar::AOA_JELLYDOLL)) - { - // No shadows for jellydolled or invisible avs. - return; - } - - LLDrawPoolAvatar::sShadowPass = pass; + if (avatarp->isDead() || avatarp->isUIAvatar() || avatarp->mDrawable.isNull()) + { + return; + } + LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); + BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); + if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE)) + { + // No shadows for impostored (including jellydolled) or invisible avs. + return; + } - if (pass == SHADOW_PASS_AVATAR_OPAQUE) - { - LLDrawPoolAvatar::sSkipTransparent = true; - avatarp->renderSkinned(); - LLDrawPoolAvatar::sSkipTransparent = false; - } - else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND) - { - LLDrawPoolAvatar::sSkipOpaque = true; - avatarp->renderSkinned(); - LLDrawPoolAvatar::sSkipOpaque = false; - } - else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK) - { - LLDrawPoolAvatar::sSkipOpaque = true; - 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; - } + LLDrawPoolAvatar::sShadowPass = pass; + + if (pass == SHADOW_PASS_AVATAR_OPAQUE) + { + LLDrawPoolAvatar::sSkipTransparent = true; + avatarp->renderSkinned(); + LLDrawPoolAvatar::sSkipTransparent = false; + } + else if (pass == SHADOW_PASS_AVATAR_ALPHA_BLEND) + { + LLDrawPoolAvatar::sSkipOpaque = true; + avatarp->renderSkinned(); + LLDrawPoolAvatar::sSkipOpaque = false; + } + else if (pass == SHADOW_PASS_AVATAR_ALPHA_MASK) + { + LLDrawPoolAvatar::sSkipOpaque = true; + 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() @@ -1890,7 +1899,7 @@ void LLDrawPoolAvatar::getRiggedGeometry( U16 offset = 0; - LLMatrix4 mat_vert = skin->mBindShapeMatrix; + LLMatrix4 mat_vert = LLMatrix4(skin->mBindShapeMatrix); glh::matrix4f m((F32*) mat_vert.mMatrix); m = m.inverse().transpose(); @@ -1932,7 +1941,7 @@ void LLDrawPoolAvatar::getRiggedGeometry( void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( LLVOAvatar* avatar, LLFace* face, - const LLMeshSkinInfo* skin, + const LLVOVolume* vobj, LLVolume* volume, LLVolumeFace& vol_face) { @@ -1944,14 +1953,14 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( return; } + if (!vobj || vobj->isNoLOD()) + { + 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 @@ -1991,23 +2000,26 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( } #endif - // FIXME ugly const cast - LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin)); + U32 data_mask = face->getRiggedVertexBufferDataMask(); + const LLMeshSkinInfo* skin = nullptr; - 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))) { + LL_PROFILE_ZONE_NAMED("Rigged VBO Rebuild"); + skin = vobj->getSkinInfo(); + // FIXME ugly const cast + LLSkinningUtil::scrubInvalidJoints(avatar, const_cast<LLMeshSkinInfo*>(skin)); + + if (!vol_face.mWeightsScrubbed) + { + LLSkinningUtil::scrubSkinWeights(weights, vol_face.mNumVertices, skin); + vol_face.mWeightsScrubbed = TRUE; + } + if (drawable && drawable->isState(LLDrawable::REBUILD_ALL)) { //rebuild EVERY face in the drawable, not just this one, to avoid missing drawable wide rebuild issues @@ -2033,18 +2045,13 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( } } - 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()) + if (sShaderLevel <= 0 && + face->mLastSkinTime < avatar->getLastSkinTime() && + !buffer.isNull() && + buffer->getNumVerts() == vol_face.mNumVertices && + buffer->getNumIndices() == vol_face.mNumIndices) { + LL_PROFILE_ZONE_NAMED("Software Skinning"); //perform software vertex skinning for this face LLStrider<LLVector3> position; LLStrider<LLVector3> normal; @@ -2061,14 +2068,16 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer( LLVector4a* norm = has_normal ? (LLVector4a*) normal.get() : NULL; - //build matrix palette - LLMatrix4a mat[LL_MAX_JOINTS_PER_MESH_OBJECT]; - U32 count = LLSkinningUtil::getMeshJointCount(skin); - LLSkinningUtil::initSkinningMatrixPalette((LLMatrix4*)mat, count, skin, avatar); - LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin); + if (skin == nullptr) + { + skin = vobj->getSkinInfo(); + } - LLMatrix4a bind_shape_matrix; - bind_shape_matrix.loadu(skin->mBindShapeMatrix); + const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, skin); + const LLMatrix4a* mat = &(mpc.mMatrixPalette[0]); + + LLSkinningUtil::checkSkinWeights(weights, buffer->getNumVerts(), skin); + const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix; #if USE_SEPARATE_JOINT_INDICES_AND_WEIGHTS U8* joint_indices_cursor = vol_face.mJointIndices; @@ -2145,15 +2154,18 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) stop_glerror(); + const LLMeshSkinInfo* lastSkin = nullptr; + for (U32 i = 0; i < mRiggedFace[type].size(); ++i) { + LL_PROFILE_ZONE_NAMED("Render Rigged Face"); LLFace* face = mRiggedFace[type][i]; S32 offset = face->getIndicesStart(); U32 count = face->getIndicesCount(); U16 start = face->getGeomStart(); - U16 end = start + face->getGeomCount()-1; + U16 end = start + face->getGeomCount()-1; LLDrawable* drawable = face->getDrawable(); if (!drawable) @@ -2275,52 +2287,32 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow) } 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]; + if (lastSkin != skin) // <== only upload matrix palette to GL if the skininfo changed + { + // upload matrix palette to shader + const MatrixPaletteCache& mpc = updateSkinInfoMatrixPalette(avatar, skin); + U32 count = mpc.mMatrixPalette.size(); - mp[idx+8] = m[8]; - mp[idx+9] = m[9]; - mp[idx+10] = m[10]; - mp[idx+11] = m[14]; - } + stop_glerror(); - LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, - count, - FALSE, - (GLfloat*) mp); + LLDrawPoolAvatar::sVertexProgram->uniformMatrix3x4fv(LLViewerShaderMgr::AVATAR_MATRIX, + count, + FALSE, + (GLfloat*) &(mpc.mGLMp[0])); - stop_glerror(); + stop_glerror(); + } } else { data_mask &= ~LLVertexBuffer::MAP_WEIGHT4; } + lastSkin = skin; + /*if (glow) { gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow()); @@ -2484,20 +2476,78 @@ void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar) continue; } - const LLMeshSkinInfo* skin = vobj->getSkinInfo(); - if (!skin) - { - continue; - } - stop_glerror(); LLVolumeFace& vol_face = volume->getVolumeFace(te); - updateRiggedFaceVertexBuffer(avatar, face, skin, volume, vol_face); + updateRiggedFaceVertexBuffer(avatar, face, vobj, volume, vol_face); } } } +void LLDrawPoolAvatar::updateSkinInfoMatrixPalettes(LLVOAvatar* avatarp) +{ + LL_PROFILE_ZONE_SCOPED; + //evict matrix palettes from the cache that haven't been updated in 10 frames + for (matrix_palette_cache_t::iterator iter = mMatrixPaletteCache.begin(); iter != mMatrixPaletteCache.end(); ) + { + if (gFrameCount - iter->second.mFrame > 10) + { + iter = mMatrixPaletteCache.erase(iter); + } + else + { + ++iter; + } + } +} + +const LLDrawPoolAvatar::MatrixPaletteCache& LLDrawPoolAvatar::updateSkinInfoMatrixPalette(LLVOAvatar * avatarp, const LLMeshSkinInfo* skin) +{ + MatrixPaletteCache& entry = mMatrixPaletteCache[skin]; + + if (entry.mFrame != gFrameCount) + { + LL_PROFILE_ZONE_SCOPED; + entry.mFrame = gFrameCount; + //build matrix palette + U32 count = LLSkinningUtil::getMeshJointCount(skin); + entry.mMatrixPalette.resize(count); + LLSkinningUtil::initSkinningMatrixPalette(&(entry.mMatrixPalette[0]), count, skin, avatarp); + + const LLMatrix4a* mat = &(entry.mMatrixPalette[0]); + + stop_glerror(); + + 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; +} + void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar) { LL_PROFILE_ZONE_SCOPED diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 92a8538958..0c1ee2cced 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 { @@ -253,11 +257,13 @@ typedef enum 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, + const LLVOVolume* vobj, LLVolume* volume, LLVolumeFace& vol_face); void updateRiggedVertexBuffers(LLVOAvatar* avatar); + void updateSkinInfoMatrixPalettes(LLVOAvatar* avatarp); + void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false); void renderRiggedSimple(LLVOAvatar* avatar); void renderRiggedAlpha(LLVOAvatar* avatar); @@ -277,6 +283,26 @@ typedef enum std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES]; + class MatrixPaletteCache + { + public: + U32 mFrame; + LLMeshSkinInfo::matrix_list_t mMatrixPalette; + + // Float array ready to be sent to GL + std::vector<F32> mGLMp; + + MatrixPaletteCache() : + mFrame(gFrameCount-1) + { + } + }; + + const MatrixPaletteCache& updateSkinInfoMatrixPalette(LLVOAvatar* avatarp, const LLMeshSkinInfo* skin); + + typedef std::unordered_map<const LLMeshSkinInfo*, MatrixPaletteCache> matrix_palette_cache_t; + matrix_palette_cache_t mMatrixPaletteCache; + /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display 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/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index d9edd4dc30..0e54b66ea9 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1357,31 +1357,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; @@ -1390,68 +1390,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); @@ -1459,38 +1459,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() diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp index 9d49c30a49..55a4b5a457 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; if (sDisplayText) { LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); @@ -731,6 +732,7 @@ void LLHUDNameTag::updateSize() void LLHUDNameTag::updateAll() { + LL_PROFILE_ZONE_SCOPED; // 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/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index 2c1c1191da..8ac64dbd15 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -4046,28 +4046,26 @@ 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); + } - 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()); - } - } - + //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()); + } + } return NULL; } diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 81e49cb1d8..c1698194cb 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" @@ -613,7 +614,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 a9e80ab5da..01bddd781d 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -591,7 +591,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)) { @@ -3298,7 +3298,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; @@ -3340,11 +3340,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) { diff --git a/indra/newview/llskinningutil.cpp b/indra/newview/llskinningutil.cpp index e02b21f036..dc12de29fb 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; + 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; 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/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/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index a590237440..33842497d1 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -208,9 +208,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("DS - FPS"); F32 fps = gRecentFrameCount / fps_log_freq; LL_INFOS() << llformat("FPS: %.02f", fps) << LL_ENDL; gRecentFrameCount = 0; @@ -219,6 +221,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("DS - Memory"); gMemoryAllocated = U64Bytes(LLMemory::getCurrentRSS()); U32Megabytes memory = gMemoryAllocated; LL_INFOS() << "MEMORY: " << memory << LL_ENDL; @@ -228,6 +231,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("DS - Asset Storage"); gAssetStorageLogTime.reset(); gAssetStorage->logAssetStorageInfo(); } @@ -630,6 +634,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (!gDisconnected) { + LL_PROFILE_ZONE_NAMED("display - 1"); LLAppViewer::instance()->pingMainloopTimeout("Display:Update"); if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { //don't draw hud objects in this frame @@ -722,6 +727,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLAppViewer::instance()->pingMainloopTimeout("Display:Swap"); { + LL_PROFILE_ZONE_NAMED("display - 2") if (gResizeScreenTexture) { gResizeScreenTexture = FALSE; @@ -777,6 +783,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) //if (!for_snapshot) { + LL_PROFILE_ZONE_NAMED("display - 3") LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery"); gPipeline.generateWaterReflection(*LLViewerCamera::getInstance()); gPipeline.generateHighlight(*LLViewerCamera::getInstance()); @@ -825,7 +832,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLImageGL::deleteDeadTextures(); stop_glerror(); }*/ - } + } LLGLState::checkStates(); LLGLState::checkClientArrays(); @@ -840,6 +847,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort"); { + LL_PROFILE_ZONE_NAMED("display - 3") LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; gPipeline.stateSort(*LLViewerCamera::getInstance(), result); stop_glerror(); @@ -948,6 +956,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) && !gRestoreGL) { + LL_PROFILE_ZONE_NAMED("display - 4") LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD; if (gSavedSettings.getBOOL("RenderDepthPrePass") && LLGLSLShader::sNoFixedFunction) 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/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ca01bb46aa..af55f68cd2 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -208,6 +208,7 @@ void LLViewerTextureManager::findTextures(const LLUUID& id, std::vector<LLViewe LLViewerFetchedTexture* LLViewerTextureManager::findFetchedTexture(const LLUUID& id, S32 tex_type) { + LL_PROFILE_ZONE_SCOPED; return gTextureList.findImage(id, (ETexListType)tex_type); } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 561319ca5d..12495078e9 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -620,6 +620,7 @@ void LLViewerTextureList::findTexturesByID(const LLUUID &image_id, std::vector<L LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLTextureKey &search_key) { + LL_PROFILE_ZONE_SCOPED; uuid_map_t::iterator iter = mUUIDMap.find(search_key); if (iter == mUUIDMap.end()) return NULL; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 1d13a306ef..2157585364 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -5280,6 +5280,7 @@ void LLViewerWindow::setup3DRender() void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset) { + LL_PROFILE_ZONE_SCOPED gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset; gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset; gGLViewport[2] = mWorldViewRectRaw.getWidth(); 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 e085a945a8..a588d05ff7 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -3136,6 +3136,8 @@ void LLVOAvatar::idleUpdateWindEffect() void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) { + LL_PROFILE_ZONE_SCOPED; + // update chat bubble //-------------------------------------------------------------------- // draw text label over character's head @@ -4884,6 +4886,8 @@ bool LLVOAvatar::shouldAlphaMask() //----------------------------------------------------------------------------- U32 LLVOAvatar::renderSkinned() { + LL_PROFILE_ZONE_SCOPED; + U32 num_indices = 0; if (!mIsBuilt) @@ -6158,27 +6162,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; } @@ -6513,7 +6519,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; @@ -7117,6 +7123,7 @@ void LLVOAvatar::updateGL() { if (mMeshTexturesDirty) { + LL_PROFILE_ZONE_SCOPED updateMeshTextures(); mMeshTexturesDirty = FALSE; } @@ -7862,6 +7869,8 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color) // Do rigged mesh attachments display with this av? bool LLVOAvatar::shouldRenderRigged() const { + LL_PROFILE_ZONE_SCOPED; + if (getOverallAppearance() == AOA_NORMAL) { return true; @@ -8353,6 +8362,7 @@ void LLVOAvatar::updateMeshVisibility() // virtual void LLVOAvatar::updateMeshTextures() { + LL_PROFILE_ZONE_SCOPED static S32 update_counter = 0; mBakedTextureDebugText.clear(); @@ -10949,6 +10959,7 @@ void LLVOAvatar::updateOverallAppearanceAnimations() // Based on isVisuallyMuted(), but has 3 possible results. LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const { + LL_PROFILE_ZONE_SCOPED; AvatarOverallAppearance result = AOA_NORMAL; // Priority order (highest priority first) diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 74ef589ca4..39adaab8ca 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -209,6 +209,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 addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen = NULL, bool recursive = true); void removeAttachmentOverridesForObject(const LLUUID& mesh_id); void removeAttachmentOverridesForObject(LLViewerObject *vo); diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 897bace4e1..b5560d3d79 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -218,6 +218,7 @@ void LLVOSurfacePatch::updateGL() { if (mPatchp) { + LL_PROFILE_ZONE_SCOPED mPatchp->updateGL(); } } diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index f9b2285989..e5a4b0f374 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -4807,7 +4807,7 @@ 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); S32 rigged_vert_count = 0; S32 rigged_face_count = 0; @@ -4823,8 +4823,7 @@ 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); + const LLMatrix4a& bind_shape_matrix = skin->mBindShapeMatrix; LLVector4a* pos = dst_face.mPositions; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index a1a1db35d6..c7b0a2bfb4 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1284,6 +1284,7 @@ void send_agent_pause() void send_agent_resume() { + LL_PROFILE_ZONE_SCOPED // 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/pipeline.cpp b/indra/newview/pipeline.cpp index 4e28c8c493..d7acf2ec0e 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1897,6 +1897,7 @@ void LLPipeline::createObject(LLViewerObject* vobj) void LLPipeline::resetFrameStats() { + LL_PROFILE_ZONE_SCOPED assertInitialized(); sCompiles = 0; @@ -2125,6 +2126,7 @@ void LLPipeline::grabReferences(LLCullResult& result) void LLPipeline::clearReferences() { + LL_PROFILE_ZONE_SCOPED sCull = NULL; mGroupSaveQ1.clear(); } 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; } |