diff --git a/doc/responders.txt b/doc/responders.txt new file mode 100644 index 000000000..b1bf31f50 --- /dev/null +++ b/doc/responders.txt @@ -0,0 +1,82 @@ +All Responders are derived from ResponderBase, however you normally do never derived from that directly yourself. +Instead, Responder classes are derived from one of: + +1. Responder base classes + + ResponderHeadersOnly -- Derived classes are used with HTTPClient::head or HTTPClient::getHeaderOnly. + ResponderWithCompleted -- Derived classes implement completed(U32, std::string const&, LLSD const&), + or completedRaw(U32, std::string const&, LLChannelDescriptors const&, buffer_ptr_t const&) + if the response is not (always) LLSD. + ResponderWithResult -- Derived classes implement result(LLSD const&) and optionally + errorWithContent(U32, std::string const&, LLSD const&) OR error(U32, std::string const&). + +2. Special base classes + + ResponderIgnoreBody -- Same as ResponderWithResult but already implements result() that ignored the body. + LLAssetUploadResponder -- Derived from ResponderWithResult. Base class for responders that upload assets via capabilities. + LegacyPolledResponder -- Used for old code that needs polling (do not use). + + +There is one non-base class Responder with a more general purpose: + +3. Special purpose responders: + + ResponderIgnore -- Derived from ResponderIgnoreBody. Used for "fire and forget" requests as it ignores any response. + + +4. Signatures. + +Every final (derived) responder class must implement 'getName(void) const' and 'getHTTPTimeoutPolicy(void)', +except the base classes (this is to alert the developer they have to implement getName as it is pure virtual). + +For example: + + extern AIHTTPTimeoutPolicy myResponder_timeout; // Add 'P(myResponder)' to indra/llmessage/aihttptimeoutpolicy.cpp. + + class MyResponder : public LLHTTPClient::SomeResponderBaseClass { + ... + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return myResponder_timeout; } + /*virtual*/ char const* getName(void) const { return "MyResponder"; } + }; + +Note the convention that the name of a AIHTTPTimeoutPolicy (what goes between the brackets of P()) is +the class name minus any 'AI' or 'LL' prefix and starting with a lowercase character. + +Then, depending on the three main base classes that was derived from, the signatures should be: + + class MyResponder1 : public LLHTTPClient::ResponderHeadersOnly { + /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers); + // See for example PostImageResponder + ... + }; + + class MyResponder2 : public LLHTTPClient::ResponderWithCompleted { + /*virtual*/ void completedRaw(U32 status, std::string const& reason, LLChannelDescriptors const& channels, buffer_ptr_t const& buffer); + // See for example PostImageRedirectResponder + >>>OR<<< + + /*virtual*/ void completed(U32 status, const std::string& reason, const LLSD& content); // See for example LLImportPostResponder + + }; + + class MyResponder3 : public LLHTTPClient::ResponderWithResult { + /*virtual*/ void result(const LLSD& content); // See for example LLInventoryModelFetchItemResponder + /*virtual*/ void error(U32 status, const std::string& reason); + >>>OR instead error()<<< + /*virtual*/ void errorWithContent(U32 status, const std::string& reason, const LLSD& content); + // See for example LLSDMessage::EventResponder + }; + +Finally, if a responder derived from ResponderWithCompleted or ResponderWithResult needs to process +individual headers, you need to override 'needsHeaders': + + /*virtual*/ bool needsHeaders(void) const { return true; } // See for example LLWebProfileResponders::PostImageResponder + // which will cause this to be called: + /*virtual*/ void completedHeaders(U32 status, std::string const& reason, AIHTTPReceivedHeaders const& headers); + +And if it needs redirection to work (you'll get an assert if you forget this and it is being redirected): + + /*virtual*/ bool followRedir(void) const { return true; } // See for example LLWebProfileResponders::ConfigResponder + +This is not necessary for ResponderHeadersOnly because that already defines both. + diff --git a/indra/cwdebug/debug.cc b/indra/cwdebug/debug.cc index 17d86d77f..4a5de2da8 100644 --- a/indra/cwdebug/debug.cc +++ b/indra/cwdebug/debug.cc @@ -562,8 +562,10 @@ namespace dc fake_channel const warning(1, "WARNING "); fake_channel const curl(1, "CURL "); fake_channel const curlio(1, "CURLIO "); +fake_channel const curltr(1, "CURLTR "); fake_channel const statemachine(1, "STATEMACHINE"); fake_channel const notice(1, "NOTICE "); +fake_channel const snapshot(0, "SNAPSHOT "); } // namespace dc } // namespace debug diff --git a/indra/cwdebug/debug.h b/indra/cwdebug/debug.h index 329f0448e..e14fb18b9 100644 --- a/indra/cwdebug/debug.h +++ b/indra/cwdebug/debug.h @@ -82,8 +82,10 @@ struct fake_channel { extern LL_COMMON_API fake_channel const warning; extern LL_COMMON_API fake_channel const curl; extern LL_COMMON_API fake_channel const curlio; +extern LL_COMMON_API fake_channel const curltr; extern LL_COMMON_API fake_channel const statemachine; extern LL_COMMON_API fake_channel const notice; +extern LL_COMMON_API fake_channel const snapshot; } // namespace dc } // namespace debug @@ -173,8 +175,8 @@ extern LL_COMMON_API fake_channel const notice; #include #if CWDEBUG_LOCATION #include // Needed for 'backtrace'. -#include "llpreprocessor.h" #endif +#include "llpreprocessor.h" // LL_COMMON_API #include #define CWD_API __attribute__ ((visibility("default"))) @@ -387,21 +389,21 @@ void InstanceTracker::dump(void) // Print "Entering " << \a data to channel \a cntrl and increment // debugging output indentation until the end of the current scope. #define DoutEntering(cntrl, data) \ - int __slviewer_debug_indentation = 2; \ + int __slviewer_debug_indentation = 2; \ { \ LIBCWD_TSD_DECLARATION; \ if (LIBCWD_DO_TSD_MEMBER_OFF(::libcwd::libcw_do) < 0) \ { \ ::libcwd::channel_set_bootstrap_st __libcwd_channel_set(LIBCWD_DO_TSD(::libcwd::libcw_do) LIBCWD_COMMA_TSD); \ - bool on; \ + bool __slviewer_debug_on; \ { \ using namespace LIBCWD_DEBUGCHANNELS; \ - on = (__libcwd_channel_set|cntrl).on; \ + __slviewer_debug_on = (__libcwd_channel_set|cntrl).on; \ } \ - if (on) \ + if (__slviewer_debug_on) \ Dout(cntrl, "Entering " << data); \ else \ - __slviewer_debug_indentation = 0; \ + __slviewer_debug_indentation = 0; \ } \ } \ debug::Indent __slviewer_debug_indent(__slviewer_debug_indentation); diff --git a/indra/llappearance/lldriverparam.h b/indra/llappearance/lldriverparam.h index 1a24cefa1..65dd3cdde 100644 --- a/indra/llappearance/lldriverparam.h +++ b/indra/llappearance/lldriverparam.h @@ -76,6 +76,7 @@ protected: //----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) class LLDriverParam : public LLViewerVisualParam { friend class LLPhysicsMotion; @@ -133,13 +134,13 @@ protected: void setDrivenWeight(LLDrivenEntry *driven, F32 driven_weight, bool upload_bake); - LLVector4a mDefaultVec; // temp holder + LL_ALIGN_16(LLVector4a mDefaultVec); // temp holder typedef std::vector entry_list_t; entry_list_t mDriven; LLViewerVisualParam* mCurrentDistortionParam; // Backlink only; don't make this an LLPointer. LLAvatarAppearance* mAvatarAppearance; LLWearable* mWearablep; -}; +} LL_ALIGN_POSTFIX(16); #endif // LL_LLDRIVERPARAM_H diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h index f7782ffb3..03915d3da 100644 --- a/indra/llappearance/llpolymorph.h +++ b/indra/llappearance/llpolymorph.h @@ -41,6 +41,7 @@ class LLWearable; //----------------------------------------------------------------------------- // LLPolyMorphData() //----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) class LLPolyMorphData { public: @@ -79,12 +80,13 @@ public: F32 mTotalDistortion; // vertex distortion summed over entire morph F32 mMaxDistortion; // maximum single vertex distortion in a given morph - LLVector4a mAvgDistortion; // average vertex distortion, to infer directionality of the morph + LL_ALIGN_16(LLVector4a mAvgDistortion); // average vertex distortion, to infer directionality of the morph LLPolyMeshSharedData* mMesh; private: void freeData(); -}; +} LL_ALIGN_POSTFIX(16); + //----------------------------------------------------------------------------- // LLPolyVertexMask() diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h index b9c3c3628..774bc7dfa 100644 --- a/indra/llappearance/llpolyskeletaldistortion.h +++ b/indra/llappearance/llpolyskeletaldistortion.h @@ -63,6 +63,7 @@ struct LLPolySkeletalBoneInfo BOOL mHasPositionDeformation; }; +LL_ALIGN_PREFIX(16) class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo { friend class LLPolySkeletalDistortion; @@ -118,13 +119,13 @@ public: /*virtual*/ const LLVector4a* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;}; protected: + LL_ALIGN_16(LLVector4a mDefaultVec); typedef std::map joint_vec_map_t; joint_vec_map_t mJointScales; joint_vec_map_t mJointOffsets; - LLVector4a mDefaultVec; // Backlink only; don't make this an LLPointer. LLAvatarAppearance *mAvatar; -}; +} LL_ALIGN_POSTFIX(16); #endif // LL_LLPOLYSKELETALDISTORTION_H diff --git a/indra/llappearance/lltexlayerparams.h b/indra/llappearance/lltexlayerparams.h index ca1497ebf..b38d28d3e 100644 --- a/indra/llappearance/lltexlayerparams.h +++ b/indra/llappearance/lltexlayerparams.h @@ -60,6 +60,7 @@ protected: // LLTexLayerParamAlpha // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL_ALIGN_PREFIX(16) class LLTexLayerParamAlpha : public LLTexLayerParam { public: @@ -67,8 +68,6 @@ public: LLTexLayerParamAlpha( LLAvatarAppearance* appearance ); /*virtual*/ ~LLTexLayerParamAlpha(); - /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; - void* operator new(size_t size) { return ll_aligned_malloc_16(size); @@ -79,6 +78,8 @@ public: ll_aligned_free_16(ptr); } + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; + // LLVisualParam Virtual functions ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); /*virtual*/ void apply( ESex avatar_sex ) {} @@ -106,7 +107,7 @@ private: LLPointer mStaticImageRaw; BOOL mNeedsCreateTexture; BOOL mStaticImageInvalid; - LLVector4a mAvgDistortionVec; + LL_ALIGN_16(LLVector4a mAvgDistortionVec); F32 mCachedEffectiveWeight; public: @@ -116,7 +117,7 @@ public: typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t; static param_alpha_ptr_list_t sInstances; -}; +} LL_ALIGN_POSTFIX(16); class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo { friend class LLTexLayerParamAlpha; @@ -140,6 +141,8 @@ private: // LLTexLayerParamColor // //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LL_ALIGN_PREFIX(16) class LLTexLayerParamColor : public LLTexLayerParam { public: @@ -153,7 +156,6 @@ public: LLTexLayerParamColor( LLTexLayerInterface* layer ); LLTexLayerParamColor( LLAvatarAppearance* appearance ); - /* virtual */ ~LLTexLayerParamColor(); void* operator new(size_t size) { @@ -165,6 +167,8 @@ public: ll_aligned_free_16(ptr); } + /* virtual */ ~LLTexLayerParamColor(); + /*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable = NULL) const; // LLVisualParam Virtual functions @@ -188,8 +192,8 @@ public: protected: virtual void onGlobalColorChanged(bool upload_bake) {} private: - LLVector4a mAvgDistortionVec; -}; + LL_ALIGN_16(LLVector4a mAvgDistortionVec); +} LL_ALIGN_POSTFIX(16); class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo { diff --git a/indra/llappearance/llviewervisualparam.h b/indra/llappearance/llviewervisualparam.h index 259c0d6ee..64364c881 100644 --- a/indra/llappearance/llviewervisualparam.h +++ b/indra/llappearance/llviewervisualparam.h @@ -66,6 +66,7 @@ protected: // VIRTUAL CLASS // a viewer side interface class for a generalized parametric modification of the avatar mesh //----------------------------------------------------------------------------- +LL_ALIGN_PREFIX(16) class LLViewerVisualParam : public LLVisualParam { public: @@ -106,6 +107,6 @@ public: BOOL getCrossWearable() const { return getInfo()->mCrossWearable; } -}; +} LL_ALIGN_POSTFIX(16); #endif // LL_LLViewerVisualParam_H diff --git a/indra/llcommon/aithreadsafe.h b/indra/llcommon/aithreadsafe.h index 425741601..461bb4cc5 100644 --- a/indra/llcommon/aithreadsafe.h +++ b/indra/llcommon/aithreadsafe.h @@ -106,9 +106,9 @@ // on a compiler that doesn't need this hack. #define AI_NEED_ACCESS_CC (defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)) || (__GNUC__ < 4))) -template struct AIReadAccessConst; -template struct AIReadAccess; -template struct AIWriteAccess; +template struct AIReadAccessConst; +template struct AIReadAccess; +template struct AIWriteAccess; template struct AIAccessConst; template struct AIAccess; template struct AISTAccessConst; @@ -225,17 +225,17 @@ protected: * * */ -template +template class AIThreadSafe : public AIThreadSafeBits { protected: // Only these may access the object (through ptr()). - friend struct AIReadAccessConst; - friend struct AIReadAccess; - friend struct AIWriteAccess; + friend struct AIReadAccessConst; + friend struct AIReadAccess; + friend struct AIWriteAccess; // Locking control. - AIRWLock mRWLock; + RWLOCK mRWLock; // For use by AIThreadSafeDC AIThreadSafe(void) { } @@ -310,20 +310,20 @@ public: * * which is not possible with AITHREADSAFE. */ -template -class AIThreadSafeDC : public AIThreadSafe +template +class AIThreadSafeDC : public AIThreadSafe { public: // Construct a wrapper around a default constructed object. - AIThreadSafeDC(void) { new (AIThreadSafe::ptr()) T; } + AIThreadSafeDC(void) { new (AIThreadSafe::ptr()) T; } // Allow an arbitrary parameter to be passed for construction. - template AIThreadSafeDC(T2 const& val) { new (AIThreadSafe::ptr()) T(val); } + template AIThreadSafeDC(T2 const& val) { new (AIThreadSafe::ptr()) T(val); } }; /** * @brief Read lock object and provide read access. */ -template +template struct AIReadAccessConst { //! Internal enum for the lock-type of the AI*Access object. @@ -336,8 +336,8 @@ struct AIReadAccessConst }; //! Construct a AIReadAccessConst from a constant AIThreadSafe. - AIReadAccessConst(AIThreadSafe const& wrapper, bool high_priority = false) - : mWrapper(const_cast&>(wrapper)), + AIReadAccessConst(AIThreadSafe const& wrapper, bool high_priority = false) + : mWrapper(const_cast&>(wrapper)), mState(readlocked) #if AI_NEED_ACCESS_CC , mIsCopyConstructed(false) @@ -369,14 +369,14 @@ struct AIReadAccessConst protected: //! Constructor used by AIReadAccess. - AIReadAccessConst(AIThreadSafe& wrapper, state_type state) + AIReadAccessConst(AIThreadSafe& wrapper, state_type state) : mWrapper(wrapper), mState(state) #if AI_NEED_ACCESS_CC , mIsCopyConstructed(false) #endif { } - AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to. + AIThreadSafe& mWrapper; //!< Reference to the object that we provide access to. state_type const mState; //!< The lock state that mWrapper is in. #if AI_NEED_ACCESS_CC @@ -393,39 +393,39 @@ private: /** * @brief Read lock object and provide read access, with possible promotion to write access. */ -template -struct AIReadAccess : public AIReadAccessConst +template +struct AIReadAccess : public AIReadAccessConst { - typedef typename AIReadAccessConst::state_type state_type; - using AIReadAccessConst::readlocked; + typedef typename AIReadAccessConst::state_type state_type; + using AIReadAccessConst::readlocked; //! Construct a AIReadAccess from a non-constant AIThreadSafe. - AIReadAccess(AIThreadSafe& wrapper, bool high_priority = false) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); } + AIReadAccess(AIThreadSafe& wrapper, bool high_priority = false) : AIReadAccessConst(wrapper, readlocked) { this->mWrapper.mRWLock.rdlock(high_priority); } protected: //! Constructor used by AIWriteAccess. - AIReadAccess(AIThreadSafe& wrapper, state_type state) : AIReadAccessConst(wrapper, state) { } + AIReadAccess(AIThreadSafe& wrapper, state_type state) : AIReadAccessConst(wrapper, state) { } - friend struct AIWriteAccess; + friend struct AIWriteAccess; }; /** * @brief Write lock object and provide read/write access. */ -template -struct AIWriteAccess : public AIReadAccess +template +struct AIWriteAccess : public AIReadAccess { - using AIReadAccessConst::readlocked; - using AIReadAccessConst::read2writelocked; - using AIReadAccessConst::writelocked; - using AIReadAccessConst::write2writelocked; + using AIReadAccessConst::readlocked; + using AIReadAccessConst::read2writelocked; + using AIReadAccessConst::writelocked; + using AIReadAccessConst::write2writelocked; //! Construct a AIWriteAccess from a non-constant AIThreadSafe. - AIWriteAccess(AIThreadSafe& wrapper) : AIReadAccess(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();} + AIWriteAccess(AIThreadSafe& wrapper) : AIReadAccess(wrapper, writelocked) { this->mWrapper.mRWLock.wrlock();} //! Promote read access to write access. - explicit AIWriteAccess(AIReadAccess& access) - : AIReadAccess(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked) + explicit AIWriteAccess(AIReadAccess& access) + : AIReadAccess(access.mWrapper, (access.mState == readlocked) ? read2writelocked : write2writelocked) { if (this->mState == read2writelocked) { diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp index 87654b5b9..34fc28d8c 100644 --- a/indra/llcommon/llallocator.cpp +++ b/indra/llcommon/llallocator.cpp @@ -35,28 +35,6 @@ DECLARE_bool(heap_profile_use_stack_trace); //DECLARE_double(tcmalloc_release_rate); -// static -void LLAllocator::pushMemType(S32 type) -{ - if(isProfiling()) - { - PushMemType(type); - } -} - -// static -S32 LLAllocator::popMemType() -{ - if (isProfiling()) - { - return PopMemType(); - } - else - { - return -1; - } -} - void LLAllocator::setProfilingEnabled(bool should_enable) { // NULL disables dumping to disk @@ -94,17 +72,6 @@ std::string LLAllocator::getRawProfile() // stub implementations for when tcmalloc is disabled // -// static -void LLAllocator::pushMemType(S32 type) -{ -} - -// static -S32 LLAllocator::popMemType() -{ - return -1; -} - void LLAllocator::setProfilingEnabled(bool should_enable) { } diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h index a91dd57d1..d26ad73c5 100644 --- a/indra/llcommon/llallocator.h +++ b/indra/llcommon/llallocator.h @@ -29,16 +29,10 @@ #include -#include "llmemtype.h" #include "llallocator_heap_profile.h" class LL_COMMON_API LLAllocator { friend class LLMemoryView; - friend class LLMemType; - -private: - static void pushMemType(S32 type); - static S32 popMemType(); public: void setProfilingEnabled(bool should_enable); diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 993f16d04..b79417f96 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -224,32 +225,81 @@ namespace LLInitParam typedef std::map parser_write_func_map_t; typedef std::map parser_inspect_func_map_t; + private: + template::value> + struct ReaderWriter + { + static bool read(T& param, Parser* parser) + { + parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(T)); + if (found_it != parser->mParserReadFuncs->end()) + { + return found_it->second(*parser, (void*)¶m); + } + return false; + } + + static bool write(const T& param, Parser* parser, name_stack_t& name_stack) + { + parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(T)); + if (found_it != parser->mParserWriteFuncs->end()) + { + return found_it->second(*parser, (const void*)¶m, name_stack); + } + return false; + } + }; + + // read enums as ints + template + struct ReaderWriter + { + static bool read(T& param, Parser* parser) + { + // read all enums as ints + parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(S32)); + if (found_it != parser->mParserReadFuncs->end()) + { + S32 value; + if (found_it->second(*parser, (void*)&value)) + { + param = (T)value; + return true; + } + } + return false; + } + + static bool write(const T& param, Parser* parser, name_stack_t& name_stack) + { + parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(S32)); + if (found_it != parser->mParserWriteFuncs->end()) + { + return found_it->second(*parser, (const void*)¶m, name_stack); + } + return false; + } + }; + + public: + Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) : mParseSilently(false), mParserReadFuncs(&read_map), mParserWriteFuncs(&write_map), mParserInspectFuncs(&inspect_map) {} + virtual ~Parser(); template bool readValue(T& param) { - parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); - if (found_it != mParserReadFuncs->end()) - { - return found_it->second(*this, (void*)¶m); - } - return false; + return ReaderWriter::read(param, this); } template bool writeValue(const T& param, name_stack_t& name_stack) { - parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); - if (found_it != mParserWriteFuncs->end()) - { - return found_it->second(*this, (const void*)¶m, name_stack); - } - return false; + return ReaderWriter::write(param, this, name_stack); } // dispatch inspection to registered inspection functions, for each parameter in a param block @@ -841,31 +891,25 @@ namespace LLInitParam self_t& typed_param = static_cast(param); // no further names in stack, attempt to parse value now if (name_stack_range.first == name_stack_range.second) - { - if (parser.readValue(typed_param.getValue())) + { + std::string name; + + // try to parse a known named value + if(name_value_lookup_t::valueNamesExist() + && parser.readValue(name) + && name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } + // try to read value directly + else if (parser.readValue(typed_param.getValue())) { typed_param.clearValueName(); typed_param.setProvided(); return true; } - - // try to parse a known named value - if(name_value_lookup_t::valueNamesExist()) - { - // try to parse a known named value - std::string name; - if (parser.readValue(name)) - { - // try to parse a per type named value - if (name_value_lookup_t::getValueFromName(name, typed_param.getValue())) - { - typed_param.setValueName(name); - typed_param.setProvided(); - return true; - } - - } - } } return false; } @@ -987,30 +1031,29 @@ namespace LLInitParam static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) { self_t& typed_param = static_cast(param); - // attempt to parse block... + + if (name_stack_range.first == name_stack_range.second) + { // try to parse a known named value + std::string name; + + if(name_value_lookup_t::valueNamesExist() + && parser.readValue(name) + && name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } + } + if(typed_param.deserializeBlock(parser, name_stack_range, new_name)) - { + { // attempt to parse block... typed_param.clearValueName(); typed_param.setProvided(); return true; } - if(name_value_lookup_t::valueNamesExist()) - { - // try to parse a known named value - std::string name; - if (parser.readValue(name)) - { - // try to parse a per type named value - if (name_value_lookup_t::getValueFromName(name, typed_param.getValue())) - { - typed_param.setValueName(name); - typed_param.setProvided(); - return true; - } - } - } return false; } @@ -1160,31 +1203,23 @@ namespace LLInitParam value_t value; // no further names in stack, attempt to parse value now if (name_stack_range.first == name_stack_range.second) - { - // attempt to read value directly - if (parser.readValue(value)) + { + std::string name; + + // try to parse a known named value + if(name_value_lookup_t::valueNamesExist() + && parser.readValue(name) + && name_value_lookup_t::getValueFromName(name, value)) + { + typed_param.add(value); + typed_param.mValues.back().setValueName(name); + return true; + } + else if (parser.readValue(value)) // attempt to read value directly { typed_param.add(value); return true; } - - // try to parse a known named value - if(name_value_lookup_t::valueNamesExist()) - { - // try to parse a known named value - std::string name; - if (parser.readValue(name)) - { - // try to parse a per type named value - if (name_value_lookup_t::getValueFromName(name, value)) - { - typed_param.add(value); - typed_param.mValues.back().setValueName(name); - return true; - } - - } - } } return false; } @@ -1362,28 +1397,27 @@ namespace LLInitParam param_value_t& value = typed_param.mValues.back(); + if (name_stack_range.first == name_stack_range.second) + { // try to parse a known named value + std::string name; + + if(name_value_lookup_t::valueNamesExist() + && parser.readValue(name) + && name_value_lookup_t::getValueFromName(name, value.getValue())) + { + typed_param.mValues.back().setValueName(name); + typed_param.setProvided(); + return true; + } + } + // attempt to parse block... if(value.deserializeBlock(parser, name_stack_range, new_name)) { typed_param.setProvided(); return true; } - else if(name_value_lookup_t::valueNamesExist()) - { - // try to parse a known named value - std::string name; - if (parser.readValue(name)) - { - // try to parse a per type named value - if (name_value_lookup_t::getValueFromName(name, value.getValue())) - { - typed_param.mValues.back().setValueName(name); - typed_param.setProvided(); - return true; - } - } - } if (new_value) { // failed to parse new value, pop it off diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp index 9dcdaeff1..614dee323 100644 --- a/indra/llcommon/llmemtype.cpp +++ b/indra/llcommon/llmemtype.cpp @@ -27,7 +27,9 @@ #include "llmemtype.h" #include "llallocator.h" +#if MEM_TRACK_TYPE std::vector LLMemType::DeclareMemType::mNameList; +#endif LLMemType::DeclareMemType LLMemType::MTYPE_INIT("Init"); LLMemType::DeclareMemType LLMemType::MTYPE_STARTUP("Startup"); @@ -194,7 +196,7 @@ LLMemType::DeclareMemType LLMemType::MTYPE_TEMP9("Temp9"); LLMemType::DeclareMemType LLMemType::MTYPE_OTHER("Other"); - +#if MEM_TRACK_TYPE LLMemType::DeclareMemType::DeclareMemType(char const * st) { mID = (S32)mNameList.size(); @@ -229,3 +231,4 @@ char const * LLMemType::getNameFromID(S32 id) } //-------------------------------------------------------------------------------------------------- +#endif //MEM_TRACK_TYPE \ No newline at end of file diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h index b51d7e0f6..2a411eb90 100644 --- a/indra/llcommon/llmemtype.h +++ b/indra/llcommon/llmemtype.h @@ -52,6 +52,10 @@ public: class LL_COMMON_API DeclareMemType { public: + +#if !MEM_TRACK_TYPE + DeclareMemType(char const * st) {}; //Do nothing +#else DeclareMemType(char const * st); ~DeclareMemType(); @@ -60,12 +64,17 @@ public: // array so we can map an index ID to Name static std::vector mNameList; +#endif }; +#if !MEM_TRACK_TYPE + LLMemType(DeclareMemType& dt){} //Do nothing +#else LLMemType(DeclareMemType& dt); ~LLMemType(); static char const * getNameFromID(S32 id); +#endif static DeclareMemType MTYPE_INIT; static DeclareMemType MTYPE_STARTUP; @@ -232,7 +241,9 @@ public: static DeclareMemType MTYPE_OTHER; // Special; used by display code +#if MEM_TRACK_TYPE S32 mTypeIndex; +#endif }; //---------------------------------------------------------------------------- diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 2c91b68ef..120bfa2c9 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -598,7 +598,7 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits) case LLSD::TypeReal: // This is where the 'bits' argument comes in handy. If passed // explicitly, it means to use is_approx_equal_fraction() to compare. - if (bits >= 0) + if (bits != -1) { return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits); } diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 6fac2c8a9..45aae60e8 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -226,7 +226,7 @@ void LLSingleton::createInstance(SingletonInstanceData& data) if (data.mInitState == INITIALIZING) { - llwarns << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from initSingleton(), using half-initialized object" << llendl; + lldebugs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from initSingleton(), using half-initialized object" << llendl; return; } diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index ac5bdcffb..6cc2246e2 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -37,736 +37,30 @@ // statics -S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded -LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects -std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step" - //------------------------------------------------------------------------ -// Live config file to trigger stats logging -static const char STATS_CONFIG_FILE_NAME[] = "/dev/shm/simperf/simperf_proc_config.llsd"; -static const F32 STATS_CONFIG_REFRESH_RATE = 5.0; // seconds - -class LLStatsConfigFile : public LLLiveFile -{ -public: - LLStatsConfigFile() - : LLLiveFile(filename(), STATS_CONFIG_REFRESH_RATE), - mChanged(false), mStatsp(NULL) { } - - static std::string filename(); - -protected: - /* virtual */ bool loadFile(); - -public: - void init(LLPerfStats* statsp); - static LLStatsConfigFile& instance(); - // return the singleton stats config file - - bool mChanged; - -protected: - LLPerfStats* mStatsp; -}; - -std::string LLStatsConfigFile::filename() -{ - return STATS_CONFIG_FILE_NAME; -} - -void LLStatsConfigFile::init(LLPerfStats* statsp) -{ - mStatsp = statsp; -} - -LLStatsConfigFile& LLStatsConfigFile::instance() -{ - static LLStatsConfigFile the_file; - return the_file; -} - - -/* virtual */ -// Load and parse the stats configuration file -bool LLStatsConfigFile::loadFile() -{ - if (!mStatsp) - { - llwarns << "Tries to load performance configure file without initializing LPerfStats" << llendl; - return false; - } - mChanged = true; - - LLSD stats_config; - { - llifstream file(filename().c_str()); - if (file.is_open()) - { - LLSDSerialize::fromXML(stats_config, file); - if (stats_config.isUndefined()) - { - llinfos << "Performance statistics configuration file ill-formed, not recording statistics" << llendl; - mStatsp->setReportPerformanceDuration( 0.f ); - return false; - } - } - else - { // File went away, turn off stats if it was on - if ( mStatsp->frameStatsIsRunning() ) - { - llinfos << "Performance statistics configuration file deleted, not recording statistics" << llendl; - mStatsp->setReportPerformanceDuration( 0.f ); - } - return true; - } - } - - F32 duration = 0.f; - F32 interval = 0.f; - S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS; - - const char * w = "duration"; - if (stats_config.has(w)) - { - duration = (F32)stats_config[w].asReal(); - } - w = "interval"; - if (stats_config.has(w)) - { - interval = (F32)stats_config[w].asReal(); - } - w = "flags"; - if (stats_config.has(w)) - { - flags = (S32)stats_config[w].asInteger(); - if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS && - duration > 0) - { // No flags passed in, but have a duration, so reset to basic stats - flags = LLPerfBlock::LLSTATS_BASIC_STATS; - } - } - - mStatsp->setReportPerformanceDuration( duration, flags ); - mStatsp->setReportPerformanceInterval( interval ); - - if ( duration > 0 ) - { - if ( interval == 0.f ) - { - llinfos << "Recording performance stats every frame for " << duration << " sec" << llendl; - } - else - { - llinfos << "Recording performance stats every " << interval << " seconds for " << duration << " seconds" << llendl; - } - } - else - { - llinfos << "Performance stats recording turned off" << llendl; - } - return true; -} - - -//------------------------------------------------------------------------ - -LLPerfStats::LLPerfStats(const std::string& process_name, S32 process_pid) : - mFrameStatsFileFailure(FALSE), - mSkipFirstFrameStats(FALSE), - mProcessName(process_name), - mProcessPID(process_pid), - mReportPerformanceStatInterval(1.f), - mReportPerformanceStatEnd(0.0) -{ } - -LLPerfStats::~LLPerfStats() -{ - LLPerfBlock::clearDynamicStats(); - mFrameStatsFile.close(); -} - -void LLPerfStats::init() -{ - // Initialize the stats config file instance. - (void) LLStatsConfigFile::instance().init(this); - (void) LLStatsConfigFile::instance().checkAndReload(); -} - -// Open file for statistics -void LLPerfStats::openPerfStatsFile() -{ - if ( !mFrameStatsFile - && !mFrameStatsFileFailure ) - { - std::string stats_file = llformat("/dev/shm/simperf/%s_proc.%d.llsd", mProcessName.c_str(), mProcessPID); - mFrameStatsFile.close(); - mFrameStatsFile.clear(); - mFrameStatsFile.open(stats_file, llofstream::out); - if ( mFrameStatsFile.fail() ) - { - llinfos << "Error opening statistics log file " << stats_file << llendl; - mFrameStatsFileFailure = TRUE; - } - else - { - LLSD process_info = LLSD::emptyMap(); - process_info["name"] = mProcessName; - process_info["pid"] = (LLSD::Integer) mProcessPID; - process_info["stat_rate"] = (LLSD::Integer) mReportPerformanceStatInterval; - // Add process-specific info. - addProcessHeaderInfo(process_info); - - mFrameStatsFile << LLSDNotationStreamer(process_info) << std::endl; - } - } -} - -// Dump out performance metrics over some time interval -void LLPerfStats::dumpIntervalPerformanceStats() -{ - // Ensure output file is OK - openPerfStatsFile(); - - if ( mFrameStatsFile ) - { - LLSD stats = LLSD::emptyMap(); - - LLStatAccum::TimeScale scale; - if ( getReportPerformanceInterval() == 0.f ) - { - scale = LLStatAccum::SCALE_PER_FRAME; - } - else if ( getReportPerformanceInterval() < 0.5f ) - { - scale = LLStatAccum::SCALE_100MS; - } - else - { - scale = LLStatAccum::SCALE_SECOND; - } - - // Write LLSD into log - stats["utc_time"] = (LLSD::String) LLError::utcTime(); - stats["timestamp"] = U64_to_str((totalTime() / 1000) + (gUTCOffset * 1000)); // milliseconds since epoch - stats["frame_number"] = (LLSD::Integer) LLFrameTimer::getFrameCount(); - - // Add process-specific frame info. - addProcessFrameInfo(stats, scale); - LLPerfBlock::addStatsToLLSDandReset( stats, scale ); - - mFrameStatsFile << LLSDNotationStreamer(stats) << std::endl; - } -} - -// Set length of performance stat recording. -// If turning stats on, caller must provide flags -void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ ) -{ - if ( seconds <= 0.f ) - { - mReportPerformanceStatEnd = 0.0; - LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off - mFrameStatsFile.close(); - LLPerfBlock::clearDynamicStats(); - } - else - { - mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds); - // Clear failure flag to try and create the log file once - mFrameStatsFileFailure = FALSE; - mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame) - LLPerfBlock::setStatsFlags(flags); - } -} - -void LLPerfStats::updatePerFrameStats() -{ - (void) LLStatsConfigFile::instance().checkAndReload(); - static LLFrameTimer performance_stats_timer; - if ( frameStatsIsRunning() ) - { - if ( mReportPerformanceStatInterval == 0 ) - { // Record info every frame - if ( mSkipFirstFrameStats ) - { // Skip the first time - was started this frame - mSkipFirstFrameStats = FALSE; - } - else - { - dumpIntervalPerformanceStats(); - } - } - else - { - performance_stats_timer.setTimerExpirySec( getReportPerformanceInterval() ); - if (performance_stats_timer.checkExpirationAndReset( mReportPerformanceStatInterval )) - { - dumpIntervalPerformanceStats(); - } - } - - if ( LLFrameTimer::getElapsedSeconds() > mReportPerformanceStatEnd ) - { // Reached end of time, clear it to stop reporting - setReportPerformanceDuration(0.f); // Don't set mReportPerformanceStatEnd directly - llinfos << "Recording performance stats completed" << llendl; - } - } -} - - -//------------------------------------------------------------------------ - -U64 LLStatAccum::sScaleTimes[NUM_SCALES] = -{ - USEC_PER_SEC / 10, // 100 millisec - USEC_PER_SEC * 1, // seconds - USEC_PER_SEC * 60, // minutes -#if ENABLE_LONG_TIME_STATS - // enable these when more time scales are desired - USEC_PER_SEC * 60*60, // hours - USEC_PER_SEC * 24*60*60, // days - USEC_PER_SEC * 7*24*60*60, // weeks -#endif -}; - - - -LLStatAccum::LLStatAccum(bool useFrameTimer) - : mUseFrameTimer(useFrameTimer), - mRunning(FALSE), - mLastTime(0), - mLastSampleValue(0.0), - mLastSampleValid(FALSE) -{ -} - -LLStatAccum::~LLStatAccum() -{ -} - - - -void LLStatAccum::reset(U64 when) -{ - mRunning = TRUE; - mLastTime = when; - - for (int i = 0; i < NUM_SCALES; ++i) - { - mBuckets[i].accum = 0.0; - mBuckets[i].endTime = when + sScaleTimes[i]; - mBuckets[i].lastValid = false; - } -} - -void LLStatAccum::sum(F64 value) -{ - sum(value, getCurrentUsecs()); -} - -void LLStatAccum::sum(F64 value, U64 when) -{ - if (!mRunning) - { - reset(when); - return; - } - if (when < mLastTime) - { - // This happens a LOT on some dual core systems. - lldebugs << "LLStatAccum::sum clock has gone backwards from " - << mLastTime << " to " << when << ", resetting" << llendl; - - reset(when); - return; - } - - // how long is this value for - U64 timeSpan = when - mLastTime; - - for (int i = 0; i < NUM_SCALES; ++i) - { - Bucket& bucket = mBuckets[i]; - - if (when < bucket.endTime) - { - bucket.accum += value; - } - else - { - U64 timeScale = sScaleTimes[i]; - - U64 timeLeft = when - bucket.endTime; - // how much time is left after filling this bucket - - if (timeLeft < timeScale) - { - F64 valueLeft = value * timeLeft / timeSpan; - - bucket.lastValid = true; - bucket.lastAccum = bucket.accum + (value - valueLeft); - bucket.accum = valueLeft; - bucket.endTime += timeScale; - } - else - { - U64 timeTail = timeLeft % timeScale; - - bucket.lastValid = true; - bucket.lastAccum = value * timeScale / timeSpan; - bucket.accum = value * timeTail / timeSpan; - bucket.endTime += (timeLeft - timeTail) + timeScale; - } - } - } - - mLastTime = when; -} - - -F32 LLStatAccum::meanValue(TimeScale scale) const -{ - if (!mRunning) - { - return 0.0; - } - if ( scale == SCALE_PER_FRAME ) - { // Per-frame not supported here - scale = SCALE_100MS; - } - - if (scale < 0 || scale >= NUM_SCALES) - { - llwarns << "llStatAccum::meanValue called for unsupported scale: " - << scale << llendl; - return 0.0; - } - - const Bucket& bucket = mBuckets[scale]; - - F64 value = bucket.accum; - U64 timeLeft = bucket.endTime - mLastTime; - U64 scaleTime = sScaleTimes[scale]; - - if (bucket.lastValid) - { - value += bucket.lastAccum * timeLeft / scaleTime; - } - else if (timeLeft < scaleTime) - { - value *= scaleTime / (scaleTime - timeLeft); - } - else - { - value = 0.0; - } - - return (F32)(value / scaleTime); -} - - -U64 LLStatAccum::getCurrentUsecs() const -{ - if (mUseFrameTimer) - { - return LLFrameTimer::getTotalTime(); - } - else - { - return totalTime(); - } -} - - -// ------------------------------------------------------------------------ - -LLStatRate::LLStatRate(bool use_frame_timer) - : LLStatAccum(use_frame_timer) -{ -} - -void LLStatRate::count(U32 value) -{ - sum((F64)value * sScaleTimes[SCALE_SECOND]); -} - - -void LLStatRate::mark() - { - // Effectively the same as count(1), but sets mLastSampleValue - U64 when = getCurrentUsecs(); - - if ( mRunning - && (when > mLastTime) ) - { // Set mLastSampleValue to the time from the last mark() - F64 duration = ((F64)(when - mLastTime)) / sScaleTimes[SCALE_SECOND]; - if ( duration > 0.0 ) - { - mLastSampleValue = 1.0 / duration; - } - else - { - mLastSampleValue = 0.0; - } - } - - sum( (F64) sScaleTimes[SCALE_SECOND], when); - } - - -// ------------------------------------------------------------------------ - - -LLStatMeasure::LLStatMeasure(bool use_frame_timer) - : LLStatAccum(use_frame_timer) -{ -} - -void LLStatMeasure::sample(F64 value) -{ - U64 when = getCurrentUsecs(); - - if (mLastSampleValid) - { - F64 avgValue = (value + mLastSampleValue) / 2.0; - F64 interval = (F64)(when - mLastTime); - - sum(avgValue * interval, when); - } - else - { - reset(when); - } - - mLastSampleValid = TRUE; - mLastSampleValue = value; -} - - -// ------------------------------------------------------------------------ - -LLStatTime::LLStatTime(const std::string & key) - : LLStatAccum(false), - mFrameNumber(LLFrameTimer::getFrameCount()), - mTotalTimeInFrame(0), - mKey(key) -#if LL_DEBUG - , mRunning(FALSE) -#endif -{ -} - -void LLStatTime::start() -{ - // Reset frame accumluation if the frame number has changed - U32 frame_number = LLFrameTimer::getFrameCount(); - if ( frame_number != mFrameNumber ) - { - mFrameNumber = frame_number; - mTotalTimeInFrame = 0; - } - - sum(0.0); - -#if LL_DEBUG - // Shouldn't be running already - llassert( !mRunning ); - mRunning = TRUE; -#endif -} - -void LLStatTime::stop() -{ - U64 end_time = getCurrentUsecs(); - U64 duration = end_time - mLastTime; - sum(F64(duration), end_time); - //llinfos << "mTotalTimeInFrame incremented from " << mTotalTimeInFrame << " to " << (mTotalTimeInFrame + duration) << llendl; - mTotalTimeInFrame += duration; - -#if LL_DEBUG - mRunning = FALSE; -#endif -} - -/* virtual */ F32 LLStatTime::meanValue(TimeScale scale) const -{ - if ( LLStatAccum::SCALE_PER_FRAME == scale ) - { - return (F32)mTotalTimeInFrame; - } - else - { - return LLStatAccum::meanValue(scale); - } -} - - -// ------------------------------------------------------------------------ - - -// Use this constructor for pre-defined LLStatTime objects -LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicStat(NULL) -{ - if (mPredefinedStat) - { - // If dynamic stats are turned on, this will create a separate entry in the stat map. - initDynamicStat(mPredefinedStat->mKey); - - // Start predefined stats. These stats are not part of the stat map. - mPredefinedStat->start(); - } -} - -// Use this constructor for normal, optional LLPerfBlock time slices -LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL) -{ - if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0) - { // These are off unless the base set is enabled - return; - } - - initDynamicStat(key); -} - - -// Use this constructor for dynamically created LLPerfBlock time slices -// that are only enabled by specific control flags -LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL) -{ - if ((sStatsFlags & flags) == 0) - { - return; - } - - if (NULL == key2 || strlen(key2) == 0) - { - initDynamicStat(key1); - } - else - { - std::ostringstream key; - key << key1 << "_" << key2; - initDynamicStat(key.str()); - } -} - -// Set up the result data map if dynamic stats are enabled -void LLPerfBlock::initDynamicStat(const std::string& key) -{ - // Early exit if dynamic stats aren't enabled. - if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS) - return; - - mLastPath = sCurrentStatPath; // Save and restore current path - sCurrentStatPath += "/" + key; // Add key to current path - - // See if the LLStatTime object already exists - stat_map_t::iterator iter = sStatMap.find(sCurrentStatPath); - if ( iter == sStatMap.end() ) - { - // StatEntry object doesn't exist, so create it - mDynamicStat = new StatEntry( key ); - sStatMap[ sCurrentStatPath ] = mDynamicStat; // Set the entry for this path - } - else - { - // Found this path in the map, use the object there - mDynamicStat = (*iter).second; // Get StatEntry for the current path - } - - if (mDynamicStat) - { - mDynamicStat->mStat.start(); - mDynamicStat->mCount++; - } - else - { - llwarns << "Initialized NULL dynamic stat at '" << sCurrentStatPath << "'" << llendl; - sCurrentStatPath = mLastPath; - } -} - - -// Destructor does the time accounting -LLPerfBlock::~LLPerfBlock() -{ - if (mPredefinedStat) mPredefinedStat->stop(); - if (mDynamicStat) - { - mDynamicStat->mStat.stop(); - sCurrentStatPath = mLastPath; // Restore the path in case sStatsEnabled changed during this block - } -} - - -// Clear the map of any dynamic stats. Static routine -void LLPerfBlock::clearDynamicStats() -{ - std::for_each(sStatMap.begin(), sStatMap.end(), DeletePairedPointer()); - sStatMap.clear(); -} - -// static - Extract the stat info into LLSD -void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats, - LLStatAccum::TimeScale scale ) -{ - // If we aren't in per-frame scale, we need to go from second to microsecond. - U32 scale_adjustment = 1; - if (LLStatAccum::SCALE_PER_FRAME != scale) - { - scale_adjustment = USEC_PER_SEC; - } - stat_map_t::iterator iter = sStatMap.begin(); - for ( ; iter != sStatMap.end(); ++iter ) - { // Put the entry into LLSD "/full/path/to/stat/" = microsecond total time - const std::string & stats_full_path = (*iter).first; - - StatEntry * stat = (*iter).second; - if (stat) - { - if (stat->mCount > 0) - { - stats[stats_full_path] = LLSD::emptyMap(); - stats[stats_full_path]["us"] = (LLSD::Integer) (scale_adjustment * stat->mStat.meanValue(scale)); - if (stat->mCount > 1) - { - stats[stats_full_path]["count"] = (LLSD::Integer) stat->mCount; - } - stat->mCount = 0; - } - } - else - { // Shouldn't have a NULL pointer in the map. - llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl; - } - } -} - - -// ------------------------------------------------------------------------ - LLTimer LLStat::sTimer; LLFrameTimer LLStat::sFrameTimer; -void LLStat::init() +void LLStat::reset() { - llassert(mNumBins > 0); mNumValues = 0; mLastValue = 0.f; - mLastTime = 0.f; - mCurBin = (mNumBins-1); + delete[] mBins; + mBins = new ValueEntry[mNumBins]; + mCurBin = mNumBins-1; mNextBin = 0; - mBins = new F32[mNumBins]; - mBeginTime = new F64[mNumBins]; - mTime = new F64[mNumBins]; - mDT = new F32[mNumBins]; - for (U32 i = 0; i < mNumBins; i++) - { - mBins[i] = 0.f; - mBeginTime[i] = 0.0; - mTime[i] = 0.0; - mDT[i] = 0.f; - } +} + +LLStat::LLStat(std::string name, S32 num_bins, BOOL use_frame_timer) +: mUseFrameTimer(use_frame_timer), + mNumBins(num_bins), + mName(name), + mBins(NULL) +{ + llassert(mNumBins > 0); + mLastTime = 0.f; + + reset(); if (!mName.empty()) { @@ -787,27 +81,9 @@ LLStat::stat_map_t& LLStat::getStatList() return *stat_list; } -LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer) - : mUseFrameTimer(use_frame_timer), - mNumBins(num_bins) -{ - init(); -} - -LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer) - : mUseFrameTimer(use_frame_timer), - mNumBins(num_bins), - mName(name) -{ - init(); -} - LLStat::~LLStat() { delete[] mBins; - delete[] mBeginTime; - delete[] mTime; - delete[] mDT; if (!mName.empty()) { @@ -819,76 +95,15 @@ LLStat::~LLStat() } } -void LLStat::reset() -{ - U32 i; - - mNumValues = 0; - mLastValue = 0.f; - mCurBin = (mNumBins-1); - delete[] mBins; - delete[] mBeginTime; - delete[] mTime; - delete[] mDT; - mBins = new F32[mNumBins]; - mBeginTime = new F64[mNumBins]; - mTime = new F64[mNumBins]; - mDT = new F32[mNumBins]; - for (i = 0; i < mNumBins; i++) - { - mBins[i] = 0.f; - mBeginTime[i] = 0.0; - mTime[i] = 0.0; - mDT[i] = 0.f; - } -} - -void LLStat::setBeginTime(const F64 time) -{ - mBeginTime[mNextBin] = time; -} - -void LLStat::addValueTime(const F64 time, const F32 value) -{ - if (mNumValues < mNumBins) - { - mNumValues++; - } - - // Increment the bin counters. - mCurBin++; - if ((U32)mCurBin == mNumBins) - { - mCurBin = 0; - } - mNextBin++; - if ((U32)mNextBin == mNumBins) - { - mNextBin = 0; - } - - mBins[mCurBin] = value; - mTime[mCurBin] = time; - mDT[mCurBin] = (F32)(mTime[mCurBin] - mBeginTime[mCurBin]); - //this value is used to prime the min/max calls - mLastTime = mTime[mCurBin]; - mLastValue = value; - - // Set the begin time for the next stat segment. - mBeginTime[mNextBin] = mTime[mCurBin]; - mTime[mNextBin] = mTime[mCurBin]; - mDT[mNextBin] = 0.f; -} - void LLStat::start() { if (mUseFrameTimer) { - mBeginTime[mNextBin] = sFrameTimer.getElapsedSeconds(); + mBins[mNextBin].mBeginTime = sFrameTimer.getElapsedSeconds(); } else { - mBeginTime[mNextBin] = sTimer.getElapsedTimeF64(); + mBins[mNextBin].mBeginTime = sTimer.getElapsedTimeF64(); } } @@ -901,41 +116,41 @@ void LLStat::addValue(const F32 value) // Increment the bin counters. mCurBin++; - if ((U32)mCurBin == mNumBins) + if ((U32)mCurBin >= mNumBins) { mCurBin = 0; } mNextBin++; - if ((U32)mNextBin == mNumBins) + if ((U32)mNextBin >= mNumBins) { mNextBin = 0; } - mBins[mCurBin] = value; + mBins[mCurBin].mValue = value; if (mUseFrameTimer) { - mTime[mCurBin] = sFrameTimer.getElapsedSeconds(); + mBins[mCurBin].mTime = sFrameTimer.getElapsedSeconds(); } else { - mTime[mCurBin] = sTimer.getElapsedTimeF64(); + mBins[mCurBin].mTime = sTimer.getElapsedTimeF64(); } - mDT[mCurBin] = (F32)(mTime[mCurBin] - mBeginTime[mCurBin]); + mBins[mCurBin].mDT = (F32)(mBins[mCurBin].mTime - mBins[mCurBin].mBeginTime); //this value is used to prime the min/max calls - mLastTime = mTime[mCurBin]; + mLastTime = mBins[mCurBin].mTime; mLastValue = value; // Set the begin time for the next stat segment. - mBeginTime[mNextBin] = mTime[mCurBin]; - mTime[mNextBin] = mTime[mCurBin]; - mDT[mNextBin] = 0.f; + mBins[mNextBin].mBeginTime = mBins[mCurBin].mTime; + mBins[mNextBin].mTime = mBins[mCurBin].mTime; + mBins[mNextBin].mDT = 0.f; } F32 LLStat::getMax() const { - U32 i; + S32 i; F32 current_max = mLastValue; if (mNumBins == 0) { @@ -943,16 +158,16 @@ F32 LLStat::getMax() const } else { - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) + for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) { // Skip the bin we're currently filling. - if (i == (U32)mNextBin) + if (i == mNextBin) { continue; } - if (mBins[i] > current_max) + if (mBins[i].mValue > current_max) { - current_max = mBins[i]; + current_max = mBins[i].mValue; } } } @@ -961,17 +176,17 @@ F32 LLStat::getMax() const F32 LLStat::getMean() const { - U32 i; + S32 i; F32 current_mean = 0.f; - U32 samples = 0; - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) + S32 samples = 0; + for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) { // Skip the bin we're currently filling. - if (i == (U32)mNextBin) + if (i == mNextBin) { continue; } - current_mean += mBins[i]; + current_mean += mBins[i].mValue; samples++; } @@ -989,7 +204,7 @@ F32 LLStat::getMean() const F32 LLStat::getMin() const { - U32 i; + S32 i; F32 current_min = mLastValue; if (mNumBins == 0) @@ -998,56 +213,22 @@ F32 LLStat::getMin() const } else { - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) + for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) { // Skip the bin we're currently filling. - if (i == (U32)mNextBin) + if (i == mNextBin) { continue; } - if (mBins[i] < current_min) + if (mBins[i].mValue < current_min) { - current_min = mBins[i]; + current_min = mBins[i].mValue; } } } return current_min; } -F32 LLStat::getSum() const -{ - U32 i; - F32 sum = 0.f; - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == (U32)mNextBin) - { - continue; - } - sum += mBins[i]; - } - - return sum; -} - -F32 LLStat::getSumDuration() const -{ - U32 i; - F32 sum = 0.f; - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == (U32)mNextBin) - { - continue; - } - sum += mDT[i]; - } - - return sum; -} - F32 LLStat::getPrev(S32 age) const { S32 bin; @@ -1063,7 +244,7 @@ F32 LLStat::getPrev(S32 age) const // Bogus for bin we're currently working on. return 0.f; } - return mBins[bin]; + return mBins[bin].mValue; } F32 LLStat::getPrevPerSec(S32 age) const @@ -1081,7 +262,7 @@ F32 LLStat::getPrevPerSec(S32 age) const // Bogus for bin we're currently working on. return 0.f; } - return mBins[bin] / mDT[bin]; + return mBins[bin].mValue / mBins[bin].mDT; } F64 LLStat::getPrevBeginTime(S32 age) const @@ -1100,7 +281,7 @@ F64 LLStat::getPrevBeginTime(S32 age) const return 0.f; } - return mBeginTime[bin]; + return mBins[bin].mBeginTime; } F64 LLStat::getPrevTime(S32 age) const @@ -1119,69 +300,45 @@ F64 LLStat::getPrevTime(S32 age) const return 0.f; } - return mTime[bin]; + return mBins[bin].mTime; } -F32 LLStat::getBin(S32 bin) const -{ - return mBins[bin]; -} - -F32 LLStat::getBinPerSec(S32 bin) const -{ - return mBins[bin] / mDT[bin]; -} - -F64 LLStat::getBinBeginTime(S32 bin) const -{ - return mBeginTime[bin]; -} F64 LLStat::getBinTime(S32 bin) const { - return mTime[bin]; + return mBins[bin].mTime; } F32 LLStat::getCurrent() const { - return mBins[mCurBin]; + return mBins[mCurBin].mValue; } F32 LLStat::getCurrentPerSec() const { - return mBins[mCurBin] / mDT[mCurBin]; -} - -F64 LLStat::getCurrentBeginTime() const -{ - return mBeginTime[mCurBin]; -} - -F64 LLStat::getCurrentTime() const -{ - return mTime[mCurBin]; + return mBins[mCurBin].mValue / mBins[mCurBin].mDT; } F32 LLStat::getCurrentDuration() const { - return mDT[mCurBin]; + return mBins[mCurBin].mDT; } F32 LLStat::getMeanPerSec() const { - U32 i; + S32 i; F32 value = 0.f; F32 dt = 0.f; - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) + for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) { // Skip the bin we're currently filling. - if (i == (U32)mNextBin) + if (i == mNextBin) { continue; } - value += mBins[i]; - dt += mDT[i]; + value += mBins[i].mValue; + dt += mBins[i].mDT; } if (dt > 0.f) @@ -1197,14 +354,14 @@ F32 LLStat::getMeanPerSec() const F32 LLStat::getMeanDuration() const { F32 dur = 0.0f; - U32 count = 0; - for (U32 i=0; (i < mNumBins) && (i < mNumValues); i++) + S32 count = 0; + for (S32 i=0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) { - if (i == (U32)mNextBin) + if (i == mNextBin) { continue; } - dur += mDT[i]; + dur += mBins[i].mDT; count++; } @@ -1221,74 +378,63 @@ F32 LLStat::getMeanDuration() const F32 LLStat::getMaxPerSec() const { - U32 i; F32 value; if (mNextBin != 0) { - value = mBins[0]/mDT[0]; + value = mBins[0].mValue/mBins[0].mDT; } else if (mNumValues > 0) { - value = mBins[1]/mDT[1]; + value = mBins[1].mValue/mBins[1].mDT; } else { value = 0.f; } - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) + for (S32 i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) { // Skip the bin we're currently filling. - if (i == (U32)mNextBin) + if (i == mNextBin) { continue; } - value = llmax(value, mBins[i]/mDT[i]); + value = llmax(value, mBins[i].mValue/mBins[i].mDT); } return value; } F32 LLStat::getMinPerSec() const { - U32 i; + S32 i; F32 value; if (mNextBin != 0) { - value = mBins[0]/mDT[0]; + value = mBins[0].mValue/mBins[0].mDT; } else if (mNumValues > 0) { - value = mBins[1]/mDT[1]; + value = mBins[1].mValue/mBins[0].mDT; } else { value = 0.f; } - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) + for (i = 0; (i < (S32)mNumBins) && (i < (S32)mNumValues); i++) { // Skip the bin we're currently filling. - if (i == (U32)mNextBin) + if (i == mNextBin) { continue; } - value = llmin(value, mBins[i]/mDT[i]); + value = llmin(value, mBins[i].mValue/mBins[i].mDT); } return value; } -F32 LLStat::getMinDuration() const -{ - F32 dur = 0.0f; - for (U32 i=0; (i < mNumBins) && (i < mNumValues); i++) - { - dur = llmin(dur, mDT[i]); - } - return dur; -} - U32 LLStat::getNumValues() const { return mNumValues; diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index 1a8404cc0..12737a8ce 100644 --- a/indra/llcommon/llstat.h +++ b/indra/llcommon/llstat.h @@ -27,294 +27,52 @@ #ifndef LL_LLSTAT_H #define LL_LLSTAT_H -#include #include #include "lltimer.h" #include "llframetimer.h" -#include "llfile.h" class LLSD; -// Set this if longer stats are needed -#define ENABLE_LONG_TIME_STATS 0 - -// -// Accumulates statistics for an arbitrary length of time. -// Does this by maintaining a chain of accumulators, each one -// accumulation the results of the parent. Can scale to arbitrary -// amounts of time with very low memory cost. -// - -class LL_COMMON_API LLStatAccum -{ -protected: - LLStatAccum(bool use_frame_timer); - virtual ~LLStatAccum(); - -public: - enum TimeScale { - SCALE_100MS, - SCALE_SECOND, - SCALE_MINUTE, -#if ENABLE_LONG_TIME_STATS - SCALE_HOUR, - SCALE_DAY, - SCALE_WEEK, -#endif - NUM_SCALES, // Use to size storage arrays - SCALE_PER_FRAME // For latest frame information - should be after NUM_SCALES since this doesn't go into the time buckets - }; - - static U64 sScaleTimes[NUM_SCALES]; - - virtual F32 meanValue(TimeScale scale) const; - // see the subclasses for the specific meaning of value - - F32 meanValueOverLast100ms() const { return meanValue(SCALE_100MS); } - F32 meanValueOverLastSecond() const { return meanValue(SCALE_SECOND); } - F32 meanValueOverLastMinute() const { return meanValue(SCALE_MINUTE); } - - void reset(U64 when); - - void sum(F64 value); - void sum(F64 value, U64 when); - - U64 getCurrentUsecs() const; - // Get current microseconds based on timer type - - BOOL mUseFrameTimer; - BOOL mRunning; - - U64 mLastTime; - - struct Bucket - { - Bucket() : - accum(0.0), - endTime(0), - lastValid(false), - lastAccum(0.0) - {} - - F64 accum; - U64 endTime; - - bool lastValid; - F64 lastAccum; - }; - - Bucket mBuckets[NUM_SCALES]; - - BOOL mLastSampleValid; - F64 mLastSampleValue; -}; - -class LL_COMMON_API LLStatMeasure : public LLStatAccum - // gathers statistics about things that are measured - // ex.: tempature, time dilation -{ -public: - LLStatMeasure(bool use_frame_timer = true); - - void sample(F64); - void sample(S32 v) { sample((F64)v); } - void sample(U32 v) { sample((F64)v); } - void sample(S64 v) { sample((F64)v); } - void sample(U64 v) { sample((F64)v); } -}; - - -class LL_COMMON_API LLStatRate : public LLStatAccum - // gathers statistics about things that can be counted over time - // ex.: LSL instructions executed, messages sent, simulator frames completed - // renders it in terms of rate of thing per second -{ -public: - LLStatRate(bool use_frame_timer = true); - - void count(U32); - // used to note that n items have occured - - void mark(); - // used for counting the rate thorugh a point in the code -}; - - -class LL_COMMON_API LLStatTime : public LLStatAccum - // gathers statistics about time spent in a block of code - // measure average duration per second in the block -{ -public: - LLStatTime( const std::string & key = "undefined" ); - - U32 mFrameNumber; // Current frame number - U64 mTotalTimeInFrame; // Total time (microseconds) accumulated during the last frame - - void setKey( const std::string & key ) { mKey = key; }; - - virtual F32 meanValue(TimeScale scale) const; - -private: - void start(); // Start and stop measuring time block - void stop(); - - std::string mKey; // Tag representing this time block - -#if LL_DEBUG - BOOL mRunning; // TRUE if start() has been called -#endif - - friend class LLPerfBlock; -}; - -// ---------------------------------------------------------------------------- - - -// Use this class on the stack to record statistics about an area of code -class LL_COMMON_API LLPerfBlock -{ -public: - struct StatEntry - { - StatEntry(const std::string& key) : mStat(LLStatTime(key)), mCount(0) {} - LLStatTime mStat; - U32 mCount; - }; - typedef std::map stat_map_t; - - // Use this constructor for pre-defined LLStatTime objects - LLPerfBlock(LLStatTime* stat); - - // Use this constructor for normal, optional LLPerfBlock time slices - LLPerfBlock( const char* key ); - - // Use this constructor for dynamically created LLPerfBlock time slices - // that are only enabled by specific control flags - LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS ); - - ~LLPerfBlock(); - - enum - { // Stats bitfield flags - LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects - LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats - LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls - }; - static void setStatsFlags( S32 flags ) { sStatsFlags = flags; }; - static S32 getStatsFlags() { return sStatsFlags; }; - - static void clearDynamicStats(); // Reset maps to clear out dynamic objects - static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin - LLStatAccum::TimeScale scale ); - -private: - // Initialize dynamically created LLStatTime objects - void initDynamicStat(const std::string& key); - - std::string mLastPath; // Save sCurrentStatPath when this is called - LLStatTime * mPredefinedStat; // LLStatTime object to get data - StatEntry * mDynamicStat; // StatEntryobject to get data - - static S32 sStatsFlags; // Control what is being recorded - static stat_map_t sStatMap; // Map full path string to LLStatTime objects - static std::string sCurrentStatPath; // Something like "frame/physics/physics step" -}; - -// ---------------------------------------------------------------------------- - -class LL_COMMON_API LLPerfStats -{ -public: - LLPerfStats(const std::string& process_name = "unknown", S32 process_pid = 0); - virtual ~LLPerfStats(); - - virtual void init(); // Reset and start all stat timers - virtual void updatePerFrameStats(); - // Override these function to add process-specific information to the performance log header and per-frame logging. - virtual void addProcessHeaderInfo(LLSD& info) { /* not implemented */ } - virtual void addProcessFrameInfo(LLSD& info, LLStatAccum::TimeScale scale) { /* not implemented */ } - - // High-resolution frame stats - BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); }; - F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; }; - void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; }; - void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS ); - void setProcessName(const std::string& process_name) { mProcessName = process_name; } - void setProcessPID(S32 process_pid) { mProcessPID = process_pid; } - -protected: - void openPerfStatsFile(); // Open file for high resolution metrics logging - void dumpIntervalPerformanceStats(); - - llofstream mFrameStatsFile; // File for per-frame stats - BOOL mFrameStatsFileFailure; // Flag to prevent repeat opening attempts - BOOL mSkipFirstFrameStats; // Flag to skip one (partial) frame report - std::string mProcessName; - S32 mProcessPID; - -private: - F32 mReportPerformanceStatInterval; // Seconds between performance stats - F64 mReportPerformanceStatEnd; // End time (seconds) for performance stats -}; - // ---------------------------------------------------------------------------- class LL_COMMON_API LLStat { private: typedef std::multimap stat_map_t; - void init(); static stat_map_t& getStatList(); public: - LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE); - LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE); + LLStat(std::string name = std::string(), S32 num_bins = 32, BOOL use_frame_timer = FALSE); ~LLStat(); - void reset(); - void start(); // Start the timer for the current "frame", otherwise uses the time tracked from // the last addValue + void reset(); void addValue(const F32 value = 1.f); // Adds the current value being tracked, and tracks the DT. void addValue(const S32 value) { addValue((F32)value); } void addValue(const U32 value) { addValue((F32)value); } - - void setBeginTime(const F64 time); - void addValueTime(const F64 time, const F32 value = 1.f); S32 getCurBin() const; S32 getNextBin() const; - F32 getCurrent() const; - F32 getCurrentPerSec() const; - F64 getCurrentBeginTime() const; - F64 getCurrentTime() const; - F32 getCurrentDuration() const; - F32 getPrev(S32 age) const; // Age is how many "addValues" previously - zero is current F32 getPrevPerSec(S32 age) const; // Age is how many "addValues" previously - zero is current + F32 getCurrent() const; + F32 getCurrentPerSec() const; + F32 getCurrentDuration() const; + F64 getPrevBeginTime(S32 age) const; F64 getPrevTime(S32 age) const; - - F32 getBin(S32 bin) const; - F32 getBinPerSec(S32 bin) const; - F64 getBinBeginTime(S32 bin) const; F64 getBinTime(S32 bin) const; - F32 getMax() const; - F32 getMaxPerSec() const; - - F32 getMean() const; - F32 getMeanPerSec() const; - F32 getMeanDuration() const; - F32 getMin() const; F32 getMinPerSec() const; - F32 getMinDuration() const; - - F32 getSum() const; - F32 getSumDuration() const; + F32 getMean() const; + F32 getMeanPerSec() const; + F32 getMeanDuration() const; + F32 getMax() const; + F32 getMaxPerSec() const; U32 getNumValues() const; S32 getNumBins() const; @@ -326,10 +84,21 @@ private: U32 mNumBins; F32 mLastValue; F64 mLastTime; - F32 *mBins; - F64 *mBeginTime; - F64 *mTime; - F32 *mDT; + + struct ValueEntry + { + ValueEntry() + : mValue(0.f), + mBeginTime(0.0), + mTime(0.0), + mDT(0.f) + {} + F32 mValue; + F64 mBeginTime; + F64 mTime; + F32 mDT; + }; + ValueEntry* mBins; S32 mCurBin; S32 mNextBin; diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h index 608ac5473..81c4085d1 100644 --- a/indra/llcommon/llstatenums.h +++ b/indra/llcommon/llstatenums.h @@ -63,6 +63,13 @@ enum LL_SIM_STAT_SIMSPARETIME = 32, LL_SIM_STAT_SIMSLEEPTIME = 33, LL_SIM_STAT_IOPUMPTIME = 34, + LL_SIM_STAT_PCTSCRIPTSRUN = 35, + LL_SIM_STAT_REGION_IDLE = 36, // dataserver only + LL_SIM_STAT_REGION_IDLE_POSSIBLE = 37, // dataserver only + LL_SIM_STAT_SIMAISTEPTIMEMS = 38, + LL_SIM_STAT_SKIPPEDAISILSTEPS_PS = 39, + LL_SIM_STAT_PCTSTEPPEDCHARACTERS = 40 + }; #endif diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 4056b3253..c96f2191f 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -24,6 +24,10 @@ * $/LicenseInfo$ */ +#if LL_WINDOWS +#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally +#endif + #include "linden_common.h" #include "llsys.h" @@ -36,22 +40,45 @@ #endif #include "llprocessor.h" +#include "llerrorcontrol.h" +#include "llevents.h" +#include "lltimer.h" +#include "llsdserialize.h" +#include "llsdutil.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace llsd; #if LL_WINDOWS # define WIN32_LEAN_AND_MEAN # include # include +# include // GetPerformanceInfo() et al. #elif LL_DARWIN # include # include # include # include # include +# include +# include +# include +# include +# include #elif LL_LINUX # include # include # include # include +# include const char MEMINFO_FILE[] = "/proc/meminfo"; #elif LL_SOLARIS # include @@ -70,6 +97,15 @@ extern int errno; static const S32 CPUINFO_BUFFER_SIZE = 16383; LLCPUInfo gSysCPU; +// Don't log memory info any more often than this. It also serves as our +// framerate sample size. +static const F32 MEM_INFO_THROTTLE = 20; +// Sliding window of samples. We intentionally limit the length of time we +// remember "the slowest" framerate because framerate is very slow at login. +// If we only triggered FrameWatcher logging when the session framerate +// dropped below the login framerate, we'd have very little additional data. +static const F32 MEM_INFO_WINDOW = 10*60; + #if LL_WINDOWS #ifndef DLLVERSIONINFO typedef struct _DllVersionInfo @@ -572,6 +608,7 @@ LLCPUInfo::LLCPUInfo() out << " (" << mCPUMHz << " MHz)"; } mCPUString = out.str(); + LLStringUtil::trim(mCPUString); } bool LLCPUInfo::hasAltivec() const @@ -613,8 +650,78 @@ void LLCPUInfo::stream(std::ostream& s) const s << "->mCPUString: " << mCPUString << std::endl; } +// Helper class for LLMemoryInfo: accumulate stats in the form we store for +// LLMemoryInfo::getStatsMap(). +class Stats +{ +public: + Stats(): + mStats(LLSD::emptyMap()) + {} + + // Store every integer type as LLSD::Integer. + template + void add(const LLSD::String& name, const T& value, + typename boost::enable_if >::type* = 0) + { + mStats[name] = LLSD::Integer(value); + } + + // Store every floating-point type as LLSD::Real. + template + void add(const LLSD::String& name, const T& value, + typename boost::enable_if >::type* = 0) + { + mStats[name] = LLSD::Real(value); + } + + // Hope that LLSD::Date values are sufficiently unambiguous. + void add(const LLSD::String& name, const LLSD::Date& value) + { + mStats[name] = value; + } + + LLSD get() const { return mStats; } + +private: + LLSD mStats; +}; + +// Wrap boost::regex_match() with a function that doesn't throw. +template +static bool regex_match_no_exc(const S& string, M& match, const R& regex) +{ + try + { + return boost::regex_match(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS("LLMemoryInfo") << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} + +// Wrap boost::regex_search() with a function that doesn't throw. +template +static bool regex_search_no_exc(const S& string, M& match, const R& regex) +{ + try + { + return boost::regex_search(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS("LLMemoryInfo") << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } +} + LLMemoryInfo::LLMemoryInfo() { + refresh(); } #if LL_WINDOWS @@ -638,11 +745,7 @@ static U32 LLMemoryAdjustKBResult(U32 inKB) U32 LLMemoryInfo::getPhysicalMemoryKB() const { #if LL_WINDOWS - MEMORYSTATUSEX state; - state.dwLength = sizeof(state); - GlobalMemoryStatusEx(&state); - - return LLMemoryAdjustKBResult((U32)(state.ullTotalPhys >> 10)); + return LLMemoryAdjustKBResult(mStatsMap["Total Physical KB"].asInteger()); #elif LL_DARWIN // This might work on Linux as well. Someone check... @@ -690,12 +793,82 @@ U32 LLMemoryInfo::getPhysicalMemoryClamped() const void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb) { #if LL_WINDOWS - MEMORYSTATUSEX state; - state.dwLength = sizeof(state); - GlobalMemoryStatusEx(&state); + // Sigh, this shouldn't be a static method, then we wouldn't have to + // reload this data separately from refresh() + LLSD statsMap(loadStatsMap()); - avail_physical_mem_kb = (U32)(state.ullAvailPhys/1024) ; - avail_virtual_mem_kb = (U32)(state.ullAvailVirtual/1024) ; + avail_physical_mem_kb = statsMap["Avail Physical KB"].asInteger(); + avail_virtual_mem_kb = statsMap["Avail Virtual KB"].asInteger(); + +#elif LL_DARWIN + // mStatsMap is derived from vm_stat, look for (e.g.) "kb free": + // $ vm_stat + // Mach Virtual Memory Statistics: (page size of 4096 bytes) + // Pages free: 462078. + // Pages active: 142010. + // Pages inactive: 220007. + // Pages wired down: 159552. + // "Translation faults": 220825184. + // Pages copy-on-write: 2104153. + // Pages zero filled: 167034876. + // Pages reactivated: 65153. + // Pageins: 2097212. + // Pageouts: 41759. + // Object cache: 841598 hits of 7629869 lookups (11% hit rate) + avail_physical_mem_kb = -1 ; + avail_virtual_mem_kb = -1 ; + +#elif LL_LINUX + // mStatsMap is derived from MEMINFO_FILE: + // $ cat /proc/meminfo + // MemTotal: 4108424 kB + // MemFree: 1244064 kB + // Buffers: 85164 kB + // Cached: 1990264 kB + // SwapCached: 0 kB + // Active: 1176648 kB + // Inactive: 1427532 kB + // Active(anon): 529152 kB + // Inactive(anon): 15924 kB + // Active(file): 647496 kB + // Inactive(file): 1411608 kB + // Unevictable: 16 kB + // Mlocked: 16 kB + // HighTotal: 3266316 kB + // HighFree: 721308 kB + // LowTotal: 842108 kB + // LowFree: 522756 kB + // SwapTotal: 6384632 kB + // SwapFree: 6384632 kB + // Dirty: 28 kB + // Writeback: 0 kB + // AnonPages: 528820 kB + // Mapped: 89472 kB + // Shmem: 16324 kB + // Slab: 159624 kB + // SReclaimable: 145168 kB + // SUnreclaim: 14456 kB + // KernelStack: 2560 kB + // PageTables: 5560 kB + // NFS_Unstable: 0 kB + // Bounce: 0 kB + // WritebackTmp: 0 kB + // CommitLimit: 8438844 kB + // Committed_AS: 1271596 kB + // VmallocTotal: 122880 kB + // VmallocUsed: 65252 kB + // VmallocChunk: 52356 kB + // HardwareCorrupted: 0 kB + // HugePages_Total: 0 + // HugePages_Free: 0 + // HugePages_Rsvd: 0 + // HugePages_Surp: 0 + // Hugepagesize: 2048 kB + // DirectMap4k: 434168 kB + // DirectMap2M: 477184 kB + // (could also run 'free', but easier to read a file than run a program) + avail_physical_mem_kb = -1 ; + avail_virtual_mem_kb = -1 ; #else //do not know how to collect available memory info for other systems. @@ -708,56 +881,285 @@ void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_v void LLMemoryInfo::stream(std::ostream& s) const { + // We want these memory stats to be easy to grep from the log, along with + // the timestamp. So preface each line with the timestamp and a + // distinctive marker. Without that, we'd have to search the log for the + // introducer line, then read subsequent lines, etc... + std::string pfx(LLError::utcTime() + " "); + + // Max key length + size_t key_width(0); + BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) + { + size_t len(pair.first.length()); + if (len > key_width) + { + key_width = len; + } + } + + // Now stream stats + BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) + { + s << pfx << std::setw(key_width+1) << (pair.first + ':') << ' '; + LLSD value(pair.second); + if (value.isInteger()) + s << std::setw(12) << value.asInteger(); + else if (value.isReal()) + s << std::fixed << std::setprecision(1) << value.asReal(); + else if (value.isDate()) + value.asDate().toStream(s); + else + s << value; // just use default LLSD formatting + s << std::endl; + } +} + +LLSD LLMemoryInfo::getStatsMap() const +{ + return mStatsMap; +} + +LLMemoryInfo& LLMemoryInfo::refresh() +{ + mStatsMap = loadStatsMap(); + + LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n"; + LLSDSerialize::toPrettyXML(mStatsMap, LL_CONT); + LL_ENDL; + + return *this; +} + +LLSD LLMemoryInfo::loadStatsMap() +{ + // This implementation is derived from stream() code (as of 2011-06-29). + Stats stats; + + // associate timestamp for analysis over time + stats.add("timestamp", LLDate::now()); + #if LL_WINDOWS MEMORYSTATUSEX state; state.dwLength = sizeof(state); GlobalMemoryStatusEx(&state); - s << "Percent Memory use: " << (U32)state.dwMemoryLoad << '%' << std::endl; - s << "Total Physical KB: " << (U32)(state.ullTotalPhys/1024) << std::endl; - s << "Avail Physical KB: " << (U32)(state.ullAvailPhys/1024) << std::endl; - s << "Total page KB: " << (U32)(state.ullTotalPageFile/1024) << std::endl; - s << "Avail page KB: " << (U32)(state.ullAvailPageFile/1024) << std::endl; - s << "Total Virtual KB: " << (U32)(state.ullTotalVirtual/1024) << std::endl; - s << "Avail Virtual KB: " << (U32)(state.ullAvailVirtual/1024) << std::endl; + DWORDLONG div = 1024; + + stats.add("Percent Memory use", state.dwMemoryLoad/div); + stats.add("Total Physical KB", state.ullTotalPhys/div); + stats.add("Avail Physical KB", state.ullAvailPhys/div); + stats.add("Total page KB", state.ullTotalPageFile/div); + stats.add("Avail page KB", state.ullAvailPageFile/div); + stats.add("Total Virtual KB", state.ullTotalVirtual/div); + stats.add("Avail Virtual KB", state.ullAvailVirtual/div); + + PERFORMANCE_INFORMATION perf; + perf.cb = sizeof(perf); + GetPerformanceInfo(&perf, sizeof(perf)); + + SIZE_T pagekb(perf.PageSize/1024); + stats.add("CommitTotal KB", perf.CommitTotal * pagekb); + stats.add("CommitLimit KB", perf.CommitLimit * pagekb); + stats.add("CommitPeak KB", perf.CommitPeak * pagekb); + stats.add("PhysicalTotal KB", perf.PhysicalTotal * pagekb); + stats.add("PhysicalAvail KB", perf.PhysicalAvailable * pagekb); + stats.add("SystemCache KB", perf.SystemCache * pagekb); + stats.add("KernelTotal KB", perf.KernelTotal * pagekb); + stats.add("KernelPaged KB", perf.KernelPaged * pagekb); + stats.add("KernelNonpaged KB", perf.KernelNonpaged * pagekb); + stats.add("PageSize KB", pagekb); + stats.add("HandleCount", perf.HandleCount); + stats.add("ProcessCount", perf.ProcessCount); + stats.add("ThreadCount", perf.ThreadCount); + + PROCESS_MEMORY_COUNTERS_EX pmem; + pmem.cb = sizeof(pmem); + // GetProcessMemoryInfo() is documented to accept either + // PROCESS_MEMORY_COUNTERS* or PROCESS_MEMORY_COUNTERS_EX*, presumably + // using the redundant size info to distinguish. But its prototype + // specifically accepts PROCESS_MEMORY_COUNTERS*, and since this is a + // classic-C API, PROCESS_MEMORY_COUNTERS_EX isn't a subclass. Cast the + // pointer. + GetProcessMemoryInfo(GetCurrentProcess(), PPROCESS_MEMORY_COUNTERS(&pmem), sizeof(pmem)); + + stats.add("Page Fault Count", pmem.PageFaultCount); + stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div); + stats.add("WorkingSetSize KB", pmem.WorkingSetSize/div); + stats.add("QutaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage/div); + stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage/div); + stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/div); + stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage/div); + stats.add("PagefileUsage KB", pmem.PagefileUsage/div); + stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage/div); + stats.add("PrivateUsage KB", pmem.PrivateUsage/div); + #elif LL_DARWIN - uint64_t phys = 0; - size_t len = sizeof(phys); + const vm_size_t pagekb(vm_page_size / 1024); + + // + // Collect the vm_stat's + // - if(sysctlbyname("hw.memsize", &phys, &len, NULL, 0) == 0) { - s << "Total Physical KB: " << phys/1024 << std::endl; - } - else - { - s << "Unable to collect memory information"; - } -#elif LL_SOLARIS - U64 phys = 0; + vm_statistics_data_t vmstat; + mach_msg_type_number_t vmstatCount = HOST_VM_INFO_COUNT; - phys = (U64)(sysconf(_SC_PHYS_PAGES)) * (U64)(sysconf(_SC_PAGESIZE)/1024); - - s << "Total Physical KB: " << phys << std::endl; -#else - // *NOTE: This works on linux. What will it do on other systems? - LLFILE* meminfo = LLFile::fopen(MEMINFO_FILE,"rb"); - if(meminfo) + if (host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t) &vmstat, &vmstatCount) != KERN_SUCCESS) { - char line[MAX_STRING]; /* Flawfinder: ignore */ - memset(line, 0, MAX_STRING); - while(fgets(line, MAX_STRING, meminfo)) - { - line[strlen(line)-1] = ' '; /*Flawfinder: ignore*/ - s << line; + LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; + } + else + { + stats.add("Pages free KB", pagekb * vmstat.free_count); + stats.add("Pages active KB", pagekb * vmstat.active_count); + stats.add("Pages inactive KB", pagekb * vmstat.inactive_count); + stats.add("Pages wired KB", pagekb * vmstat.wire_count); + + stats.add("Pages zero fill", vmstat.zero_fill_count); + stats.add("Page reactivations", vmstat.reactivations); + stats.add("Page-ins", vmstat.pageins); + stats.add("Page-outs", vmstat.pageouts); + + stats.add("Faults", vmstat.faults); + stats.add("Faults copy-on-write", vmstat.cow_faults); + + stats.add("Cache lookups", vmstat.lookups); + stats.add("Cache hits", vmstat.hits); + + stats.add("Page purgeable count", vmstat.purgeable_count); + stats.add("Page purges", vmstat.purges); + + stats.add("Page speculative reads", vmstat.speculative_count); + } + } + + // + // Collect the misc task info + // + + { + task_events_info_data_t taskinfo; + unsigned taskinfoSize = sizeof(taskinfo); + + if (task_info(mach_task_self(), TASK_EVENTS_INFO, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; + } + else + { + stats.add("Task page-ins", taskinfo.pageins); + stats.add("Task copy-on-write faults", taskinfo.cow_faults); + stats.add("Task messages sent", taskinfo.messages_sent); + stats.add("Task messages received", taskinfo.messages_received); + stats.add("Task mach system call count", taskinfo.syscalls_mach); + stats.add("Task unix system call count", taskinfo.syscalls_unix); + stats.add("Task context switch count", taskinfo.csw); + } + } + + // + // Collect the basic task info + // + + { + task_basic_info_64_data_t taskinfo; + unsigned taskinfoSize = sizeof(taskinfo); + + if (task_info(mach_task_self(), TASK_BASIC_INFO_64, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; + } + else + { + stats.add("Basic suspend count", taskinfo.suspend_count); + stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024); + stats.add("Basic resident memory KB", taskinfo.resident_size / 1024); + stats.add("Basic new thread policy", taskinfo.policy); + } + } + +#elif LL_SOLARIS + U64 phys = 0; + + phys = (U64)(sysconf(_SC_PHYS_PAGES)) * (U64)(sysconf(_SC_PAGESIZE)/1024); + + stats.add("Total Physical KB", phys); + +#elif LL_LINUX + std::ifstream meminfo(MEMINFO_FILE); + if (meminfo.is_open()) + { + // MemTotal: 4108424 kB + // MemFree: 1244064 kB + // Buffers: 85164 kB + // Cached: 1990264 kB + // SwapCached: 0 kB + // Active: 1176648 kB + // Inactive: 1427532 kB + // ... + // VmallocTotal: 122880 kB + // VmallocUsed: 65252 kB + // VmallocChunk: 52356 kB + // HardwareCorrupted: 0 kB + // HugePages_Total: 0 + // HugePages_Free: 0 + // HugePages_Rsvd: 0 + // HugePages_Surp: 0 + // Hugepagesize: 2048 kB + // DirectMap4k: 434168 kB + // DirectMap2M: 477184 kB + + // Intentionally don't pass the boost::no_except flag. This + // boost::regex object is constructed with a string literal, so it + // should be valid every time. If it becomes invalid, we WANT an + // exception, hopefully even before the dev checks in. + boost::regex stat_rx("(.+): +([0-9]+)( kB)?"); + boost::smatch matched; + + std::string line; + while (std::getline(meminfo, line)) + { + LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL; + if (regex_match_no_exc(line, matched, stat_rx)) + { + // e.g. "MemTotal: 4108424 kB" + LLSD::String key(matched[1].first, matched[1].second); + LLSD::String value_str(matched[2].first, matched[2].second); + LLSD::Integer value(0); + try + { + value = boost::lexical_cast(value_str); + } + catch (const boost::bad_lexical_cast&) + { + LL_WARNS("LLMemoryInfo") << "couldn't parse '" << value_str + << "' in " << MEMINFO_FILE << " line: " + << line << LL_ENDL; + continue; + } + // Store this statistic. + stats.add(key, value); + } + else + { + LL_WARNS("LLMemoryInfo") << "unrecognized " << MEMINFO_FILE << " line: " + << line << LL_ENDL; + } } - fclose(meminfo); } else { - s << "Unable to collect memory information"; + LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; } + +#else + LL_WARNS("LLMemoryInfo") << "Unknown system; unable to collect memory information" << LL_ENDL; + #endif + + return stats.get(); } std::ostream& operator<<(std::ostream& s, const LLOSInfo& info) @@ -778,6 +1180,143 @@ std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info) return s; } +class FrameWatcher +{ +public: + FrameWatcher(): + // Hooking onto the "mainloop" event pump gets us one call per frame. + mConnection(LLEventPumps::instance() + .obtain("mainloop") + .listen("FrameWatcher", boost::bind(&FrameWatcher::tick, this, _1))), + // Initializing mSampleStart to an invalid timestamp alerts us to skip + // trying to compute framerate on the first call. + mSampleStart(-1), + // Initializing mSampleEnd to 0 ensures that we treat the first call + // as the completion of a sample window. + mSampleEnd(0), + mFrames(0), + // Both MEM_INFO_WINDOW and MEM_INFO_THROTTLE are in seconds. We need + // the number of integer MEM_INFO_THROTTLE sample slots that will fit + // in MEM_INFO_WINDOW. Round up. + mSamples(int((MEM_INFO_WINDOW / MEM_INFO_THROTTLE) + 0.7)), + // Initializing to F32_MAX means that the first real frame will become + // the slowest ever, which sounds like a good idea. + mSlowest(F32_MAX) + {} + + bool tick(const LLSD&) + { + F32 timestamp(mTimer.getElapsedTimeF32()); + + // Count this frame in the interval just completed. + ++mFrames; + + // Have we finished a sample window yet? + if (timestamp < mSampleEnd) + { + // no, just keep waiting + return false; + } + + // Set up for next sample window. Capture values for previous frame in + // local variables and reset data members. + U32 frames(mFrames); + F32 sampleStart(mSampleStart); + // No frames yet in next window + mFrames = 0; + // which starts right now + mSampleStart = timestamp; + // and ends MEM_INFO_THROTTLE seconds in the future + mSampleEnd = mSampleStart + MEM_INFO_THROTTLE; + + // On the very first call, that's all we can do, no framerate + // computation is possible. + if (sampleStart < 0) + { + return false; + } + + // How long did this actually take? As framerate slows, the duration + // of the frame we just finished could push us WELL beyond our desired + // sample window size. + F32 elapsed(timestamp - sampleStart); + F32 framerate(frames/elapsed); + + // Remember previous slowest framerate because we're just about to + // update it. + F32 slowest(mSlowest); + // Remember previous number of samples. + boost::circular_buffer::size_type prevSize(mSamples.size()); + + // Capture new framerate in our samples buffer. Once the buffer is + // full (after MEM_INFO_WINDOW seconds), this will displace the oldest + // sample. ("So they all rolled over, and one fell out...") + mSamples.push_back(framerate); + + // Calculate the new minimum framerate. I know of no way to update a + // rolling minimum without ever rescanning the buffer. But since there + // are only a few tens of items in this buffer, rescanning it is + // probably cheaper (and certainly easier to reason about) than + // attempting to optimize away some of the scans. + mSlowest = framerate; // pick an arbitrary entry to start + for (boost::circular_buffer::const_iterator si(mSamples.begin()), send(mSamples.end()); + si != send; ++si) + { + if (*si < mSlowest) + { + mSlowest = *si; + } + } + + // We're especially interested in memory as framerate drops. Only log + // when framerate drops below the slowest framerate we remember. + // (Should always be true for the end of the very first sample + // window.) + if (framerate >= slowest) + { + return false; + } + // Congratulations, we've hit a new low. :-P + + LL_INFOS("FrameWatcher") << ' '; + if (! prevSize) + { + LL_CONT << "initial framerate "; + } + else + { + LL_CONT << "slowest framerate for last " << int(prevSize * MEM_INFO_THROTTLE) + << " seconds "; + } + LL_CONT << std::fixed << std::setprecision(1) << framerate << '\n' + << LLMemoryInfo() << LL_ENDL; + + return false; + } + +private: + // Storing the connection in an LLTempBoundListener ensures it will be + // disconnected when we're destroyed. + LLTempBoundListener mConnection; + // Track elapsed time + LLTimer mTimer; + // Some of what you see here is in fact redundant with functionality you + // can get from LLTimer. Unfortunately the LLTimer API is missing the + // feature we need: has at least the stated interval elapsed, and if so, + // exactly how long has passed? So we have to do it by hand, sigh. + // Time at start, end of sample window + F32 mSampleStart, mSampleEnd; + // Frames this sample window + U32 mFrames; + // Sliding window of framerate samples + boost::circular_buffer mSamples; + // Slowest framerate in mSamples + F32 mSlowest; +}; + +// Need an instance of FrameWatcher before it does any good +static FrameWatcher sFrameWatcher; + BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) { std::string tmpfile; diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index 41a4f2500..fb39ef4da 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -117,6 +117,27 @@ public: //get the available memory infomation in KiloBytes. static void getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb); + + // Retrieve a map of memory statistics. The keys of the map are platform- + // dependent. The values are in kilobytes to try to avoid integer overflow. + LLSD getStatsMap() const; + + // Re-fetch memory data (as reported by stream() and getStatsMap()) from the + // system. Normally this is fetched at construction time. Return (*this) + // to permit usage of the form: + // @code + // LLMemoryInfo info; + // ... + // info.refresh().getStatsMap(); + // @endcode + LLMemoryInfo& refresh(); + +private: + // set mStatsMap + static LLSD loadStatsMap(); + + // Memory stats for getStatsMap(). + LLSD mStatsMap; }; diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 08d6e2110..f64200c95 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -397,6 +397,43 @@ public: #endif }; +#if LL_DEBUG +class LL_COMMON_API AINRLock +{ +private: + int read_locked; + int write_locked; + + mutable bool mAccessed; + mutable AIThreadID mTheadID; + + void accessed(void) const + { + if (!mAccessed) + { + mAccessed = true; + mTheadID.reset(); + } + else + { + llassert_always(mTheadID.equals_current_thread()); + } + } + +public: + AINRLock(void) : read_locked(false), write_locked(false), mAccessed(false) { } + + bool isLocked() const { return read_locked || write_locked; } + + void rdlock(bool high_priority = false) { accessed(); ++read_locked; } + void rdunlock() { --read_locked; } + void wrlock() { llassert(!isLocked()); accessed(); ++write_locked; } + void wrunlock() { --write_locked; } + void wr2rdlock() { llassert(false); } + void rd2wrlock() { llassert(false); } +}; +#endif + //============================================================================ void LLThread::lockData() diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 1cbd888e5..f6b9db6c1 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -41,10 +41,15 @@ #include "llmd5.h" #include "llstring.h" #include "lltimer.h" +#include "llthread.h" const LLUUID LLUUID::null; const LLTransactionID LLTransactionID::tnull; +// static +LLMutex * LLUUID::mMutex = NULL; + + /* NOT DONE YET!!! @@ -731,6 +736,7 @@ void LLUUID::getCurrentTime(uuid_time_t *timestamp) getSystemTime(&time_last); uuids_this_tick = uuids_per_tick; init = TRUE; + mMutex = new LLMutex; } uuid_time_t time_now = {0,0}; @@ -782,6 +788,7 @@ void LLUUID::generate() #endif if (!has_init) { + has_init = 1; if (getNodeID(node_id) <= 0) { get_random_bytes(node_id, 6); @@ -803,18 +810,24 @@ void LLUUID::generate() #else clock_seq = (U16)ll_rand(65536); #endif - has_init = 1; } // get current time getCurrentTime(×tamp); + U16 our_clock_seq = clock_seq; - // if clock went backward change clockseq - if (cmpTime(×tamp, &time_last) == -1) { + // if clock hasn't changed or went backward, change clockseq + if (cmpTime(×tamp, &time_last) != 1) + { + LLMutexLock lock(mMutex); clock_seq = (clock_seq + 1) & 0x3FFF; - if (clock_seq == 0) clock_seq++; + if (clock_seq == 0) + clock_seq++; + our_clock_seq = clock_seq; // Ensure we're using a different clock_seq value from previous time } + time_last = timestamp; + memcpy(mData+10, node_id, 6); /* Flawfinder: ignore */ U32 tmp; tmp = timestamp.low; @@ -836,7 +849,8 @@ void LLUUID::generate() tmp >>= 8; mData[6] = (unsigned char) tmp; - tmp = clock_seq; + tmp = our_clock_seq; + mData[9] = (unsigned char) tmp; tmp >>= 8; mData[8] = (unsigned char) tmp; @@ -846,8 +860,6 @@ void LLUUID::generate() md5_uuid.update(mData,16); md5_uuid.finalize(); md5_uuid.raw_digest(mData); - - time_last = timestamp; } void LLUUID::generate(const std::string& hash_string) @@ -861,8 +873,14 @@ U32 LLUUID::getRandomSeed() static unsigned char seed[16]; /* Flawfinder: ignore */ getNodeID(&seed[0]); - seed[6]='\0'; - seed[7]='\0'; + + // Incorporate the pid into the seed to prevent + // processes that start on the same host at the same + // time from generating the same seed. + pid_t pid = LLApp::getPid(); + + seed[6]=(unsigned char)(pid >> 8); + seed[7]=(unsigned char)(pid); getSystemTime((uuid_time_t *)(&seed[8])); LLMD5 md5_seed; diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index 726be4a82..4e5bed189 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -31,6 +31,8 @@ #include "stdtypes.h" #include "llpreprocessor.h" +class LLMutex; + const S32 UUID_BYTES = 16; const S32 UUID_WORDS = 4; const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below @@ -118,6 +120,7 @@ public: static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal. static const LLUUID null; + static LLMutex * mMutex; static U32 getRandomSeed(); static S32 getNodeID(unsigned char * node_id); diff --git a/indra/llmessage/aihttptimeout.cpp b/indra/llmessage/aihttptimeout.cpp index 61ed5ca86..499921a2e 100644 --- a/indra/llmessage/aihttptimeout.cpp +++ b/indra/llmessage/aihttptimeout.cpp @@ -152,7 +152,7 @@ void HTTPTimeout::upload_finished(void) // ^ ^ ^ ^ ^ ^ ^ ^ // | | | | | | | | bool HTTPTimeout::data_received(size_t n/*,*/ -#ifdef CWDEBUG +#if defined(CWDEBUG) || defined(DEBUG_CURLIO) ASSERT_ONLY_COMMA(bool upload_error_status) #else ASSERT_ONLY_COMMA(bool) @@ -208,8 +208,9 @@ bool HTTPTimeout::lowspeed(size_t bytes) // // We do this as follows: we create low_speed_time (in seconds) buckets and fill them with the number // of bytes received during that second. We also keep track of the sum of all bytes received between 'now' - // and 'now - llmax(starttime, low_speed_time)'. Then if that period reaches at least low_speed_time - // seconds, and the transfer rate (sum / low_speed_time) is less than low_speed_limit, we abort. + // and 'llmax(starttime, now - low_speed_time)'. Then if that period reaches at least low_speed_time + // seconds (when now >= starttime + low_speed_time) and the transfer rate (sum / low_speed_time) is + // less than low_speed_limit, we abort. // When are we? S32 second = (sClockCount - mLowSpeedClock) * sClockWidth; @@ -244,6 +245,7 @@ bool HTTPTimeout::lowspeed(size_t bytes) if (s == -1) { mBucket = 0; // It doesn't really matter where we start. + mOverwriteSecond = second + low_speed_time; mTotalBytes = bytes; mBuckets[mBucket] = bytes; return false; @@ -257,11 +259,17 @@ bool HTTPTimeout::lowspeed(size_t bytes) bucket = 0; if (++s == second) break; - mTotalBytes -= mBuckets[bucket]; + if (s >= mOverwriteSecond) + { + mTotalBytes -= mBuckets[bucket]; + } mBuckets[bucket] = 0; } mBucket = bucket; - mTotalBytes -= mBuckets[mBucket]; + if (s >= mOverwriteSecond) + { + mTotalBytes -= mBuckets[mBucket]; + } mTotalBytes += bytes; mBuckets[mBucket] = bytes; @@ -286,29 +294,40 @@ bool HTTPTimeout::lowspeed(size_t bytes) } // Calculate how long the data transfer may stall until we should timeout. + // + // Assume 6 buckets: 0 1 2 3 4 5 (low_speed_time == 6) + // Seconds since start of transfer: 4 5 6 7 8 9 (mOverwriteSecond == 10) + // Current second: ^ + // Data in buckets: A B w x y z (mTotalBytes = A + B; w, x, y and z are undefined) + // + // Obviously, we need to stall at LEAST till second low_speed_time before we can "timeout". + // And possibly more if mTotalBytes is already >= mintotalbytes. + // + // The code below finds 'max_stall_time', so that when from now on the buckets + // are filled with 0, then at 'second + max_stall_time' we should time out, + // meaning that the resulting mTotalBytes after writing 0 at that second + // will be less than mintotalbytes and 'second + max_stall_time' >= low_speed_time. + // llassert_always(mintotalbytes > 0); - S32 max_stall_time = 0; - U32 dropped_bytes = 0; - while(1) + S32 max_stall_time = low_speed_time - second; // Minimum value. + // Note that if max_stall_time <= 0 here, then second >= low_speed_time and + // thus mTotalBytes >= mintotalbytes because we didn't timeout already above. + if (mTotalBytes >= mintotalbytes) { - if (++bucket == low_speed_time) // The next second the next bucket will be emptied. - bucket = 0; - ++max_stall_time; - dropped_bytes += mBuckets[bucket]; - // Note how, when max_stall_time == low_speed_time, dropped_bytes has - // to be equal to mTotalBytes, the sum of all vector elements. - llassert(max_stall_time < low_speed_time || dropped_bytes == mTotalBytes); - // AIFIXME: This is a bug and should really be fixed instead of just be a warning. - if (!(max_stall_time < low_speed_time || dropped_bytes == mTotalBytes)) + // In this case max_stall_time has a minimum value equal to when we will reach mOverwriteSecond, + // because that is the first second at which mTotalBytes will decrease. + max_stall_time = mOverwriteSecond - second - 1; + U32 total_bytes = mTotalBytes; + int bucket = -1; // Must be one less as the start bucket, which corresponds with mOverwriteSecond (and thus with the current max_stall_time). + do { - llwarns << "ASSERT max_stall_time < low_speed_time || dropped_bytes == mTotalBytes failed... aborting. " - "max_stall_time = " << max_stall_time << "; low_speed_time = " << low_speed_time << - "; dropped_bytes = " << dropped_bytes << "; mTotalBytes = " << mTotalBytes << llendl; - break; + ++max_stall_time; // Next second (mOverwriteSecond upon entry of the loop). + ++bucket; // The next bucket (0 upon entry of the loop). + // Once we reach the end of the vector total_bytes MUST have reached 0 exactly and we should have left this loop. + llassert_always(bucket < low_speed_time); + total_bytes -= mBuckets[bucket]; // Empty this bucket. } - // And thus the following will certainly abort. - if (second + max_stall_time >= low_speed_time && mTotalBytes - dropped_bytes < mintotalbytes) - break; + while(total_bytes >= 1); // Use 1 here instead of mintotalbytes, to test that total_bytes indeed always reaches zero. } // If this function isn't called again within max_stall_time seconds, we stalled. mStalled = sClockCount + max_stall_time / sClockWidth; diff --git a/indra/llmessage/aihttptimeout.h b/indra/llmessage/aihttptimeout.h index 6bb89ee20..ab7895a3b 100644 --- a/indra/llmessage/aihttptimeout.h +++ b/indra/llmessage/aihttptimeout.h @@ -81,6 +81,7 @@ class HTTPTimeout : public LLRefCount { bool mLowSpeedOn; // Set while uploading or downloading data. bool mUploadFinished; // Used to keep track of whether upload_finished was called yet. S32 mLastSecond; // The time at which lowspeed() was last called, in seconds since mLowSpeedClock. + S32 mOverwriteSecond; // The second at which the first bucket of this transfer will be overwritten. U32 mTotalBytes; // The sum of all bytes in mBuckets. U64 mLowSpeedClock; // Clock count at which low speed detection (re)started. U64 mStalled; // The clock count at which this transaction is considered to be stalling if nothing is transfered anymore. diff --git a/indra/llmessage/debug_libcurl.cpp b/indra/llmessage/debug_libcurl.cpp index 0a302e601..e07cc4ba4 100644 --- a/indra/llmessage/debug_libcurl.cpp +++ b/indra/llmessage/debug_libcurl.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "llpreprocessor.h" #include #define COMPILING_DEBUG_LIBCURL_CC diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp index 2ae76ab5e..6bb435f53 100644 --- a/indra/llmessage/llcircuit.cpp +++ b/indra/llmessage/llcircuit.cpp @@ -680,7 +680,6 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) setPacketInID((id + 1) % LL_MAX_OUT_PACKET_ID); mLastPacketGap = 0; - mOutOfOrderRate.count(0); return; } @@ -776,7 +775,6 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent) } } - mOutOfOrderRate.count(gap); mLastPacketGap = gap; } diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h index cd7576efa..13b0e9e49 100644 --- a/indra/llmessage/llcircuit.h +++ b/indra/llmessage/llcircuit.h @@ -40,7 +40,6 @@ #include "llpacketack.h" #include "lluuid.h" #include "llthrottle.h" -#include "llstat.h" // // Constants @@ -126,8 +125,6 @@ public: S32 getUnackedPacketCount() const { return mUnackedPacketCount; } S32 getUnackedPacketBytes() const { return mUnackedPacketBytes; } F64 getNextPingSendTime() const { return mNextPingSendTime; } - F32 getOutOfOrderRate(LLStatAccum::TimeScale scale = LLStatAccum::SCALE_MINUTE) - { return mOutOfOrderRate.meanValue(scale); } U32 getLastPacketGap() const { return mLastPacketGap; } LLHost getHost() const { return mHost; } F64 getLastPacketInTime() const { return mLastPacketInTime; } @@ -275,7 +272,6 @@ protected: LLTimer mExistenceTimer; // initialized when circuit created, used to track bandwidth numbers S32 mCurrentResendCount; // Number of resent packets since last spam - LLStatRate mOutOfOrderRate; // Rate of out of order packets coming in. U32 mLastPacketGap; // Gap in sequence number of last packet. const F32 mHeartbeatInterval; diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index 6e2ec7f9b..9ce06f147 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -141,6 +141,11 @@ private: }; static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PIPE("HTTP Pipe"); +static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_GET("HTTP Get"); +static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_PUT("HTTP Put"); +static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_POST("HTTP Post"); +static LLFastTimer::DeclareTimer FTM_PROCESS_HTTP_DELETE("HTTP Delete"); + LLIOPipe::EStatus LLHTTPPipe::process_impl( const LLChannelDescriptors& channels, buffer_ptr_t& buffer, @@ -177,12 +182,12 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB]; if(verb == HTTP_VERB_GET) { - LLPerfBlock getblock("http_get"); + LLFastTimer _(FTM_PROCESS_HTTP_GET); mNode.get(LLHTTPNode::ResponsePtr(mResponse), context); } else if(verb == HTTP_VERB_PUT) { - LLPerfBlock putblock("http_put"); + LLFastTimer _(FTM_PROCESS_HTTP_PUT); LLSD input; if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) { @@ -198,7 +203,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( } else if(verb == HTTP_VERB_POST) { - LLPerfBlock postblock("http_post"); + LLFastTimer _(FTM_PROCESS_HTTP_POST); LLSD input; if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD) { @@ -214,7 +219,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl( } else if(verb == HTTP_VERB_DELETE) { - LLPerfBlock delblock("http_delete"); + LLFastTimer _(FTM_PROCESS_HTTP_DELETE); mNode.del(LLHTTPNode::ResponsePtr(mResponse), context); } else if(verb == HTTP_VERB_OPTIONS) diff --git a/indra/llmessage/llmessagetemplate.h b/indra/llmessage/llmessagetemplate.h index 16d825d33..a91a8f775 100644 --- a/indra/llmessage/llmessagetemplate.h +++ b/indra/llmessage/llmessagetemplate.h @@ -364,7 +364,6 @@ public: { if (mHandlerFunc) { - LLPerfBlock msg_cb_time("msg_cb", mName); mHandlerFunc(msgsystem, mUserData); return TRUE; } diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index e6c6a42d6..d4f6f59b1 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -454,6 +454,7 @@ void LLPumpIO::pump() } static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO"); +static LLFastTimer::DeclareTimer FTM_PUMP_POLL("Pump Poll"); LLPumpIO::current_chain_t LLPumpIO::removeRunningChain(LLPumpIO::current_chain_t& run_chain) { @@ -549,7 +550,7 @@ void LLPumpIO::pump(const S32& poll_timeout) S32 count = 0; S32 client_id = 0; { - LLPerfBlock polltime("pump_poll"); + LLFastTimer _(FTM_PUMP_POLL); apr_pollset_poll(mPollset, poll_timeout, &count, &poll_fd); } PUMP_DEBUG; diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 6aa14e8d6..e35d5b5dd 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -82,6 +82,7 @@ set(llui_SOURCE_FILES set(llui_HEADER_FILES CMakeLists.txt + ailist.h llalertdialog.h llbutton.h llcallbackmap.h diff --git a/indra/llui/ailist.h b/indra/llui/ailist.h new file mode 100644 index 000000000..14ef05f0c --- /dev/null +++ b/indra/llui/ailist.h @@ -0,0 +1,645 @@ +/** + * @file ailist.h + * @brief A linked list with iterators that advance when their element is deleted. + * + * Copyright (c) 2013, Aleric Inglewood. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution. + * + * CHANGELOG + * and additional copyright holders. + * + * 05/02/2013 + * Initial version, written by Aleric Inglewood @ SL + */ + +#ifndef AILIST_H +#define AILIST_H + +#include + +template +class AIList; + +template +class AIConstListIterator; + +/* + * AINode + * + * The actual data stored in a std::list when using AIList. + * T is the template parameter used with AIList. + * count are the number of iterators that currently point to this element. + * dead is 0 or 1, where 1 means that the element was erased from the AIList + * (but not yet from the internal std::list, so that any iterators to it + * are NOT invalidated). + */ +template +struct AINode { + T mElement; // The user visual data. + mutable unsigned short count; // Number of iterators pointing to this element. + mutable unsigned short dead; // Whether or not the element is "erased". + + AINode(void) : count(0), dead(0) { } + explicit AINode(T const& __val) : mElement(__val), count(0), dead(0) { } + + // Equivalence operators. + // __node may not be dead. Dead nodes in the list are "skipped" (obviously), meaning that they are never equal or always unequal. + bool operator==(AINode const& __node) const { llassert(!__node.dead); return mElement == __node.mElement && !dead; } + bool operator!=(AINode const& __node) const { llassert(!__node.dead); return mElement != __node.mElement || dead; } + + // Default ordering for sort(). + bool operator<(AINode const& __node) const { return mElement < __node.mElement; } +}; + +/* + * AIListIterator + * + * A non-const iterator to an element of AIList. + */ +template +class AIListIterator { + private: + typedef AIListIterator _Self; + typedef std::list > _Container; + typedef typename _Container::iterator _Iterator; + + _Container* mContainer; // A pointer to the associated container, or NULL when (still) singular. + // Note that this code does not allow a container to be destructed while + // any non-end iterators still exist (although that could be legal). + // If an iterator points to end() and the container is destructed then + // this pointer is NOT reset to NULL. + _Iterator mIterator; // Internal iterator to element of mContainer (or singular when mContainer is NULL). + + // Increment reference counter for mIterator (if not singular and not end()). + void ref(void) + { + if (mContainer && mContainer->end() != mIterator) + { + // It would be bad a new iterator was created that pointed to a dead element. + // Also, as a sanity check, make sure there aren't a ridiculous number of iterators + // pointing to this element. + llassert(!mIterator->dead && mIterator->count < 100); + ++(mIterator->count); + } + } + + // Decrement reference counter for mIterator (if not singular and not end()). + // If this was the last iterator pointing to a dead element, then really erase it. + void unref(void) + { + if (mContainer && mContainer->end() != mIterator) + { + llassert(mIterator->count > 0); + if (--(mIterator->count) == 0 && mIterator->dead) + { + mContainer->erase(mIterator); + } + } + } + + public: + // Some standard typedefs that have to exist for iterators. + typedef typename _Iterator::difference_type difference_type; + typedef typename _Iterator::iterator_category iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + + // Construct a singular iterator. + AIListIterator(void) : mContainer(NULL) { } + + // Construct an iterator to a given element of std::list. Only for internal use by AIList. + AIListIterator(_Container* __c, _Iterator const& __i) : mContainer(__c), mIterator(__i) + { + llassert(mContainer); + ref(); + } + + // Copy constructor. + AIListIterator(AIListIterator const& __i) : mContainer(__i.mContainer), mIterator(__i.mIterator) + { + ref(); + } + + // Destructor. + ~AIListIterator() + { + unref(); + } + + // Assignment operator. + _Self& operator=(_Self const& __x) + { + unref(); // We no longer point to whatever we were pointing. + mContainer = __x.mContainer; + mIterator = __x.mIterator; + llassert(mContainer); + ref(); // We now point an(other) element. + return *this; + } + + // Dereference operator. + reference operator*() const + { + // Iterator may not be singular or dead. + llassert(mContainer && !mIterator->dead); + return mIterator->mElement; + } + + // Dereference operator. + pointer operator->() const + { + // Iterator may not be singular or dead. + llassert(mContainer && !mIterator->dead); + return &mIterator->mElement; + } + + // Pre-increment operator (not being singular is implied). + _Self& operator++() + { + _Iterator cur = mIterator; // Make copy of mIterator. + ++cur; // Advance it. + unref(); // We will no longer be pointing to this element. This might invalidate mIterator! + while(cur != mContainer->end() && cur->dead) // Advance till the first non-dead element. + { + ++cur; + } + mIterator = cur; // Put result back into mIterator. + ref(); // We are now pointing to a valid element again. + return *this; + } + + // Post-increment operator (not being singular is implied). + _Self operator++(int) + { + _Self tmp = *this; + this->operator++(); + return tmp; + } + + // Pre-decrement operator (not being singular is implied). + _Self& operator--() + { + _Iterator cur = mIterator; // See operator++(). + --cur; + unref(); + while(cur->dead) + { + --cur; + } + mIterator = cur; + ref(); + return *this; + } + + // Post-decrement operator (not being singular is implied). + _Self operator--(int) + { + _Self tmp = *this; + this->operator--(); + return tmp; + } + + // Equivalence operators. + // We allow comparing with dead iterators, because if one of them is not-dead + // then the result is "unequal" anyway, which is probably what you want. + bool operator==(_Self const& __x) const { return mIterator == __x.mIterator; } + bool operator!=(_Self const& __x) const { return mIterator != __x.mIterator; } + + friend class AIList; + friend class AIConstListIterator; + template friend bool operator==(AIListIterator const& __x, AIConstListIterator const& __y); + template friend bool operator!=(AIListIterator const& __x, AIConstListIterator const& __y); + + // Return the total number of iterators pointing the element that this iterator is pointing to. + // Unless the iterator points to end, a positive number will be returned since this iterator is + // pointing to the element. If it points to end (or is singular) then 0 is returned. + int count(void) const + { + if (mContainer && mIterator != mContainer->end()) + { + return mIterator->count; + } + return 0; + } +}; + +/* + * AIConstListIterator + * + * A const iterator to an element of AIList. + * + * Because this class is very simular to AIListIterator, see above for detailed comments. + */ +template +class AIConstListIterator { + private: + typedef AIConstListIterator _Self; + typedef std::list > _Container; + typedef typename _Container::iterator _Iterator; + typedef typename _Container::const_iterator _ConstIterator; + typedef AIListIterator iterator; + + _Container const* mContainer; + _Iterator mConstIterator; // This has to be an _Iterator instead of _ConstIterator, because the compiler doesn't accept a const_iterator for erase yet (C++11 does). + + void ref(void) + { + if (mContainer && mContainer->end() != mConstIterator) + { + llassert(mConstIterator->count < 100); + mConstIterator->count++; + } + } + + void unref(void) + { + if (mContainer && mContainer->end() != mConstIterator) + { + llassert(mConstIterator->count > 0); + mConstIterator->count--; + if (mConstIterator->count == 0 && mConstIterator->dead) + { + const_cast<_Container*>(mContainer)->erase(mConstIterator); + } + } + } + + public: + typedef typename _ConstIterator::difference_type difference_type; + typedef typename _ConstIterator::iterator_category iterator_category; + typedef T value_type; + typedef T const* pointer; + typedef T const& reference; + + AIConstListIterator(void) : mContainer(NULL) { } + AIConstListIterator(_Container const* __c, _Iterator const& __i) : mContainer(__c), mConstIterator(__i) + { + llassert(mContainer); + ref(); + } + // Allow to construct a const_iterator from an iterator. + AIConstListIterator(iterator const& __x) : mContainer(__x.mContainer), mConstIterator(__x.mIterator) + { + ref(); + } + AIConstListIterator(AIConstListIterator const& __i) : mContainer(__i.mContainer), mConstIterator(__i.mConstIterator) + { + ref(); + } + ~AIConstListIterator() + { + unref(); + } + + _Self& operator=(_Self const& __x) + { + unref(); + mContainer = __x.mContainer; + mConstIterator = __x.mConstIterator; + llassert(mContainer); + ref(); + return *this; + } + + // Allow to assign from a non-const iterator. + _Self& operator=(iterator const& __x) + { + unref(); + mContainer = __x.mContainer; + mConstIterator = __x.mIterator; + llassert(mContainer); + ref(); + return *this; + } + + reference operator*() const + { + llassert(mContainer && !mConstIterator->dead); + return mConstIterator->mElement; + } + + pointer operator->() const + { + llassert(mContainer && !mConstIterator->dead); + return &mConstIterator->mElement; + } + + _Self& operator++() + { + _Iterator cur = mConstIterator; + ++cur; + unref(); + while(cur != mContainer->end() && cur->dead) + { + ++cur; + } + mConstIterator = cur; + ref(); + return *this; + } + + _Self operator++(int) + { + _Self tmp = *this; + this->operator++(); + return tmp; + } + + _Self& operator--() + { + _Iterator cur = mConstIterator; + --cur; + unref(); + while(cur->dead) + { + --cur; + } + mConstIterator = cur; + ref(); + return *this; + } + + _Self operator--(int) + { + _Self tmp = *this; + this->operator--(); + return tmp; + } + + bool operator==(_Self const& __x) const { return mConstIterator == __x.mConstIterator; } + bool operator!=(_Self const& __x) const { return mConstIterator != __x.mConstIterator; } + bool operator==(iterator const& __x) const { return mConstIterator == __x.mIterator; } + bool operator!=(iterator const& __x) const { return mConstIterator != __x.mIterator; } + + template friend bool operator==(AIListIterator const& __x, AIConstListIterator const& __y); + template friend bool operator!=(AIListIterator const& __x, AIConstListIterator const& __y); + + int count(void) const + { + if (mContainer && mConstIterator != mContainer->end()) + { + return mConstIterator->count; + } + return 0; + } +}; + +template +inline bool operator==(AIListIterator const& __x, AIConstListIterator const& __y) +{ + return __x.mIterator == __y.mConstIterator; +} + +template +inline bool operator!=(AIListIterator const& __x, AIConstListIterator const& __y) +{ + return __x.mIterator != __y.mConstIterator; +} + +/* + * AIList + * + * A linked list that allows elements to be erased while one or more iterators + * are still pointing to that element, after which pre-increment and pre-decrement + * operators still work. + * + * For example: + * + * for (AIList::iterator i = l.begin(); i != l.end(); ++i) + * { + * int x = *i; + * f(i); // Might erase any element of list l. + * // Should not dereference i anymore here (because it might be erased). + * } + */ +template +class AIList { + private: + typedef std::list > _Container; + typedef typename _Container::iterator _Iterator; + typedef typename _Container::const_iterator _ConstIterator; + + _Container mContainer; + size_t mSize; + + public: + typedef T value_type; + typedef T* pointer; + typedef T const* const_pointer; + typedef T& reference; + typedef T const& const_reference; + typedef AIListIterator iterator; + typedef AIConstListIterator const_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + // Default constructor. Create an empty list. + AIList(void) : mSize(0) { } +#ifdef LL_DEBUG + // Destructor calls clear() to check if there are no iterators left pointing to this list. Destructing an empty list is trivial. + ~AIList() { clear(); } +#endif + + // Construct a list with __n elements of __val. + explicit AIList(size_type __n, value_type const& __val = value_type()) : mContainer(__n, AINode(__val)), mSize(__n) { } + + // Copy constructor. + AIList(AIList const& __list) : mSize(0) + { + for (_ConstIterator __i = __list.mContainer.begin(); __i != __list.mContainer.end(); ++__i) + { + if (!__i->dead) + { + mContainer.push_back(AINode(__i->mElement)); + ++mSize; + } + } + } + + // Construct a list from the range [__first, __last>. + template + AIList(_InputIterator __first, _InputIterator __last) : mSize(0) + { + for (_InputIterator __i = __first; __i != __last; ++__i) + { + mContainer.push_back(AINode(*__i)); + ++mSize; + } + } + + // Assign from another list. + AIList& operator=(AIList const& __list) + { + clear(); + for (_ConstIterator __i = __list.mContainer.begin(); __i != __list.mContainer.end(); ++__i) + { + if (!__i->dead) + { + mContainer.push_back(AINode(__i->mElement)); + ++mSize; + } + } + return *this; + } + + iterator begin() + { + _Iterator __i = mContainer.begin(); + while(__i != mContainer.end() && __i->dead) + { + ++__i; + } + return iterator(&mContainer, __i); + } + + const_iterator begin() const + { + _Iterator __i = const_cast<_Container&>(mContainer).begin(); + while(__i != mContainer.end() && __i->dead) + { + ++__i; + } + return const_iterator(&mContainer, __i); + } + + iterator end() { return iterator(&mContainer, mContainer.end()); } + const_iterator end() const { return const_iterator(&mContainer, const_cast<_Container&>(mContainer).end()); } + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } + + bool empty() const { return mSize == 0; } + size_type size() const { return mSize; } + size_type max_size() const { return mContainer.max_size(); } + + reference front() { iterator __i = begin(); return *__i; } + const_reference front() const { const_iterator __i = begin(); return *__i; } + reference back() { iterator __i = end(); --__i; return *__i; } + const_reference back() const { const_iterator __i = end(); --__i; return *__i; } + + void push_front(value_type const& __x) + { + mContainer.push_front(AINode(__x)); + ++mSize; + } + void pop_front() + { + iterator __i = begin(); + erase(__i); + } + void push_back(value_type const& __x) + { + mContainer.push_back(AINode(__x)); + ++mSize; + } + void pop_back() + { + iterator __i = end(); + --__i; + erase(__i); + } + + iterator insert(iterator __position, value_type const& __x) + { + ++mSize; + return iterator(&mContainer, mContainer.insert(__position.mIterator, AINode(__x))); + } + + void clear() + { +#ifdef LL_DEBUG + // There should be no iterators left pointing at any element here. + for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i) + { + llassert(__i->count == 0); + } +#endif + mContainer.clear(); + mSize = 0; + } + + iterator erase(iterator __position) + { + // Mark the element __position points to as being erased. + // Iterator may not be singular, point to end, or be dead already. + // Obviously count must be larger than zero since __position is still pointing to it. + llassert(__position.mContainer == &mContainer && __position.mIterator != mContainer.end() && __position.mIterator->count > 0 && !__position.mIterator->dead); + __position.mIterator->dead = 1; + --mSize; + return ++__position; + } + + // Remove all elements, designated by the iterator where, for which *where == __val. + void remove(value_type const& __val) + { + _Iterator const __e = mContainer.end(); + for (_Iterator __i = mContainer.begin(); __i != __e;) + { + if (!__i->dead && __i->mElement == __val) + { + --mSize; + if (__i->count == 0) + { + mContainer.erase(__i++); + continue; + } + // Mark the element as being erased. + __i->dead = 1; + } + ++__i; + } + } + + void sort() + { +#ifdef LL_DEBUG + // There should be no iterators left pointing at any element here. + for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i) + { + llassert(__i->count == 0); + } +#endif + mContainer.sort(); + } + template + struct PredWrapper + { + _StrictWeakOrdering mPred; + PredWrapper(_StrictWeakOrdering const& pred) : mPred(pred) { } + bool operator()(AINode const& __x, AINode const& __y) const { return mPred(__x.mElement, __y.mElement); } + }; + template + void sort(_StrictWeakOrdering const& pred) + { +#ifdef LL_DEBUG + // There should be no iterators left pointing at any element here. + for (_Iterator __i = mContainer.begin(); __i != mContainer.end(); ++__i) + { + llassert(__i->count == 0); + } +#endif + mContainer.sort(PredWrapper<_StrictWeakOrdering>(pred)); + } +}; + +#endif diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 1cbb52dab..b91b0df43 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -911,6 +911,8 @@ void LLFloater::setMinimized(BOOL minimize) // Lose keyboard focus when minimized releaseFocus(); + // Also reset mLockedView and mLastKeyboardFocus, to avoid that we get focus back somehow. + gFocusMgr.removeKeyboardFocusWithoutCallback(this); for (S32 i = 0; i < 4; i++) { diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 66834a6a1..7817fd0d5 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -55,6 +55,8 @@ BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_pa // virtual LLFocusableElement::~LLFocusableElement() { + // Make sure nothing is pointing to us anymore! + gFocusMgr.removeKeyboardFocusWithoutCallback(this); delete mFocusLostCallback; delete mFocusReceivedCallback; delete mFocusChangedCallback; @@ -131,6 +133,7 @@ LLFocusMgr::LLFocusMgr() mKeyboardFocus( NULL ), mLastKeyboardFocus( NULL ), mDefaultKeyboardFocus( NULL ), + mLastDefaultKeyboardFocus( NULL ), mKeystrokesOnly(FALSE), mTopCtrl( NULL ), mAppHasFocus(TRUE), // Macs don't seem to notify us that we've gotten focus, so default to true @@ -171,6 +174,23 @@ void LLFocusMgr::releaseFocusIfNeeded( const LLView* view ) } } +void LLFocusMgr::restoreDefaultKeyboardFocus(LLFocusableElement* current_default_focus) +{ + if (current_default_focus && mDefaultKeyboardFocus == current_default_focus) + { + setDefaultKeyboardFocus(mLastDefaultKeyboardFocus); + mLastDefaultKeyboardFocus = NULL; + } +} + +void LLFocusMgr::restoreKeyboardFocus(LLFocusableElement* current_focus) +{ + if (current_focus && mKeyboardFocus == current_focus) + { + setKeyboardFocus(mLastKeyboardFocus); + mLastKeyboardFocus = NULL; + } +} void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only) { @@ -328,11 +348,22 @@ void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* f { mLockedView = NULL; } - - if( mKeyboardFocus == focus ) + if (mKeyboardFocus == focus) { mKeyboardFocus = NULL; } + if (mLastKeyboardFocus == focus) + { + mLastKeyboardFocus = NULL; + } + if (mDefaultKeyboardFocus == focus) + { + mDefaultKeyboardFocus = NULL; + } + if (mLastDefaultKeyboardFocus == focus) + { + mLastDefaultKeyboardFocus = NULL; + } } diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index 14c711b5e..5f1466f5d 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -84,6 +84,7 @@ public: // Keyboard Focus void setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock = FALSE, BOOL keystrokes_only = FALSE); // new_focus = NULL to release the focus. + void restoreKeyboardFocus(LLFocusableElement* current_focus); LLFocusableElement* getKeyboardFocus() const { return mKeyboardFocus; } LLFocusableElement* getLastKeyboardFocus() const { return mLastKeyboardFocus; } BOOL childHasKeyboardFocus( const LLView* parent ) const; @@ -103,7 +104,8 @@ public: // If setKeyboardFocus(NULL) is called, and there is a non-NULL default // keyboard focus view, focus goes there. JC - void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mDefaultKeyboardFocus = default_focus; } + void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mLastDefaultKeyboardFocus = mDefaultKeyboardFocus; mDefaultKeyboardFocus = default_focus; } + void restoreDefaultKeyboardFocus(LLFocusableElement* current_default_focus); LLFocusableElement* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; } @@ -132,6 +134,7 @@ private: LLFocusableElement* mKeyboardFocus; // Keyboard events are preemptively routed to this object LLFocusableElement* mLastKeyboardFocus; // who last had focus LLFocusableElement* mDefaultKeyboardFocus; + LLFocusableElement* mLastDefaultKeyboardFocus; BOOL mKeystrokesOnly; // Top View diff --git a/indra/llui/llscrollcontainer.cpp b/indra/llui/llscrollcontainer.cpp index 8e740384a..1206d3b76 100644 --- a/indra/llui/llscrollcontainer.cpp +++ b/indra/llui/llscrollcontainer.cpp @@ -77,7 +77,8 @@ LLScrollableContainerView::LLScrollableContainerView( const std::string& name, mReserveScrollCorner( FALSE ), mMinAutoScrollRate( MIN_AUTO_SCROLL_RATE ), mMaxAutoScrollRate( MAX_AUTO_SCROLL_RATE ), - mScrolledView( scrolled_view ) + mScrolledView( scrolled_view ), + mPassBackToChildren(true) { if( mScrolledView ) { @@ -218,7 +219,7 @@ BOOL LLScrollableContainerView::handleScrollWheel( S32 x, S32 y, S32 clicks ) { // Give event to my child views - they may have scroll bars // (Bad UI design, but technically possible.) - if (LLUICtrl::handleScrollWheel(x,y,clicks)) + if (mPassBackToChildren && LLUICtrl::handleScrollWheel(x,y,clicks)) return TRUE; // When the vertical scrollbar is visible, scroll wheel diff --git a/indra/llui/llscrollcontainer.h b/indra/llui/llscrollcontainer.h index a5002a341..2e1cf1dd3 100644 --- a/indra/llui/llscrollcontainer.h +++ b/indra/llui/llscrollcontainer.h @@ -70,6 +70,7 @@ public: virtual void setValue(const LLSD& value) { mInnerRect.setValue(value); } void setBorderVisible( BOOL b ); + void setPassBackToChildren(bool b) { mPassBackToChildren = b; } void scrollToShowRect( const LLRect& rect, const LLRect& constraint); void scrollToShowRect( const LLRect& rect) { scrollToShowRect(rect, LLRect(0, mInnerRect.getHeight(), mInnerRect.getWidth(), 0)); } @@ -128,6 +129,7 @@ private: F32 mMinAutoScrollRate; F32 mMaxAutoScrollRate; bool mHideScrollbar; + bool mPassBackToChildren; }; diff --git a/indra/llui/lluictrl.cpp b/indra/llui/lluictrl.cpp index 58cb3e5fa..5e388e233 100644 --- a/indra/llui/lluictrl.cpp +++ b/indra/llui/lluictrl.cpp @@ -302,8 +302,8 @@ BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash) LLCtrlQuery query = getTabOrderQuery(); // sort things such that the default tab group is at the front query.setSorter(DefaultTabGroupFirstSorter::getInstance()); - child_list_t result = query(this); - if(result.size() > 0) + viewList_t result = query(this); + if(!result.empty()) { LLUICtrl * ctrl = static_cast(result.front()); if(!ctrl->hasFocus()) @@ -322,7 +322,7 @@ BOOL LLUICtrl::focusFirstItem(BOOL prefer_text_fields, BOOL focus_flash) { LLCtrlQuery query = getTabOrderQuery(); query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); - child_list_t result = query(this); + viewList_t result = query(this); if(result.size() > 0) { LLUICtrl * ctrl = static_cast(result.front()); @@ -358,7 +358,7 @@ BOOL LLUICtrl::focusLastItem(BOOL prefer_text_fields) { LLCtrlQuery query = getTabOrderQuery(); query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); - child_list_t result = query(this); + viewList_t result = query(this); if(result.size() > 0) { LLUICtrl * ctrl = static_cast(result.back()); @@ -372,7 +372,7 @@ BOOL LLUICtrl::focusLastItem(BOOL prefer_text_fields) } } // no text field found, or we don't care about text fields - child_list_t result = getTabOrderQuery().run(this); + viewList_t result = getTabOrderQuery().run(this); if(result.size() > 0) { LLUICtrl * ctrl = static_cast(result.back()); @@ -395,7 +395,7 @@ BOOL LLUICtrl::focusNextItem(BOOL text_fields_only) { query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); } - child_list_t result = query(this); + viewList_t result = query(this); return focusNext(result); } @@ -407,7 +407,7 @@ BOOL LLUICtrl::focusPrevItem(BOOL text_fields_only) { query.addPreFilter(LLUICtrl::LLTextInputFilter::getInstance()); } - child_list_t result = query(this); + viewList_t result = query(this); return focusPrev(result); } diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp index 07f99132b..6c1bce689 100644 --- a/indra/llui/llview.cpp +++ b/indra/llui/llview.cpp @@ -518,21 +518,21 @@ LLRect LLView::getRequiredRect() BOOL LLView::focusNextRoot() { - LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); + viewList_t result = LLView::getFocusRootsQuery().run(this); return LLView::focusNext(result); } BOOL LLView::focusPrevRoot() { - LLView::child_list_t result = LLView::getFocusRootsQuery().run(this); + viewList_t result = LLView::getFocusRootsQuery().run(this); return LLView::focusPrev(result); } // static -BOOL LLView::focusNext(LLView::child_list_t & result) +BOOL LLView::focusNext(viewList_t& result) { - LLView::child_list_iter_t focused = result.end(); - for(LLView::child_list_iter_t iter = result.begin(); + viewList_t::iterator focused = result.end(); + for(viewList_t::iterator iter = result.begin(); iter != result.end(); ++iter) { @@ -542,7 +542,7 @@ BOOL LLView::focusNext(LLView::child_list_t & result) break; } } - LLView::child_list_iter_t next = focused; + viewList_t::iterator next = focused; next = (next == result.end()) ? result.begin() : ++next; while(next != focused) { @@ -565,10 +565,10 @@ BOOL LLView::focusNext(LLView::child_list_t & result) } // static -BOOL LLView::focusPrev(LLView::child_list_t & result) +BOOL LLView::focusPrev(viewList_t& result) { - LLView::child_list_reverse_iter_t focused = result.rend(); - for(LLView::child_list_reverse_iter_t iter = result.rbegin(); + viewList_t::reverse_iterator focused = result.rend(); + for(viewList_t::reverse_iterator iter = result.rbegin(); iter != result.rend(); ++iter) { @@ -578,7 +578,7 @@ BOOL LLView::focusPrev(LLView::child_list_t & result) break; } } - LLView::child_list_reverse_iter_t next = focused; + viewList_t::reverse_iterator next = focused; next = (next == result.rend()) ? result.rbegin() : ++next; while(next != focused) { @@ -1170,16 +1170,13 @@ void LLView::drawChildren() LLView* rootp = getRootView(); ++sDepth; - for (child_list_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend();) // ++child_iter) + for (child_list_const_reverse_iter_t child_iter = mChildList.rbegin(); child_iter != mChildList.rend(); ++child_iter) { - child_list_reverse_iter_t child = child_iter++; - LLView *viewp = *child; - - if (viewp == NULL) - { - continue; - } - + LLView *viewp = *child_iter; + if (viewp == NULL) + { + continue; + } if (viewp->getVisible() && /*viewp != focus_view && */viewp->getRect().isValid()) { diff --git a/indra/llui/llview.h b/indra/llui/llview.h index 233e56bbc..2ec5ce58c 100644 --- a/indra/llui/llview.h +++ b/indra/llui/llview.h @@ -57,6 +57,7 @@ #include "llinitparam.h" #include "llfocusmgr.h" #include +#include "ailist.h" const U32 FOLLOWS_NONE = 0x00; const U32 FOLLOWS_LEFT = 0x01; @@ -231,7 +232,7 @@ public: SNAP_BOTTOM }; - typedef std::list child_list_t; + typedef AIList child_list_t; typedef child_list_t::iterator child_list_iter_t; typedef child_list_t::const_iterator child_list_const_iter_t; typedef child_list_t::reverse_iterator child_list_reverse_iter_t; @@ -582,9 +583,9 @@ public: static std::string escapeXML(const std::string& xml, std::string& indent); // focuses the item in the list after the currently-focused item, wrapping if necessary - static BOOL focusNext(LLView::child_list_t & result); + static BOOL focusNext(viewList_t& result); // focuses the item in the list before the currently-focused item, wrapping if necessary - static BOOL focusPrev(LLView::child_list_t & result); + static BOOL focusPrev(viewList_t& result); // returns query for iterating over controls in tab order static const LLCtrlQuery & getTabOrderQuery(); diff --git a/indra/llui/llviewquery.cpp b/indra/llui/llviewquery.cpp index 1c9ba6b8f..bb3bab353 100644 --- a/indra/llui/llviewquery.cpp +++ b/indra/llui/llviewquery.cpp @@ -74,9 +74,10 @@ filterResult_t LLCtrlFilter::operator() (const LLView* const view, const viewLis viewList_t LLViewQuery::run(LLView* view) const { viewList_t result; + viewList_t const child_list(view->getChildList()->begin(), view->getChildList()->end()); // prefilter gets immediate children of view - filterResult_t pre = runFilters(view, *view->getChildList(), mPreFilters); + filterResult_t pre = runFilters(view, child_list, mPreFilters); if(!pre.first && !pre.second) { // not including ourselves or the children @@ -113,26 +114,26 @@ viewList_t LLViewQuery::run(LLView* view) const void LLViewQuery::filterChildren(LLView * view, viewList_t & filtered_children) const { - LLView::child_list_t views(*(view->getChildList())); + viewList_t views(view->getChildList()->begin(), view->getChildList()->end()); if (mSorterp) { (*mSorterp)(view, views); // sort the children per the sorter } - for(LLView::child_list_iter_t iter = views.begin(); + for(viewList_t::iterator iter = views.begin(); iter != views.end(); - iter++) + ++iter) { viewList_t indiv_children = this->run(*iter); filtered_children.splice(filtered_children.end(), indiv_children); } } -filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children, const filterList_t filters) const +filterResult_t LLViewQuery::runFilters(LLView* view, viewList_t const& children, filterList_t const& filters) const { filterResult_t result = filterResult_t(TRUE, TRUE); for(filterList_const_iter_t iter = filters.begin(); iter != filters.end(); - iter++) + ++iter) { filterResult_t filtered = (**iter)(view, children); result.first = result.first && filtered.first; @@ -143,7 +144,7 @@ filterResult_t LLViewQuery::runFilters(LLView * view, const viewList_t children, class SortByTabOrder : public LLQuerySorter, public LLSingleton { - /*virtual*/ void operator() (LLView * parent, LLView::child_list_t &children) const + /*virtual*/ void operator() (LLView* parent, viewList_t& children) const { children.sort(LLCompareByTabOrder(parent->getCtrlOrder())); } diff --git a/indra/llui/llviewquery.h b/indra/llui/llviewquery.h index 98d9bf879..e058985cc 100644 --- a/indra/llui/llviewquery.h +++ b/indra/llui/llviewquery.h @@ -126,7 +126,7 @@ public: private: - filterResult_t runFilters(LLView * view, const viewList_t children, const filterList_t filters) const; + filterResult_t runFilters(LLView* view, viewList_t const& children, filterList_t const& filters) const; filterList_t mPreFilters; filterList_t mPostFilters; diff --git a/indra/llxml/llcontrol.h b/indra/llxml/llcontrol.h index 18861cb23..2816918a8 100644 --- a/indra/llxml/llcontrol.h +++ b/indra/llxml/llcontrol.h @@ -99,8 +99,10 @@ typedef enum e_control_type class LLControlVariable : public LLRefCount { - friend class LLControlGroup; + LOG_CLASS(LLControlVariable); + friend class LLControlGroup; + public: typedef boost::signals2::signal validate_signal_t; typedef boost::signals2::signal commit_signal_t; @@ -208,6 +210,7 @@ T convert_from_llsd(const LLSD& sd, eControlType type, const std::string& contro //const U32 STRING_CACHE_SIZE = 10000; class LLControlGroup : public LLInstanceTracker { + LOG_CLASS(LLControlGroup); protected: typedef std::map ctrl_name_table_t; ctrl_name_table_t mNameTable; @@ -283,6 +286,7 @@ public: else { llwarns << "Control " << name << " not found." << llendl; + return T(); } return convert_from_llsd(value, type, name); } @@ -313,7 +317,7 @@ public: } else { - llerrs << "Invalid control " << name << llendl; + llwarns << "Invalid control " << name << llendl; } } diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 596081313..61e279c01 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -994,7 +994,7 @@ This should be as low as possible, but too low may break functionality Type Boolean Value - 0 + 1 TurnAroundWhenWalkingBackwards @@ -8826,7 +8826,7 @@ This should be as low as possible, but too low may break functionality LastSnapshotType Comment - Select this as next type of snapshot to take (0 = postcard, 1 = texture, 2 = local image) + Select this as next type of snapshot to take (0 = feed, 1 = postcard, 2 = texture, 3 = local image) Persist 1 Type @@ -14290,6 +14290,50 @@ This should be as low as possible, but too low may break functionality Value 0 + SnapshotFeedKeepAspect + + Comment + When adjusting feed resolution keep its aspect ratio constant and equal to the target aspect. + Persist + 1 + Type + Boolean + Value + 0 + + SnapshotPostcardKeepAspect + + Comment + When adjusting postcard resolution keep its aspect ratio constant and equal to the target aspect. + Persist + 1 + Type + Boolean + Value + 0 + + SnapshotTextureKeepAspect + + Comment + When adjusting texture resolution keep its aspect ratio constant and equal to the target aspect. + Persist + 1 + Type + Boolean + Value + 0 + + SnapshotLocalKeepAspect + + Comment + When adjusting local resolution keep its aspect ratio constant and equal to the target aspect. + Persist + 1 + Type + Boolean + Value + 0 + SnapshotOpenFreezeTime Comment diff --git a/indra/newview/app_settings/settings_ascent.xml b/indra/newview/app_settings/settings_ascent.xml index 5a77d0f50..dd8d4e606 100644 --- a/indra/newview/app_settings/settings_ascent.xml +++ b/indra/newview/app_settings/settings_ascent.xml @@ -268,7 +268,7 @@ Value 1 - AscentUseTag + AscentBroadcastTag Comment Broadcast client tag diff --git a/indra/newview/app_settings/settings_rlv.xml b/indra/newview/app_settings/settings_rlv.xml index bb385a033..7dd83af41 100644 --- a/indra/newview/app_settings/settings_rlv.xml +++ b/indra/newview/app_settings/settings_rlv.xml @@ -209,7 +209,7 @@ Type Boolean Value - 1 + 0 RLVaWearReplaceUnlocked diff --git a/indra/newview/app_settings/shaders/class1/objects/previewF.glsl b/indra/newview/app_settings/shaders/class1/objects/previewF.glsl new file mode 100644 index 000000000..284da3d0a --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/objects/previewF.glsl @@ -0,0 +1,41 @@ +/** + * @file previewF.glsl + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +VARYING vec4 vertex_color; +VARYING vec2 vary_texcoord0; + +void main() +{ + vec4 color = texture2D(diffuseMap,vary_texcoord0.xy) * vertex_color; + frag_color = color; +} diff --git a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl index 5dcfa8706..7f3f84398 100644 --- a/indra/newview/app_settings/shaders/class1/objects/previewV.glsl +++ b/indra/newview/app_settings/shaders/class1/objects/previewV.glsl @@ -32,12 +32,51 @@ ATTRIBUTE vec3 position; ATTRIBUTE vec3 normal; ATTRIBUTE vec2 texcoord0; +uniform vec4 color; + VARYING vec4 vertex_color; VARYING vec2 vary_texcoord0; +uniform vec4 light_position[8]; +uniform vec3 light_direction[8]; +uniform vec3 light_attenuation[8]; +uniform vec3 light_diffuse[8]; + +//=================================================================================================== +//declare these here explicitly to separate them from atmospheric lighting elsewhere to work around +//drivers that are picky about functions being declared but not defined even if they aren't called +float calcDirectionalLight(vec3 n, vec3 l) +{ + float a = max(dot(n,l),0.0); + return a; +} + + +float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight) +{ + //get light vector + vec3 lv = lp.xyz-v; + + //get distance + float d = length(lv); + + //normalize light vector + lv *= 1.0/d; + + //distance attenuation + float da = clamp(1.0/(la * d), 0.0, 1.0); + + // spotlight coefficient. + float spot = max(dot(-ln, lv), is_pointlight); + da *= spot*spot; // GL_SPOT_EXPONENT=2 + + //angular attenuation + da *= calcDirectionalLight(n, lv); + + return da; +} +//==================================================================================================== -vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol); -void calcAtmospherics(vec3 inPositionEye); void main() { @@ -45,13 +84,15 @@ void main() vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0)); gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; - + vec3 norm = normalize(normal_matrix * normal); - calcAtmospherics(pos.xyz); + vec4 col = vec4(0,0,0,1); - vec4 color = calcLighting(pos.xyz, norm, vec4(1,1,1,1), vec4(0.)); - vertex_color = color; - - + // Collect normal lights (need to be divided by two, as we later multiply by 2) + col.rgb += light_diffuse[1].rgb * calcDirectionalLight(norm, light_position[1].xyz); + col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].z); + col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].z); + + vertex_color = col*color; } diff --git a/indra/newview/ascentprefsvan.cpp b/indra/newview/ascentprefsvan.cpp index 2d9b32144..449745d5a 100644 --- a/indra/newview/ascentprefsvan.cpp +++ b/indra/newview/ascentprefsvan.cpp @@ -193,7 +193,7 @@ void LLPrefsAscentVan::refreshValues() mAnnounceStreamMetadata = gSavedSettings.getBOOL("AnnounceStreamMetadata"); //Tags\Colors ---------------------------------------------------------------------------- - mAscentUseTag = gSavedSettings.getBOOL("AscentUseTag"); + mAscentBroadcastTag = gSavedSettings.getBOOL("AscentBroadcastTag"); mReportClientUUID = gSavedSettings.getString("AscentReportClientUUID"); mSelectedClient = gSavedSettings.getU32("AscentReportClientIndex"); mShowSelfClientTag = gSavedSettings.getBOOL("AscentShowSelfTag"); @@ -276,7 +276,7 @@ void LLPrefsAscentVan::cancel() gSavedSettings.setBOOL("AnnounceStreamMetadata", mAnnounceStreamMetadata); //Tags\Colors ---------------------------------------------------------------------------- - gSavedSettings.setBOOL("AscentUseTag", mAscentUseTag); + gSavedSettings.setBOOL("AscentBroadcastTag", mAscentBroadcastTag); gSavedSettings.setString("AscentReportClientUUID", mReportClientUUID); gSavedSettings.setU32("AscentReportClientIndex", mSelectedClient); gSavedSettings.setBOOL("AscentShowSelfTag", mShowSelfClientTag); diff --git a/indra/newview/ascentprefsvan.h b/indra/newview/ascentprefsvan.h index 62600a264..4439205cc 100644 --- a/indra/newview/ascentprefsvan.h +++ b/indra/newview/ascentprefsvan.h @@ -63,7 +63,7 @@ protected: bool mAnnounceSnapshots; bool mAnnounceStreamMetadata; //Tags\Colors - BOOL mAscentUseTag; + BOOL mAscentBroadcastTag; std::string mReportClientUUID; U32 mSelectedClient; BOOL mShowSelfClientTag; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index ff167bb9c..cf0d063eb 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -689,9 +689,6 @@ bool LLAppViewer::init() ////////////////////////////////////////////////////////////////////////////// // *FIX: The following code isn't grouped into functions yet. - // Statistics / debug timer initialization - init_statistics(); - // // Various introspection concerning the libs we're using - particularly // the libs involved in getting to a full login screen. @@ -3967,7 +3964,7 @@ void LLAppViewer::idle() idle_afk_check(); // Update statistics for this frame - update_statistics(gFrameCount); + update_statistics(); } //////////////////////////////////////// diff --git a/indra/newview/llcontainerview.cpp b/indra/newview/llcontainerview.cpp index be7be72c7..e6d9b0119 100644 --- a/indra/newview/llcontainerview.cpp +++ b/indra/newview/llcontainerview.cpp @@ -278,3 +278,10 @@ void LLContainerView::setDisplayChildren(const BOOL displayChildren) childp->setVisible(mDisplayChildren); } } + +void LLContainerView::setScrollContainer(LLScrollableContainerView* scroll) +{ + mScrollContainer = scroll; + scroll->setPassBackToChildren(false); +} + diff --git a/indra/newview/llcontainerview.h b/indra/newview/llcontainerview.h index 37c2d97f3..1b337b09b 100644 --- a/indra/newview/llcontainerview.h +++ b/indra/newview/llcontainerview.h @@ -61,7 +61,7 @@ public: void showLabel(BOOL show) { mShowLabel = show; } void setDisplayChildren(const BOOL displayChildren); BOOL getDisplayChildren() { return mDisplayChildren; } - void setScrollContainer(LLScrollableContainerView* scroll) {mScrollContainer = scroll;} + void setScrollContainer(LLScrollableContainerView* scroll); private: LLScrollableContainerView* mScrollContainer; diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index afe3040c4..ea1450207 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -557,6 +557,12 @@ F32 LLDrawable::updateXform(BOOL undamped) mVObjp->dirtySpatialGroup(); } } + else if (!isRoot() && ( + dist_vec_squared(old_pos, target_pos) > 0.f + || old_rot != target_rot )) + { //fix for BUG-860, MAINT-2275, MAINT-1742, MAINT-2247 + gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE); + } else if (!getVOVolume() && !isAvatar()) { movePartition(); diff --git a/indra/newview/llfloateravatarlist.cpp b/indra/newview/llfloateravatarlist.cpp index 81d21ae70..39c82ab77 100644 --- a/indra/newview/llfloateravatarlist.cpp +++ b/indra/newview/llfloateravatarlist.cpp @@ -500,18 +500,9 @@ void LLFloaterAvatarList::assessColumns() if(!client_hidden) { - name_col->setWidth(width_name); + name_col->setWidth(llmax(width_name.get(),10)); } } - else if (!hide_client) - { - mAvatarList->getColumn(LIST_CLIENT)->setWidth(0); - mAvatarList->getColumn(LIST_AVATAR_NAME)->setWidth(0); - mAvatarList->getColumn(LIST_AVATAR_NAME)->mDynamicWidth = FALSE; - mAvatarList->getColumn(LIST_AVATAR_NAME)->mRelWidth = 0; - mAvatarList->getColumn(LIST_CLIENT)->mDynamicWidth = TRUE; - mAvatarList->getColumn(LIST_CLIENT)->mRelWidth = -1; - } mAvatarList->updateLayout(); } diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index 0bde0cfee..56bd7ed1f 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -58,26 +58,36 @@ #include "hippogridmanager.h" -LLFloaterBuyContents* LLFloaterBuyContents::sInstance = NULL; - LLFloaterBuyContents::LLFloaterBuyContents() : LLFloater(std::string("floater_buy_contents"), std::string("FloaterBuyContentsRect"), LLStringUtil::null) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_buy_contents.xml"); +} - childSetAction("cancel_btn", onClickCancel, this); - childSetAction("buy_btn", onClickBuy, this); +BOOL LLFloaterBuyContents::postBuild() +{ - childDisable("item_list"); - childDisable("buy_btn"); - childDisable("wear_check"); + getChild("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyContents::onClickCancel, this)); + getChild("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyContents::onClickBuy, this)); + + getChildView("item_list")->setEnabled(FALSE); + getChildView("buy_btn")->setEnabled(FALSE); + getChildView("wear_check")->setEnabled(FALSE); setDefaultBtn("cancel_btn"); // to avoid accidental buy (SL-43130) + + // Always center the dialog. User can change the size, + // but purchases are important and should be center screen. + // This also avoids problems where the user resizes the application window + // mid-session and the saved rect is off-center. + center(); + + return TRUE; } LLFloaterBuyContents::~LLFloaterBuyContents() { - sInstance = NULL; + removeVOInventoryListener(); } @@ -92,26 +102,20 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) return; } - // Create a new instance only if needed - if (sInstance) - { - LLScrollListCtrl* list = sInstance->getChild("item_list"); - if (list) list->deleteAllItems(); - } - else - { - sInstance = new LLFloaterBuyContents(); - } + LLFloaterBuyContents* floater = getInstance(); + LLScrollListCtrl* list = floater->getChild("item_list"); + if (list) + list->deleteAllItems(); - sInstance->open(); /*Flawfinder: ignore*/ - sInstance->setFocus(TRUE); - sInstance->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + floater->open(); /*Flawfinder: ignore*/ + floater->setFocus(TRUE); // Always center the dialog. User can change the size, // but purchases are important and should be center screen. // This also avoids problems where the user resizes the application window // mid-session and the saved rect is off-center. - sInstance->center(); + floater->center(); LLUUID owner_id; std::string owner_name; @@ -122,7 +126,7 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) return; } - sInstance->mSaleInfo = sale_info; + floater->mSaleInfo = sale_info; // Update the display LLSelectNode* node = selection->getFirstRootNode(); @@ -132,17 +136,17 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) gCacheName->getGroupName(owner_id, owner_name); } - sInstance->childSetTextArg("contains_text", "[NAME]", node->mName); - sInstance->childSetTextArg("buy_text", "[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); - sInstance->childSetTextArg("buy_text", "[AMOUNT]", llformat("%d", sale_info.getSalePrice())); - sInstance->childSetTextArg("buy_text", "[NAME]", owner_name); + floater->getChild("contains_text")->setTextArg("[NAME]", node->mName); + floater->getChild("buy_text")->setTextArg("[CURRENCY]", gHippoGridManager->getConnectedGrid()->getCurrencySymbol()); + floater->getChild("buy_text")->setTextArg("[AMOUNT]", llformat("%d", sale_info.getSalePrice())); + floater->getChild("buy_text")->setTextArg("[NAME]", owner_name); // Must do this after the floater is created, because // sometimes the inventory is already there and // the callback is called immediately. LLViewerObject* obj = selection->getFirstRootObject(); - sInstance->registerVOInventoryListener(obj,NULL); - sInstance->requestVOInventory(); + floater->registerVOInventoryListener(obj,NULL); + floater->requestVOInventory(); } @@ -157,23 +161,26 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj, return; } - if (!inv) - { - llwarns << "No inventory in LLFloaterBuyContents::inventoryChanged" - << llendl; - removeVOInventoryListener(); - return; - } - - LLCtrlListInterface *item_list = childGetListInterface("item_list"); + LLScrollListCtrl* item_list = getChild("item_list"); if (!item_list) { removeVOInventoryListener(); return; } + item_list->deleteAllItems(); + + if (!inv) + { + llwarns << "No inventory in LLFloaterBuyContents::inventoryChanged" + << llendl; + + return; + } + // default to turning off the buy button. - childDisable("buy_btn"); + LLView* buy_btn = getChildView("buy_btn"); + buy_btn->setEnabled(FALSE); LLUUID owner_id; BOOL is_group_owned; @@ -214,13 +221,15 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj, // There will be at least one item shown in the display, so go // ahead and enable the buy button. - childEnable("buy_btn"); + buy_btn->setEnabled(TRUE); // Create the line in the list LLSD row; BOOL item_is_multi = FALSE; - if ( inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED ) + if ((inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_LANDMARK_VISITED + || inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS) + && !(inv_item->getFlags() & LLInventoryItemFlags::II_FLAGS_WEARABLES_MASK)) { item_is_multi = TRUE; } @@ -260,28 +269,25 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj, if (wearable_count > 0) { - childEnable("wear_check"); - childSetValue("wear_check", LLSD(false) ); + getChildView("wear_check")->setEnabled(TRUE); + getChild("wear_check")->setValue(LLSD(false) ); } - - removeVOInventoryListener(); } -// static -void LLFloaterBuyContents::onClickBuy(void*) +void LLFloaterBuyContents::onClickBuy() { // Make sure this wasn't selected through other mechanisms // (ie, being the default button and pressing enter. - if(!sInstance->childIsEnabled("buy_btn")) + if(!getChildView("buy_btn")->getEnabled()) { // We shouldn't be enabled. Just close. - sInstance->close(); + close(); return; } // We may want to wear this item - if (sInstance->childGetValue("wear_check")) + if (getChild("wear_check")->getValue()) { LLInventoryState::sWearNewClothing = TRUE; } @@ -293,14 +299,14 @@ void LLFloaterBuyContents::onClickBuy(void*) // *NOTE: doesn't work for multiple object buy, which UI does not // currently support sale info is used for verification only, if // it doesn't match region info then sale is canceled. - LLSelectMgr::getInstance()->sendBuy(gAgent.getID(), category_id, sInstance->mSaleInfo); + LLSelectMgr::getInstance()->sendBuy(gAgent.getID(), category_id, mSaleInfo); - sInstance->close(); + close(); } // static -void LLFloaterBuyContents::onClickCancel(void*) +void LLFloaterBuyContents::onClickCancel() { - sInstance->close(); + close(); } diff --git a/indra/newview/llfloaterbuycontents.h b/indra/newview/llfloaterbuycontents.h index 63e62ea83..d30adcb06 100644 --- a/indra/newview/llfloaterbuycontents.h +++ b/indra/newview/llfloaterbuycontents.h @@ -47,27 +47,26 @@ class LLViewerObject; class LLObjectSelection; class LLFloaterBuyContents -: public LLFloater, public LLVOInventoryListener +: public LLFloater, public LLVOInventoryListener, public LLSingleton { public: static void show(const LLSaleInfo& sale_info); -protected: LLFloaterBuyContents(); ~LLFloaterBuyContents(); - + /*virtual*/ BOOL postBuild(); + +protected: void requestObjectInventories(); /*virtual*/ void inventoryChanged(LLViewerObject* obj, LLInventoryObject::object_list_t* inv, S32 serial_num, void* data); - - static void onClickBuy(void*); - static void onClickCancel(void*); + + void onClickBuy(); + void onClickCancel(); protected: - static LLFloaterBuyContents* sInstance; - LLSafeHandle mObjectSelection; LLSaleInfo mSaleInfo; }; diff --git a/indra/newview/llfloatereditui.cpp b/indra/newview/llfloatereditui.cpp index ff67a2069..fbef26b18 100644 --- a/indra/newview/llfloatereditui.cpp +++ b/indra/newview/llfloatereditui.cpp @@ -56,9 +56,9 @@ void LLFloaterEditUI::navigateHierarchyButtonPressed(void* data) const LLView::child_list_t* viewChildren = view->getChildList(); const LLView::child_list_t* parentChildren = parent->getChildList(); //LLView::child_list_t::iterator - std::list::const_iterator itor; - std::list::size_type idx; - std::list::size_type sidx; + LLView::child_list_t::const_iterator itor; + LLView::child_list_t::size_type idx; + LLView::child_list_t::size_type sidx; for(idx = 0,itor = parentChildren->begin();itor!=parentChildren->end();itor++,idx++){ if((*itor)==view)break; } diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 013c9aa49..72e46f09c 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -973,11 +973,13 @@ BOOL LLImagePreviewSculpted::render() { gObjectPreviewProgram.bind(); } + gPipeline.enableLightsPreview(); + gGL.pushMatrix(); const F32 SCALE = 1.25f; gGL.scalef(SCALE, SCALE, SCALE); const F32 BRIGHTNESS = 0.9f; - gGL.color3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); + gGL.diffuseColor3f(BRIGHTNESS, BRIGHTNESS, BRIGHTNESS); mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0); mVertexBuffer->draw(LLRender::TRIANGLES, num_indices, 0); diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index e5811671e..19e1b3e2c 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -106,7 +106,8 @@ BOOL LLFloaterJoystick::postBuild() for (U32 i = 0; i < 6; i++) { axis.setArg("[NUM]", llformat("%d", i)); - mAxisStats[i] = new LLStat(4); + std::string stat_name(llformat("Joystick axis %d", i)); + mAxisStats[i] = new LLStat(stat_name,4); mAxisStatsBar[i] = mAxisStatsView->addStat(axis, mAxisStats[i]); mAxisStatsBar[i]->mMinBar = -range; mAxisStatsBar[i]->mMaxBar = range; diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp index 8ca18f6b0..8ff747187 100644 --- a/indra/newview/llfloatermodelpreview.cpp +++ b/indra/newview/llfloatermodelpreview.cpp @@ -1641,7 +1641,6 @@ bool LLModelLoader::doLoadModel() //If no skeleton, do a breadth-first search to get at specific joints bool rootNode = false; - bool skeletonWithNoRootNode = false; //Need to test for a skeleton that does not have a root node //This occurs when your instance controller does not have an associated scene @@ -1652,10 +1651,6 @@ bool LLModelLoader::doLoadModel() { rootNode = true; } - else - { - skeletonWithNoRootNode = true; - } } if (!pSkeleton || !rootNode) @@ -5034,6 +5029,11 @@ BOOL LLModelPreview::render() refresh(); } + if (use_shaders) + { + gObjectPreviewProgram.bind(); + } + gGL.loadIdentity(); gPipeline.enableLightsPreview(); @@ -5043,8 +5043,9 @@ BOOL LLModelPreview::render() LLQuaternion av_rot = camera_rot; LLViewerCamera::getInstance()->setOriginAndLookAt( target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + offset) * av_rot), // camera - LLVector3::z_axis, // up - target_pos); // point of interest + LLVector3::z_axis, // up + target_pos); // point of interest + z_near = llclamp(z_far * 0.001f, 0.001f, 0.1f); @@ -5058,11 +5059,6 @@ BOOL LLModelPreview::render() const U32 type_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_TEXCOORD0; - if (use_shaders) - { - gObjectPreviewProgram.bind(); - } - LLGLEnable normalize(GL_NORMALIZE); if (!mBaseModel.empty() && mVertexBuffer[5].empty()) @@ -5248,10 +5244,10 @@ BOOL LLModelPreview::render() if (i + 1 >= hull_colors.size()) { - hull_colors.push_back(LLColor4U(rand()%128 + 127, rand()%128 + 127, rand()%128 + 127, 128)); + hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 128)); } - glColor4ubv(hull_colors[i].mV); + gGL.diffuseColor4ubv(hull_colors[i].mV); LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals); if (explode > 0.f) diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 735b033b1..1ef53b269 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -91,8 +91,8 @@ ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- -S32 LLFloaterSnapshot::sUIWinHeightLong = 619 ; -S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 260 ; +S32 LLFloaterSnapshot::sUIWinHeightLong = 625 ; +S32 LLFloaterSnapshot::sUIWinHeightShort = LLFloaterSnapshot::sUIWinHeightLong - 266 ; S32 LLFloaterSnapshot::sUIWinWidth = 219 ; S32 const THUMBHEIGHT = 159; @@ -111,6 +111,8 @@ S32 BORDER_WIDTH = 6; const S32 MAX_POSTCARD_DATASIZE = 1024 * 1024; // one megabyte const S32 MAX_TEXTURE_SIZE = 512 ; //max upload texture size 512 * 512 +static std::string snapshotKeepAspectName(); + ///---------------------------------------------------------------------------- /// Class LLSnapshotLivePreview ///---------------------------------------------------------------------------- @@ -172,6 +174,7 @@ public: BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;} bool getShowFreezeFrameSnapshot() const { return mShowFreezeFrameSnapshot; } LLViewerTexture* getCurrentImage(); + char const* resolutionComboName() const; char const* aspectComboName() const; void setSnapshotType(ESnapshotType type) { mSnapshotType = type; } @@ -305,6 +308,7 @@ public: static void onClickUICheck(LLUICtrl *ctrl, void* data); static void onClickHUDCheck(LLUICtrl *ctrl, void* data); static void onClickKeepOpenCheck(LLUICtrl *ctrl, void* data); + static void onClickKeepAspect(LLUICtrl* ctrl, void* data); static void onCommitQuality(LLUICtrl* ctrl, void* data); static void onCommitFeedResolution(LLUICtrl* ctrl, void* data); static void onCommitPostcardResolution(LLUICtrl* ctrl, void* data); @@ -327,10 +331,14 @@ public: static LLSnapshotLivePreview* getPreviewView(void); static void setResolution(LLFloaterSnapshot* floater, const std::string& comboname, bool visible, bool update_controls = true); static void setAspect(LLFloaterSnapshot* floater, const std::string& comboname, bool update_controls = true); + static void storeAspectSetting(LLComboBox* combo, const std::string& comboname); + static void enforceAspect(LLFloaterSnapshot* floater, F32 new_aspect); + static void enforceResolution(LLFloaterSnapshot* floater, F32 new_aspect); static void updateControls(LLFloaterSnapshot* floater, bool delayed_formatted = false); static void resetFeedAndPostcardAspect(LLFloaterSnapshot* floater); static void updateLayout(LLFloaterSnapshot* floater); static void freezeTime(bool on); + static void keepAspect(LLFloaterSnapshot* view, bool on, bool force = false); static LLHandle sPreviewHandle; @@ -345,7 +353,6 @@ public: LLToolset* mLastToolset; boost::signals2::connection mQualityMouseUpConnection; - LLFocusableElement* mPrevDefaultKeyboardFocus; }; //---------------------------------------------------------------------------- @@ -404,7 +411,7 @@ LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) : mNeedsFlash(TRUE), mSnapshotQuality(gSavedSettings.getS32("SnapshotQuality")), mFormattedDataSize(0), - mSnapshotType(SNAPSHOT_FEED), + mSnapshotType((ESnapshotType)gSavedSettings.getS32("LastSnapshotType")), mSnapshotFormat(LLFloaterSnapshot::ESnapshotFormat(gSavedSettings.getS32("SnapshotFormat"))), mShowFreezeFrameSnapshot(FALSE), mCameraPos(LLViewerCamera::getInstance()->getOrigin()), @@ -1716,14 +1723,12 @@ void LLFloaterSnapshot::Impl::freezeTime(bool on) } // Make sure the floater keeps focus so that pressing ESC stops Freeze Time mode. - sInstance->impl.mPrevDefaultKeyboardFocus = gFocusMgr.getDefaultKeyboardFocus(); gFocusMgr.setDefaultKeyboardFocus(sInstance); } else if (gSavedSettings.getBOOL("FreezeTime")) // turning off freeze frame mode { // Restore default keyboard focus. - gFocusMgr.setDefaultKeyboardFocus(sInstance->impl.mPrevDefaultKeyboardFocus); - sInstance->impl.mPrevDefaultKeyboardFocus = NULL; + gFocusMgr.restoreDefaultKeyboardFocus(sInstance); gSnapshotFloaterView->setMouseOpaque(FALSE); @@ -1803,7 +1808,6 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de LLSnapshotLivePreview* previewp = getPreviewView(); if (previewp) { - previewp->setSnapshotType(shot_type); LLViewerWindow::ESnapshotType layer_type = (shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL) ? (LLViewerWindow::ESnapshotType)gSavedSettings.getS32("SnapshotLayerType") : @@ -1844,6 +1848,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de floater->childSetVisible("more_btn", !is_advance); // the only item hidden in advanced mode floater->childSetVisible("less_btn", is_advance); floater->childSetVisible("type_label2", is_advance); + floater->childSetVisible("keep_aspect", is_advance); floater->childSetVisible("type_label3", is_advance); floater->childSetVisible("format_label", is_advance && is_local); floater->childSetVisible("local_format_combo", is_local); @@ -1899,6 +1904,8 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater, bool de shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD && got_bytes && previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLColor4::red : gColors.getColor( "LabelTextColor" )); + std::string target_size_str = gSavedSettings.getBOOL(snapshotKeepAspectName()) ? floater->getString("sourceAR") : floater->getString("targetAR"); + floater->childSetValue("type_label3", target_size_str); bool up_to_date = previewp && previewp->getSnapshotUpToDate(); bool can_upload = up_to_date && !previewp->isUsedBy(shot_type); @@ -1987,6 +1994,11 @@ void LLFloaterSnapshot::Impl::onCommitFeedAspect(LLUICtrl* ctrl, void* data) previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_FEED); } updateAspect(ctrl, data); + LLFloaterSnapshot* floater = (LLFloaterSnapshot*)data; + if (floater && previewp && gSavedSettings.getBOOL(snapshotKeepAspectName())) + { + enforceResolution(floater, previewp->getAspect()); + } } // static @@ -2000,6 +2012,11 @@ void LLFloaterSnapshot::Impl::onCommitPostcardAspect(LLUICtrl* ctrl, void* data) previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_POSTCARD); } updateAspect(ctrl, data); + LLFloaterSnapshot* floater = (LLFloaterSnapshot*)data; + if (floater && previewp && gSavedSettings.getBOOL(snapshotKeepAspectName())) + { + enforceResolution(floater, previewp->getAspect()); + } } // static @@ -2026,6 +2043,11 @@ void LLFloaterSnapshot::Impl::onCommitLocalAspect(LLUICtrl* ctrl, void* data) previewp->addManualOverride(LLSnapshotLivePreview::SNAPSHOT_LOCAL); } updateAspect(ctrl, data); + LLFloaterSnapshot* floater = (LLFloaterSnapshot*)data; + if (floater && previewp && gSavedSettings.getBOOL(snapshotKeepAspectName())) + { + enforceResolution(floater, previewp->getAspect()); + } } // static @@ -2252,6 +2274,18 @@ void LLFloaterSnapshot::Impl::onClickKeepOpenCheck(LLUICtrl* ctrl, void* data) gSavedSettings.setBOOL( "CloseSnapshotOnKeep", !check->get() ); } +// static +void LLFloaterSnapshot::Impl::onClickKeepAspect(LLUICtrl* ctrl, void* data) +{ + LLFloaterSnapshot* view = (LLFloaterSnapshot*)data; + if (view) + { + LLCheckBoxCtrl* check = (LLCheckBoxCtrl*)ctrl; + keepAspect(view, check->get()); + updateControls(view); + } +} + // static void LLFloaterSnapshot::Impl::onCommitQuality(LLUICtrl* ctrl, void* data) { @@ -2321,6 +2355,46 @@ static std::string lastSnapshotAspectName() } } +static std::string snapshotKeepAspectName() +{ + switch(gSavedSettings.getS32("LastSnapshotType")) + { + case LLSnapshotLivePreview::SNAPSHOT_FEED: return "SnapshotFeedKeepAspect"; + case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: return "SnapshotPostcardKeepAspect"; + case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: return "SnapshotTextureKeepAspect"; + default: return "SnapshotLocalKeepAspect"; + } +} + +// static +void LLFloaterSnapshot::Impl::keepAspect(LLFloaterSnapshot* view, bool on, bool force) +{ + DoutEntering(dc::snapshot, "LLFloaterSnapshot::Impl::keepAspect(view, " << on << ", " << force << ")"); + bool cur_on = gSavedSettings.getBOOL(snapshotKeepAspectName()); + if ((!force && cur_on == on) || + gSavedSettings.getBOOL("RenderUIInSnapshot") || + gSavedSettings.getBOOL("RenderHUDInSnapshot")) + { + // No change. + return; + } + view->childSetValue("keep_aspect", on); + gSavedSettings.setBOOL(snapshotKeepAspectName(), on); + if (on) + { + LLSnapshotLivePreview* previewp = getPreviewView(); + if (previewp) + { + S32 w = llround(view->childGetValue("snapshot_width").asReal(), 1.0); + S32 h = llround(view->childGetValue("snapshot_height").asReal(), 1.0); + gSavedSettings.setS32(lastSnapshotWidthName(), w); + gSavedSettings.setS32(lastSnapshotHeightName(), h); + comboSetCustom(view, previewp->resolutionComboName()); + enforceAspect(view, (F32)w / h); + } + } +} + // static void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool update_controls) { @@ -2332,192 +2406,12 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool return; } - S32 new_width = 0; - S32 new_height = 0; - F32 new_aspect = 0; LLSnapshotLivePreview* previewp = getPreviewView(); -#if 0 // Broken -- not doing this for now. - LLSnapshotLivePreview::ESnapshotType shot_type = (LLSnapshotLivePreview::ESnapshotType)gSavedSettings.getS32("LastSnapshotType"); - // Is the snapshot was already used (saved or uploaded) and no manual changes - // have been made since to the current destination type, and the raw snapshot - // is still up to date with regard to visibility of UI, HUD and BufferType etc? - if (previewp && previewp->isUsed() && !previewp->isOverriddenBy(shot_type) && previewp->getRawSnapshotUpToDate()) - { - previewp->getSize(new_width, new_height); - new_aspect = previewp->getAspect(); - S32 const old_width = new_width; - S32 const old_height = new_height; - F32 const old_aspect = new_aspect; - S32 raw_width; - S32 raw_height; - previewp->getRawSize(raw_width, raw_height); - F32 const raw_aspect = (F32)raw_width / raw_height; - bool fixed_crop = false; - bool fixed_size = false; - bool fixed_scale = false; - bool done = false; - bool fail = false; - while (!done) - { - // Attempt to change the size and aspect so the raw snapshot can also be used for this new destination. - S32 w, h, crop_offset; - bool crop_vertically; - previewp->setSize(new_width, new_height); - previewp->setAspect(new_aspect); - LLSnapshotLivePreview::EAspectSizeProblem ret = previewp->getAspectSizeProblem(w, h, crop_vertically, crop_offset); - switch(ret) - { - case LLSnapshotLivePreview::ASPECTSIZE_OK: - done = true; // Don't change anything (else) if the current settings are usable. - break; - case LLSnapshotLivePreview::CANNOT_CROP_HORIZONTALLY: - case LLSnapshotLivePreview::CANNOT_CROP_VERTICALLY: - if (fixed_crop) - { - done = fail = true; - } - else - { - // Set target aspect to aspect of the raw snapshot we have (no reason to crop anything). - new_aspect = raw_aspect; - fixed_crop = true; - } - break; - case LLSnapshotLivePreview::SIZE_TOO_LARGE: - if (fixed_size) - { - done = fail = true; - } - else - { - if (new_width > w) - { - new_width = w; - new_height = llround(new_width / new_aspect); - } - if (new_height > h) - { - new_width = llmin(w, llround(h * new_aspect)); - new_height = llmin(h, llround(new_width / new_aspect)); - } - fixed_size = true; - } - break; - case LLSnapshotLivePreview::CANNOT_RESIZE: - if (fixed_scale) - { - done = fail = true; - } - else - { - F32 ratio = llmin((F32)w / new_width, (F32)h / new_height); - new_width = llround(new_width * ratio); - new_height = llround(new_height * ratio); - fixed_scale = true; - } - break; - } - } - previewp->setAspect(old_aspect); - previewp->setSize(old_width, old_height); - if (fail) - { - new_aspect = 0; - new_width = new_height = 0; - } - else - { - LLComboBox* size_combo_box = NULL; - LLComboBox* aspect_combo_box = NULL; - switch(shot_type) - { - case LLSnapshotLivePreview::SNAPSHOT_FEED: - size_combo_box = view->getChild("feed_size_combo"); - aspect_combo_box = view->getChild("feed_aspect_combo"); - break; - case LLSnapshotLivePreview::SNAPSHOT_POSTCARD: - size_combo_box = view->getChild("postcard_size_combo"); - aspect_combo_box = view->getChild("postcard_aspect_combo"); - break; - case LLSnapshotLivePreview::SNAPSHOT_TEXTURE: - size_combo_box = view->getChild("texture_size_combo"); - aspect_combo_box = view->getChild("texture_aspect_combo"); - break; - case LLSnapshotLivePreview::SNAPSHOT_LOCAL: - size_combo_box = view->getChild("local_size_combo"); - aspect_combo_box = view->getChild("local_aspect_combo"); - break; - } - S32 index = 0; - S32 const size_custom = size_combo_box->getItemCount() - (shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE ? 0 : 1); // Texture does not end on 'Custom'. - while (index < size_custom) - { - size_combo_box->setCurrentByIndex(index); - std::string sdstring = size_combo_box->getSelectedValue(); - LLSD sdres; - std::stringstream sstream(sdstring); - LLSDSerialize::fromNotation(sdres, sstream, sdstring.size()); - S32 width = sdres[0]; - S32 height = sdres[1]; - if (width == 0 || height == 0) - { - width = gViewerWindow->getWindowDisplayWidth(); - height = gViewerWindow->getWindowDisplayHeight(); - } - if (width == new_width && height == new_height) - { - break; - } - ++index; - } - if (index == size_custom && shot_type != LLSnapshotLivePreview::SNAPSHOT_TEXTURE) - { - size_combo_box->setCurrentByIndex(index); - } - index = 0; - S32 const aspect_custom = aspect_combo_box->getItemCount() - 1; - while (index < aspect_custom) - { - aspect_combo_box->setCurrentByIndex(index); - std::string sdstring = aspect_combo_box->getSelectedValue(); - std::stringstream sstream; - sstream << sdstring; - F32 aspect; - sstream >> aspect; - if (aspect == -2) // Default - { - aspect = (F32)new_width / new_height; - } - if (aspect == 0) // Current window - { - aspect = (F32)gViewerWindow->getWindowDisplayWidth() / gViewerWindow->getWindowDisplayHeight(); - } - if (llabs(aspect - new_aspect) < 0.0001) - { - break; - } - ++index; - } - if (index == aspect_custom) - { - aspect_combo_box->setCurrentByIndex(index); - setAspect(view, previewp->aspectComboName(), update_controls); - } - } - } - else -#endif - { - view->getChild("feed_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastResolution")); - view->getChild("feed_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastAspect")); - view->getChild("postcard_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution")); - view->getChild("postcard_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastAspect")); - view->getChild("texture_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution")); - view->getChild("texture_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastAspect")); - view->getChild("local_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution")); - view->getChild("local_aspect_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastAspect")); - } + view->getChild("feed_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotFeedLastResolution")); + view->getChild("postcard_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotPostcardLastResolution")); + view->getChild("texture_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotTextureLastResolution")); + view->getChild("local_size_combo")->selectNthItem(gSavedSettings.getS32("SnapshotLocalLastResolution")); std::string sdstring = combobox->getSelectedValue(); LLSD sdres; @@ -2526,6 +2420,12 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool S32 width = sdres[0]; S32 height = sdres[1]; + + if (width != -1 && height != -1) + { + // Not "Custom". + keepAspect(view, false); + } if (previewp && combobox->getCurrentIndex() >= 0) { @@ -2538,15 +2438,8 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool } else if (width == -1 || height == -1) { - if (previewp->isUsed() && new_width != 0 && new_height != 0) - { - previewp->setSize(new_width, new_height); - } - else - { - // load last custom value - previewp->setSize(gSavedSettings.getS32(lastSnapshotWidthName()), gSavedSettings.getS32(lastSnapshotHeightName())); - } + // load last custom value + previewp->setSize(gSavedSettings.getS32(lastSnapshotWidthName()), gSavedSettings.getS32(lastSnapshotHeightName())); } else if (height == -2) { @@ -2597,17 +2490,8 @@ void LLFloaterSnapshot::Impl::updateResolution(LLUICtrl* ctrl, void* data, bool if (previewp) { - if (new_aspect == 0) - { - // In case the aspect is 'Default', need to update aspect (which will call updateControls, if necessary). - setAspect(view, previewp->aspectComboName(), update_controls); - } - else - { - LLSpinCtrl* aspect_spinner = view->getChild("aspect_ratio"); - aspect_spinner->set(new_aspect); - previewp->setAspect(new_aspect); - } + // In case the aspect is 'Default', need to update aspect (which will call updateControls, if necessary). + setAspect(view, previewp->aspectComboName(), update_controls); } } @@ -2640,6 +2524,8 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda S32 width, height; previewp->getSize(width, height); aspect = (F32)width / height; + // Turn off "Keep aspect" when aspect is set to Default. + keepAspect(view, false); } else if (aspect == -1) // Custom { @@ -2651,6 +2537,7 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda } LLSpinCtrl* aspect_spinner = view->getChild("aspect_ratio"); + LLCheckBoxCtrl* keep_aspect = view->getChild("keep_aspect"); // Set whether or not the spinners can be changed. if (gSavedSettings.getBOOL("RenderUIInSnapshot") || @@ -2660,11 +2547,13 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda // Disable without making label gray. aspect_spinner->setAllowEdit(FALSE); aspect_spinner->setIncrement(0); + keep_aspect->setEnabled(FALSE); } else { aspect_spinner->setAllowEdit(TRUE); aspect_spinner->setIncrement(llmax(0.01f, lltrunc(aspect) / 100.0f)); + keep_aspect->setEnabled(TRUE); } // Sync the spinner and cache value. @@ -2685,6 +2574,77 @@ void LLFloaterSnapshot::Impl::updateAspect(LLUICtrl* ctrl, void* data, bool upda } } +// static +void LLFloaterSnapshot::Impl::enforceAspect(LLFloaterSnapshot* floater, F32 new_aspect) +{ + LLSnapshotLivePreview* previewp = getPreviewView(); + if (previewp) + { + LLComboBox* combo = floater->getChild(previewp->aspectComboName()); + S32 const aspect_custom = combo->getItemCount() - 1; + for (S32 index = 0; index <= aspect_custom; ++index) + { + combo->setCurrentByIndex(index); + if (index == aspect_custom) + { + gSavedSettings.setF32(lastSnapshotAspectName(), new_aspect); + break; + } + std::string sdstring = combo->getSelectedValue(); + std::stringstream sstream; + sstream << sdstring; + F32 aspect; + sstream >> aspect; + if (aspect == -2) // Default + { + continue; + } + if (aspect == 0) // Current window + { + aspect = (F32)gViewerWindow->getWindowDisplayWidth() / gViewerWindow->getWindowDisplayHeight(); + } + if (llabs(aspect - new_aspect) < 0.0001) + { + break; + } + } + storeAspectSetting(combo, previewp->aspectComboName()); + updateAspect(combo, floater, true); + } +} + +void LLFloaterSnapshot::Impl::enforceResolution(LLFloaterSnapshot* floater, F32 new_aspect) +{ + LLSnapshotLivePreview* previewp = getPreviewView(); + if (previewp) + { + // Get current size. + S32 w, h; + previewp->getSize(w, h); + // Do all calculation in floating point. + F32 cw = w; + F32 ch = h; + // Get the current raw size. + previewp->getRawSize(w, h); + F32 rw = w; + F32 rh = h; + // Fit rectangle with aspect new_aspect, around current rectangle, but cropped to raw size. + F32 nw = llmin(llmax(cw, ch * new_aspect), rw); + F32 nh = llmin(llmax(ch, cw / new_aspect), rh); + // Fit rectangle with aspect new_aspect inside that rectangle (in case it was cropped). + nw = llmin(nw, nh * new_aspect); + nh = llmin(nh, nw / new_aspect); + // Round off to nearest integer. + S32 new_width = llround(nw); + S32 new_height = llround(nh); + + gSavedSettings.setS32(lastSnapshotWidthName(), new_width); + gSavedSettings.setS32(lastSnapshotHeightName(), new_height); + comboSetCustom(floater, previewp->resolutionComboName()); + updateResolution(floater->getChild(previewp->resolutionComboName()), floater, false); + } +} + // static void LLFloaterSnapshot::Impl::onCommitLayerTypes(LLUICtrl* ctrl, void*data) { @@ -2703,13 +2663,20 @@ void LLFloaterSnapshot::Impl::onCommitSnapshotType(LLUICtrl* ctrl, void* data) LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; if (view) { - gSavedSettings.setS32("LastSnapshotType", getTypeIndex(view)); + LLSnapshotLivePreview::ESnapshotType snapshot_type = getTypeIndex(view); + gSavedSettings.setS32("LastSnapshotType", snapshot_type); + LLSnapshotLivePreview* previewp = getPreviewView(); + if (previewp) + { + previewp->setSnapshotType(snapshot_type); + } + keepAspect(view, gSavedSettings.getBOOL(snapshotKeepAspectName()), true); updateControls(view); } } -//static +//static void LLFloaterSnapshot::Impl::onCommitSnapshotFormat(LLUICtrl* ctrl, void* data) { LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; @@ -2729,7 +2696,12 @@ void LLFloaterSnapshot::Impl::comboSetCustom(LLFloaterSnapshot* floater, const s LLComboBox* combo = floater->getChild(comboname); combo->setCurrentByIndex(combo->getItemCount() - 1); // "custom" is always the last index + storeAspectSetting(combo, comboname); +} +// static +void LLFloaterSnapshot::Impl::storeAspectSetting(LLComboBox* combo, const std::string& comboname) +{ if(comboname == "feed_size_combo") { gSavedSettings.setS32("SnapshotFeedLastResolution", combo->getCurrentIndex()); @@ -2766,8 +2738,11 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; if (view) { - S32 w = llround(view->childGetValue("snapshot_width").asReal(), 1.0); - S32 h = llround(view->childGetValue("snapshot_height").asReal(), 1.0); + LLSpinCtrl* width_spinner = view->getChild("snapshot_width"); + LLSpinCtrl* height_spinner = view->getChild("snapshot_height"); + + S32 w = llround((F32)width_spinner->getValue().asReal(), 1.0f); + S32 h = llround((F32)height_spinner->getValue().asReal(), 1.0f); LLSnapshotLivePreview* previewp = getPreviewView(); if (previewp) @@ -2777,6 +2752,33 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat if (w != curw || h != curh) { + // Enforce multiple of 32 if the step was 32. + Dout(dc::snapshot, "w = " << w << "; curw = " << curw); + if (llabs(w - curw) == 32) + { + w = (w + 16) & -32; + Dout(dc::snapshot, "w = (w + 16) & -32 = " << w); + } + if (llabs(h - curh) == 32) + { + h = (h + 16) & -32; + } + if (gSavedSettings.getBOOL(snapshotKeepAspectName())) + { + F32 aspect = previewp->getAspect(); + if (h == curh) + { + // Width was changed. Change height to keep aspect constant. + h = llround(w / aspect); + } + else + { + // Height was changed. Change width to keep aspect constant. + w = llround(h * aspect); + } + } + width_spinner->forceSetValue(LLSD::Real(w)); + height_spinner->forceSetValue(LLSD::Real(h)); previewp->setMaxImageSize((S32)((LLSpinCtrl *)ctrl)->getMaxValue()) ; previewp->setSize(w,h); checkAutoSnapshot(previewp, FALSE); @@ -2794,6 +2796,30 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat } } +char const* LLSnapshotLivePreview::resolutionComboName() const +{ + char const* result; + switch(mSnapshotType) + { + case SNAPSHOT_FEED: + result = "feed_size_combo"; + break; + case SNAPSHOT_POSTCARD: + result = "postcard_size_combo"; + break; + case SNAPSHOT_TEXTURE: + result = "texture_size_combo"; + break; + case SNAPSHOT_LOCAL: + result = "local_size_combo"; + break; + default: + result= ""; + break; + } + return result; +} + char const* LLSnapshotLivePreview::aspectComboName() const { char const* result; @@ -2841,6 +2867,11 @@ void LLFloaterSnapshot::Impl::onCommitCustomAspect(LLUICtrl *ctrl, void* data) gSavedSettings.setF32(lastSnapshotAspectName(), a); + if (gSavedSettings.getBOOL(snapshotKeepAspectName())) + { + enforceResolution(view, a); + } + updateControls(view, true); } } @@ -2902,6 +2933,7 @@ BOOL LLFloaterSnapshot::postBuild() childSetCommitCallback("snapshot_height", Impl::onCommitCustomResolution, this); childSetCommitCallback("aspect_ratio", Impl::onCommitCustomAspect, this); + childSetCommitCallback("keep_aspect", Impl::onClickKeepAspect, this); childSetCommitCallback("ui_check", Impl::onClickUICheck, this); childSetValue("ui_check", gSavedSettings.getBOOL("RenderUIInSnapshot")); @@ -2952,8 +2984,9 @@ BOOL LLFloaterSnapshot::postBuild() Impl::sPreviewHandle = previewp->getHandle(); - impl.updateControls(this); + impl.keepAspect(sInstance, gSavedSettings.getBOOL(snapshotKeepAspectName()), true); impl.freezeTime(gSavedSettings.getBOOL("SnapshotOpenFreezeTime")); + impl.updateControls(this); return TRUE; } diff --git a/indra/newview/llfloaterstats.cpp b/indra/newview/llfloaterstats.cpp index fb9b1cc24..a60619882 100644 --- a/indra/newview/llfloaterstats.cpp +++ b/indra/newview/llfloaterstats.cpp @@ -45,6 +45,7 @@ #include "pipeline.h" #include "llviewerobjectlist.h" #include "llviewertexturelist.h" +#include "lltexturefetch.h" #include "sgmemstat.h" const S32 LL_SCROLL_BORDER = 1; @@ -151,10 +152,36 @@ void LLFloaterStats::buildStats() stat_barp->mLabelSpacing = 500.f; stat_barp->mPerSec = TRUE; + stat_barp = render_statviewp->addStat("Object Cache Hit Rate", &(LLViewerStats::getInstance()->mNumNewObjectsStat), std::string(), false, true); + stat_barp->setLabel("Object Cache Hit Rate"); + stat_barp->setUnitLabel("%"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 100.f; + stat_barp->mTickSpacing = 20.f; + stat_barp->mLabelSpacing = 20.f; + stat_barp->mPerSec = FALSE; // Texture statistics LLStatView *texture_statviewp = render_statviewp->addStatView("texture stat view", "Texture", "OpenDebugStatTexture", rect); + stat_barp = texture_statviewp->addStat("Cache Hit Rate", &(LLTextureFetch::sCacheHitRate), std::string(), false, true); + stat_barp->setLabel("Cache Hit Rate"); + stat_barp->setUnitLabel("%"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 100.f; + stat_barp->mTickSpacing = 20.f; + stat_barp->mLabelSpacing = 20.f; + stat_barp->mPerSec = FALSE; + + stat_barp = texture_statviewp->addStat("Cache Read Latency", &(LLTextureFetch::sCacheReadLatency), std::string(), false, true); + stat_barp->setUnitLabel("msec"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 1000.f; + stat_barp->mTickSpacing = 100.f; + stat_barp->mLabelSpacing = 200.f; + stat_barp->mPerSec = FALSE; + stat_barp->mDisplayMean = FALSE; + stat_barp = texture_statviewp->addStat("Count", &(LLViewerStats::getInstance()->mNumImagesStat), "DebugStatModeTextureCount"); stat_barp->setUnitLabel(""); stat_barp->mMinBar = 0.f; @@ -365,6 +392,15 @@ void LLFloaterStats::buildStats() stat_barp->mPerSec = FALSE; stat_barp->mDisplayMean = FALSE; + stat_barp = sim_statviewp->addStat("Scripts Run", &(LLViewerStats::getInstance()->mSimPctScriptsRun), std::string(), false, true); + stat_barp->setUnitLabel("%"); + stat_barp->mPrecision = 3; + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 100.f; + stat_barp->mTickSpacing = 10.f; + stat_barp->mLabelSpacing = 20.f; + stat_barp->mPerSec = FALSE; + stat_barp = sim_statviewp->addStat("Script Events", &(LLViewerStats::getInstance()->mSimScriptEPS), "DebugStatModeSimScriptEvents"); stat_barp->setUnitLabel(" eps"); stat_barp->mPrecision = 0; @@ -375,6 +411,35 @@ void LLFloaterStats::buildStats() stat_barp->mPerSec = FALSE; stat_barp->mDisplayMean = FALSE; + LLStatView *pathfinding_viewp = sim_statviewp->addStatView("pathfinding view", "Pathfinding Details", std::string(), rect); + stat_barp = pathfinding_viewp->addStat("AI Step Time", &(LLViewerStats::getInstance()->mSimSimAIStepMsec)); + stat_barp->setUnitLabel("ms"); + stat_barp->mPrecision = 3; + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 40.f; + stat_barp->mTickSpacing = 10.f; + stat_barp->mLabelSpacing = 20.f; + stat_barp->mPerSec = FALSE; + stat_barp->mDisplayMean = FALSE; + + stat_barp = render_statviewp->addStat("Skipped Silhouette Steps", &(LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps)); + stat_barp->setUnitLabel("/sec"); + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 45.f; + stat_barp->mTickSpacing = 4.f; + stat_barp->mLabelSpacing = 8.f; + stat_barp->mPrecision = 0; + + stat_barp = pathfinding_viewp->addStat("Characters Updated", &(LLViewerStats::getInstance()->mSimSimPctSteppedCharacters)); + stat_barp->setUnitLabel("%"); + stat_barp->mPrecision = 1; + stat_barp->mMinBar = 0.f; + stat_barp->mMaxBar = 100.f; + stat_barp->mTickSpacing = 10.f; + stat_barp->mLabelSpacing = 20.f; + stat_barp->mPerSec = FALSE; + stat_barp->mDisplayMean = TRUE; + stat_barp = sim_statviewp->addStat("Packets In", &(LLViewerStats::getInstance()->mSimInPPS), "DebugStatModeSimInPPS"); stat_barp->setUnitLabel(" pps"); stat_barp->mPrecision = 0; diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index 122cfd60f..dd6ea2864 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -103,27 +103,6 @@ LLFloaterURLEntry::LLFloaterURLEntry(LLHandle parent) mPanelLandMediaHandle(parent) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_url_entry.xml"); - - mMediaURLEdit = getChild("media_entry"); - - // Cancel button - childSetAction("cancel_btn", onBtnCancel, this); - - // Cancel button - childSetAction("clear_btn", onBtnClear, this); - - // clear media list button - LLSD parcel_history = LLURLHistory::getURLHistory("parcel"); - bool enable_clear_button = parcel_history.size() > 0 ? true : false; - childSetEnabled( "clear_btn", enable_clear_button ); - - // OK button - childSetAction("ok_btn", onBtnOK, this); - - setDefaultBtn("ok_btn"); - buildURLHistory(); - - sInstance = this; } //----------------------------------------------------------------------------- @@ -134,6 +113,28 @@ LLFloaterURLEntry::~LLFloaterURLEntry() sInstance = NULL; } +BOOL LLFloaterURLEntry::postBuild() +{ + mMediaURLEdit = getChild("media_entry"); + + // Cancel button + childSetAction("cancel_btn", onBtnCancel, this); + + // Cancel button + childSetAction("clear_btn", onBtnClear, this); + // clear media list button + LLSD parcel_history = LLURLHistory::getURLHistory("parcel"); + bool enable_clear_button = parcel_history.size() > 0 ? true : false; + getChildView("clear_btn")->setEnabled(enable_clear_button ); + + // OK button + childSetAction("ok_btn", onBtnOK, this); + + setDefaultBtn("ok_btn"); + buildURLHistory(); + + return TRUE; +} void LLFloaterURLEntry::buildURLHistory() { LLCtrlListInterface* url_list = childGetListInterface("media_entry"); @@ -157,7 +158,7 @@ void LLFloaterURLEntry::buildURLHistory() void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_type) { - LLPanelLandMedia* panel_media = (LLPanelLandMedia*)mPanelLandMediaHandle.get(); + LLPanelLandMedia* panel_media = dynamic_cast(mPanelLandMediaHandle.get()); if (panel_media) { // status is ignored for now -- error = "none/none" @@ -166,21 +167,18 @@ void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_ } // Decrement the cursor getWindow()->decBusyCount(); - childSetVisible("loading_label", false); + getChildView("loading_label")->setVisible( false); close(); } // static LLHandle LLFloaterURLEntry::show(LLHandle parent) { - if (sInstance) - { - sInstance->open(); - } - else + if (!sInstance) { sInstance = new LLFloaterURLEntry(parent); } + sInstance->open(); sInstance->updateFromLandMediaPanel(); return sInstance->getHandle(); } @@ -239,7 +237,8 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) } // Discover the MIME type only for "http" scheme. - if(scheme == "http" || scheme == "https") + if(!media_url.empty() && + (scheme == "http" || scheme == "https")) { LLHTTPClient::getHeaderOnly( media_url, new LLMediaTypeResponder(self->getHandle())); @@ -250,13 +249,13 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) } // Grey the buttons until we get the header response - self->childSetEnabled("ok_btn", false); - self->childSetEnabled("cancel_btn", false); - self->childSetEnabled("media_entry", false); + self->getChildView("ok_btn")->setEnabled(false); + self->getChildView("cancel_btn")->setEnabled(false); + self->getChildView("media_entry")->setEnabled(false); // show progress bar here? getWindow()->incBusyCount(); - self->childSetVisible("loading_label", true); + self->getChildView("loading_label")->setVisible( true); } // static @@ -298,7 +297,7 @@ bool LLFloaterURLEntry::callback_clear_url_list(const LLSD& notification, const LLURLHistory::clear("parcel"); // cleared the list so disable Clear button - childSetEnabled( "clear_btn", false ); + getChildView("clear_btn")->setEnabled(false ); } return false; } diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index dbc345a1c..0aeca823b 100644 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -45,7 +45,7 @@ public: // Can only be shown by LLPanelLandMedia, and pushes data back into // that panel via the handle. static LLHandle show(LLHandle panel_land_media_handle); - + /*virtual*/ BOOL postBuild(); void updateFromLandMediaPanel(); void headerFetchComplete(U32 status, const std::string& mime_type); diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 82e12f525..e474dec9e 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -1513,12 +1513,6 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) LLMenuGL::sMenuContainer->hideMenus(); } - LLView *item = NULL; - if (getChildCount() > 0) - { - item = *(getChildList()->begin()); - } - switch( key ) { case KEY_F2: @@ -2074,6 +2068,12 @@ void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constr } } +void LLFolderView::setScrollContainer(LLScrollableContainerView* parent) +{ + mScrollContainer = parent; + parent->setPassBackToChildren(false); +} + LLRect LLFolderView::getVisibleRect() { S32 visible_height = mScrollContainer->getRect().getHeight(); diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 0d36bfe3b..c2771ed77 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -217,7 +217,7 @@ public: void scrollToShowSelection(); void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect); - void setScrollContainer( LLScrollableContainerView* parent ) { mScrollContainer = parent; } + void setScrollContainer(LLScrollableContainerView* parent); LLRect getVisibleRect(); BOOL search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward); diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp index 5cba79d9d..e4815fbb1 100644 --- a/indra/newview/llmemoryview.cpp +++ b/indra/newview/llmemoryview.cpp @@ -104,6 +104,7 @@ void LLMemoryView::refreshProfile() mLines.clear(); +#if MEM_TRACK_MEM if(mAlloc->isProfiling()) { const LLAllocatorHeapProfile &prof = mAlloc->getProfile(); @@ -118,6 +119,7 @@ void LLMemoryView::refreshProfile() mLines.push_back(utf8string_to_wstring(ss.str())); } } +#endif } void LLMemoryView::draw() diff --git a/indra/newview/llpanelmediahud.cpp b/indra/newview/llpanelmediahud.cpp index 27d1473d6..e56e976f5 100644 --- a/indra/newview/llpanelmediahud.cpp +++ b/indra/newview/llpanelmediahud.cpp @@ -424,8 +424,8 @@ void LLPanelMediaHUD::setAlpha(F32 alpha) LLViewQuery query; LLView* query_view = mMediaFocus ? getChildView("media_focused_controls") : getChildView("media_hover_controls"); - child_list_t children = query(query_view); - for (child_list_iter_t child_iter = children.begin(); + viewList_t children = query(query_view); + for (viewList_t::iterator child_iter = children.begin(); child_iter != children.end(); ++child_iter) { LLUICtrl* ctrl = dynamic_cast(*child_iter); diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index 276bc4a0a..accd96b42 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -53,6 +53,7 @@ #include "llviewertexture.h" #include "llviewerregion.h" #include "llviewerstats.h" +#include "llviewerstatsrecorder.h" #include "llworld.h" #include "llstartup.h" #include "llbuffer.h" @@ -61,6 +62,9 @@ class AIHTTPTimeoutPolicy; extern AIHTTPTimeoutPolicy HTTPGetResponder_timeout; extern AIHTTPTimeoutPolicy lcl_responder_timeout; +LLStat LLTextureFetch::sCacheHitRate("texture_cache_hits", 128); +LLStat LLTextureFetch::sCacheReadLatency("texture_cache_read_latency", 128); + ////////////////////////////////////////////////////////////////////////////// class LLTextureFetchWorker : public LLWorkerClass { @@ -250,6 +254,8 @@ private: S32 mDecodedDiscard; LLFrameTimer mRequestedTimer; LLFrameTimer mFetchTimer; + LLTimer mCacheReadTimer; + F32 mCacheReadTime; LLTextureCache::handle_t mCacheReadHandle; LLTextureCache::handle_t mCacheWriteHandle; std::vector mHttpBuffer; @@ -289,9 +295,6 @@ private: S32 mLastPacket; U16 mTotalPackets; U8 mImageCodec; -#if HTTP_METRICS - LLViewerAssetStats::duration_t mMetricsStartTime; -#endif }; ////////////////////////////////////////////////////////////////////////////// @@ -384,20 +387,6 @@ public: } mFetcher->removeFromHTTPQueue(mID, data_size); - -#if HTTP_METRICS - if (worker->mMetricsStartTime) - { - LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, - true, - LLImageBase::TYPE_AVATAR_BAKE == worker->mType, - LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime); - worker->mMetricsStartTime = 0; - } - LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, - true, - LLImageBase::TYPE_AVATAR_BAKE == worker->mType); -#endif } else { @@ -514,230 +503,6 @@ static bool sgConnectionThrottle() { } #endif -#if HTTP_METRICS -// Cross-thread messaging for asset metrics. - -/** - * @brief Base class for cross-thread requests made of the fetcher - * - * I believe the intent of the LLQueuedThread class was to - * have these operations derived from LLQueuedThread::QueuedRequest - * but the texture fetcher has elected to manage the queue - * in its own manner. So these are free-standing objects which are - * managed in simple FIFO order on the mCommands queue of the - * LLTextureFetch object. - * - * What each represents is a simple command sent from an - * outside thread into the TextureFetch thread to be processed - * in order and in a timely fashion (though not an absolute - * higher priority than other operations of the thread). - * Each operation derives a new class from the base customizing - * members, constructors and the doWork() method to effect - * the command. - * - * The flow is one-directional. There are two global instances - * of the LLViewerAssetStats collector, one for the main program's - * thread pointed to by gViewerAssetStatsMain and one for the - * TextureFetch thread pointed to by gViewerAssetStatsThread1. - * Common operations has each thread recording metrics events - * into the respective collector unconcerned with locking and - * the state of any other thread. But when the agent moves into - * a different region or the metrics timer expires and a report - * needs to be sent back to the grid, messaging across threads - * is required to distribute data and perform global actions. - * In pseudo-UML, it looks like: - * - * Main Thread1 - * . . - * . . - * +-----+ . - * | AM | . - * +--+--+ . - * +-------+ | . - * | Main | +--+--+ . - * | | | SRE |---. . - * | Stats | +-----+ \ . - * | | | \ (uuid) +-----+ - * | Coll. | +--+--+ `-------->| SR | - * +-------+ | MSC | +--+--+ - * | ^ +-----+ | - * | | (uuid) / . +-----+ (uuid) - * | `--------' . | MSC |---------. - * | . +-----+ | - * | +-----+ . v - * | | TE | . +-------+ - * | +--+--+ . | Thd1 | - * | | . | | - * | +-----+ . | Stats | - * `--------->| RSC | . | | - * +--+--+ . | Coll. | - * | . +-------+ - * +--+--+ . | - * | SME |---. . | - * +-----+ \ . | - * . \ (clone) +-----+ | - * . `-------->| SM | | - * . +--+--+ | - * . | | - * . +-----+ | - * . | RSC |<--------' - * . +-----+ - * . | - * . +-----+ - * . | CP |--> HTTP POST - * . +-----+ - * . . - * . . - * - * - * Key: - * - * SRE - Set Region Enqueued. Enqueue a 'Set Region' command in - * the other thread providing the new UUID of the region. - * TFReqSetRegion carries the data. - * SR - Set Region. New region UUID is sent to the thread-local - * collector. - * SME - Send Metrics Enqueued. Enqueue a 'Send Metrics' command - * including an ownership transfer of a cloned LLViewerAssetStats. - * TFReqSendMetrics carries the data. - * SM - Send Metrics. Global metrics reporting operation. Takes - * the cloned stats from the command, merges it with the - * thread's local stats, converts to LLSD and sends it on - * to the grid. - * AM - Agent Moved. Agent has completed some sort of move to a - * new region. - * TE - Timer Expired. Metrics timer has expired (on the order - * of 10 minutes). - * CP - CURL Post - * MSC - Modify Stats Collector. State change in the thread-local - * collector. Typically a region change which affects the - * global pointers used to find the 'current stats'. - * RSC - Read Stats Collector. Extract collector data cloning it - * (i.e. deep copy) when necessary. - * - */ -class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest -{ -public: - // Default ctors and assignment operator are correct. - - virtual ~TFRequest() - {} - - // Patterned after QueuedRequest's method but expected behavior - // is different. Always expected to complete on the first call - // and work dispatcher will assume the same and delete the - // request after invocation. - virtual bool doWork(LLTextureFetch * fetcher) = 0; -}; - -namespace -{ - -/** - * @brief Implements a 'Set Region' cross-thread command. - * - * When an agent moves to a new region, subsequent metrics need - * to be binned into a new or existing stats collection in 1:1 - * relationship with the region. We communicate this region - * change across the threads involved in the communication with - * this message. - * - * Corresponds to LLTextureFetch::commandSetRegion() - */ -class TFReqSetRegion : public LLTextureFetch::TFRequest -{ -public: - TFReqSetRegion(U64 region_handle) - : LLTextureFetch::TFRequest(), - mRegionHandle(region_handle) - {} - TFReqSetRegion & operator=(const TFReqSetRegion &); // Not defined - - virtual ~TFReqSetRegion() - {} - - virtual bool doWork(LLTextureFetch * fetcher); - -public: - const U64 mRegionHandle; -}; - - -/** - * @brief Implements a 'Send Metrics' cross-thread command. - * - * This is the big operation. The main thread gathers metrics - * for a period of minutes into LLViewerAssetStats and other - * objects then makes a snapshot of the data by cloning the - * collector. This command transfers the clone, along with a few - * additional arguments (UUIDs), handing ownership to the - * TextureFetch thread. It then merges its own data into the - * cloned copy, converts to LLSD and kicks off an HTTP POST of - * the resulting data to the currently active metrics collector. - * - * Corresponds to LLTextureFetch::commandSendMetrics() - */ - -class TFReqSendMetrics : public LLTextureFetch::TFRequest -{ -public: - /** - * Construct the 'Send Metrics' command to have the TextureFetch - * thread add and log metrics data. - * - * @param caps_url URL of a "ViewerMetrics" Caps target - * to receive the data. Does not have to - * be associated with a particular region. - * - * @param session_id UUID of the agent's session. - * - * @param agent_id UUID of the agent. (Being pure here...) - * - * @param main_stats Pointer to a clone of the main thread's - * LLViewerAssetStats data. Thread1 takes - * ownership of the copy and disposes of it - * when done. - */ - - TFReqSendMetrics(const std::string & caps_url, - const LLUUID & session_id, - const LLUUID & agent_id, - LLViewerAssetStats * main_stats) - : LLTextureFetch::TFRequest(), - mCapsURL(caps_url), - mSessionID(session_id), - mAgentID(agent_id), - mMainStats(main_stats) - {} - TFReqSendMetrics & operator=(const TFReqSendMetrics &); // Not defined - - virtual ~TFReqSendMetrics(); - - virtual bool doWork(LLTextureFetch * fetcher); - -public: - const std::string mCapsURL; - const LLUUID mSessionID; - const LLUUID mAgentID; - LLViewerAssetStats * mMainStats; -}; - -/* - * Examines the merged viewer metrics report and if found to be too long, - * will attempt to truncate it in some reasonable fashion. - * - * @param max_regions Limit of regions allowed in report. - * - * @param metrics Full, merged viewer metrics report. - * - * @returns If data was truncated, returns true. - */ -bool truncate_viewer_metrics(int max_regions, LLSD & metrics); - -} // end of anonymous namespace -#endif - ////////////////////////////////////////////////////////////////////////////// //static @@ -757,11 +522,6 @@ const char* LLTextureFetchWorker::sStateDescs[] = { "DONE", }; -#if HTTP_METRICS -// static -volatile bool LLTextureFetch::svMetricsDataBreak(true); // Start with a data break -#endif - // called from MAIN THREAD LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, @@ -786,6 +546,7 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mRequestedDiscard(-1), mLoadedDiscard(-1), mDecodedDiscard(-1), + mCacheReadTime(0.f), mCacheReadHandle(LLTextureCache::nullHandle()), mCacheWriteHandle(LLTextureCache::nullHandle()), mRequestedSize(0), @@ -810,9 +571,6 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher, mLastPacket(-1), mTotalPackets(0), mImageCodec(IMG_CODEC_INVALID) -#if HTTP_METRICS - ,mMetricsStartTime(0) -#endif { mCanUseNET = mUrl.empty() ; @@ -1064,6 +822,7 @@ bool LLTextureFetchWorker::doWork(S32 param) CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority, offset, size, responder); + mCacheReadTimer.reset(); } else if (mUrl.empty()) { @@ -1072,8 +831,9 @@ bool LLTextureFetchWorker::doWork(S32 param) CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage); mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority, offset, size, responder); + mCacheReadTimer.reset(); } - else if(mCanUseHTTP) + else if(!mUrl.empty() && mCanUseHTTP) { if (!(mUrl.compare(0, 7, "http://") == 0)) { @@ -1101,6 +861,9 @@ bool LLTextureFetchWorker::doWork(S32 param) } else { + // + //This should never happen + // return false; } } @@ -1124,7 +887,7 @@ bool LLTextureFetchWorker::doWork(S32 param) LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize() << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight()) << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL; - // fall through + LLTextureFetch::sCacheHitRate.addValue(100.f); } else { @@ -1139,7 +902,9 @@ bool LLTextureFetchWorker::doWork(S32 param) LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL; mState = LOAD_FROM_NETWORK; } + // fall through + LLTextureFetch::sCacheHitRate.addValue(0.f); } } @@ -1198,15 +963,6 @@ bool LLTextureFetchWorker::doWork(S32 param) mRequestedDiscard = mDesiredDiscard; mSentRequest = QUEUED; mFetcher->addToNetworkQueue(this); -#if HTTP_METRICS - if (! mMetricsStartTime) - { - mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - } - LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, - false, - LLImageBase::TYPE_AVATAR_BAKE == mType); -#endif setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return false; @@ -1217,12 +973,6 @@ bool LLTextureFetchWorker::doWork(S32 param) //llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end()); // Make certain this is in the network queue //mFetcher->addToNetworkQueue(this); - //if (! mMetricsStartTime) - //{ - // mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - //} - //LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false, - // LLImageBase::TYPE_AVATAR_BAKE == mType); //setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return false; } @@ -1247,33 +997,10 @@ bool LLTextureFetchWorker::doWork(S32 param) setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); mState = DECODE_IMAGE; mWriteToCacheState = SHOULD_WRITE; - -#if HTTP_METRICS - if (mMetricsStartTime) - { - LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE, - false, - LLImageBase::TYPE_AVATAR_BAKE == mType, - LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime); - mMetricsStartTime = 0; - } - LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE, - false, - LLImageBase::TYPE_AVATAR_BAKE == mType); -#endif } else { mFetcher->addToNetworkQueue(this); // failsafe -#if HTTP_METRICS - if (! mMetricsStartTime) - { - mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - } - LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, - false, - LLImageBase::TYPE_AVATAR_BAKE == mType); -#endif setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); } return false; @@ -1340,15 +1067,6 @@ bool LLTextureFetchWorker::doWork(S32 param) mState = WAIT_HTTP_REQ; mFetcher->addToHTTPQueue(mID); -#if HTTP_METRICS - if (! mMetricsStartTime) - { - mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp(); - } - LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, - true, - LLImageBase::TYPE_AVATAR_BAKE == mType); -#endif if(mRequestedOffset>0) { @@ -1573,11 +1291,12 @@ bool LLTextureFetchWorker::doWork(S32 param) if (mState == DECODE_IMAGE) { static LLCachedControl textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled"); - if(textures_decode_disabled) + + setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + if (textures_decode_disabled) { // for debug use, don't decode mState = DONE; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return true; } @@ -1585,7 +1304,6 @@ bool LLTextureFetchWorker::doWork(S32 param) { // We aborted, don't decode mState = DONE; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return true; } @@ -1595,7 +1313,6 @@ bool LLTextureFetchWorker::doWork(S32 param) //abort, don't decode mState = DONE; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return true; } if (mLoadedDiscard < 0) @@ -1604,10 +1321,9 @@ bool LLTextureFetchWorker::doWork(S32 param) //abort, don't decode mState = DONE; - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); return true; } - setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it + mRawImage = NULL; mAuxImage = NULL; llassert_always(mFormattedImage.notNull()); @@ -1899,6 +1615,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL; if (data_size > 0) { + LLViewerStatsRecorder::instance().textureFetch(data_size); // *TODO: set the formatted image data here directly to avoid the copy llassert(mHttpBuffer.empty()); mHttpBuffer.resize(data_size); @@ -1932,6 +1649,7 @@ S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels, mLoaded = TRUE; setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + LLViewerStatsRecorder::instance().log(0.2f); return data_size ; } @@ -2017,6 +1735,7 @@ void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImag mDecoded = TRUE; // llinfos << mID << " : DECODE COMPLETE " << llendl; setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority); + mCacheReadTime = mCacheReadTimer.getElapsedTimeF32(); } ////////////////////////////////////////////////////////////////////////////// @@ -2058,13 +1777,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image mTextureBandwidth(0), mHTTPTextureBits(0), mTotalHTTPRequests(0) -#if HTTP_METRICS - ,mQAMode(qa_mode) -#endif { -#if HTTP_METRICS - mCurlPOSTRequestCount = 0; -#endif mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold")); } @@ -2072,14 +1785,6 @@ LLTextureFetch::~LLTextureFetch() { clearDeleteList() ; -#if HTTP_METRICS - while (! mCommands.empty()) - { - TFRequest * req(mCommands.front()); - mCommands.erase(mCommands.begin()); - delete req; - } -#endif // ~LLQueuedThread() called here } @@ -2341,6 +2046,11 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, discard_level = worker->mDecodedDiscard; raw = worker->mRawImage; aux = worker->mAuxImage; + F32 cache_read_time = worker->mCacheReadTime; + if (cache_read_time != 0.f) + { + sCacheReadLatency.addValue(cache_read_time * 1000.f); + } res = true; LL_DEBUGS("Texture") << id << ": Request Finished. State: " << worker->mState << " Discard: " << discard_level << LL_ENDL; worker->unlockWorkMutex(); @@ -2393,10 +2103,6 @@ S32 LLTextureFetch::getPending() LLMutexLock lock(&mQueueMutex); res = mRequestQueue.size(); -#if HTTP_METRICS - res += mCurlPOSTRequestCount; - res += mCommands.size(); -#endif } unlockData(); return res; @@ -2414,22 +2120,7 @@ bool LLTextureFetch::runCondition() // // Changes here may need to be reflected in getPending(). -#if HTTP_METRICS - bool have_no_commands(false); - { - LLMutexLock lock(&mQueueMutex); - - have_no_commands = mCommands.empty(); - } - - bool have_no_curl_requests(0 == mCurlPOSTRequestCount); - - return ! (have_no_commands - && have_no_curl_requests - && (mRequestQueue.empty() && mIdleThread)); // From base class -#else - return !(mRequestQueue.empty() && mIdleThread); -#endif + return ! (mRequestQueue.empty() && mIdleThread); // From base class } ////////////////////////////////////////////////////////////////////////////// @@ -2437,10 +2128,6 @@ bool LLTextureFetch::runCondition() // MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs) void LLTextureFetch::commonUpdate() { -#if HTTP_METRICS - // Run a cross-thread command, if any. - cmdDoWork(); -#endif } @@ -2799,11 +2486,16 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 mNetworkQueueMutex.unlock() ; return false; } + + LLViewerStatsRecorder::instance().textureFetch(data_size); + LLViewerStatsRecorder::instance().log(0.1f); + worker->lockWorkMutex(); - // Copy header data into image object - worker->mImageCodec = codec; - worker->mTotalPackets = packets; + + // Copy header data into image object + worker->mImageCodec = codec; + worker->mTotalPackets = packets; worker->mFileSize = (S32)totalbytes; llassert_always(totalbytes > 0); llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize); @@ -2844,8 +2536,12 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1 mNetworkQueueMutex.unlock() ; return false; } + + LLViewerStatsRecorder::instance().textureFetch(data_size); + LLViewerStatsRecorder::instance().log(0.1f); worker->lockWorkMutex(); + res = worker->insertPacket(packet_num, data, data_size); @@ -2959,277 +2655,12 @@ void LLTextureFetch::dump() << " STATE: " << worker->sStateDescs[worker->mState] << llendl; } -} -////////////////////////////////////////////////////////////////////////////// - -// cross-thread command methods - -#if HTTP_METRICS -void LLTextureFetch::commandSetRegion(U64 region_handle) -{ - TFReqSetRegion * req = new TFReqSetRegion(region_handle); - - cmdEnqueue(req); -} - -void LLTextureFetch::commandSendMetrics(const std::string & caps_url, - const LLUUID & session_id, - const LLUUID & agent_id, - LLViewerAssetStats * main_stats) -{ - TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats); - - cmdEnqueue(req); -} - -void LLTextureFetch::commandDataBreak() -{ - // The pedantically correct way to implement this is to create a command - // request object in the above fashion and enqueue it. However, this is - // simple data of an advisorial not operational nature and this case - // of shared-write access is tolerable. - - LLTextureFetch::svMetricsDataBreak = true; -} - -void LLTextureFetch::cmdEnqueue(TFRequest * req) -{ - lockQueue(); - mCommands.push_back(req); - unlockQueue(); - - unpause(); -} - -LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue() -{ - TFRequest * ret = 0; - - lockQueue(); - if (! mCommands.empty()) + llinfos << "LLTextureFetch ACTIVE_HTTP:" << llendl; + for (queue_t::const_iterator iter(mHTTPTextureQueue.begin()); + mHTTPTextureQueue.end() != iter; + ++iter) { - ret = mCommands.front(); - mCommands.erase(mCommands.begin()); - } - unlockQueue(); - - return ret; -} - -void LLTextureFetch::cmdDoWork() -{ - if (mDebugPause) - { - return; // debug: don't do any work - } - - TFRequest * req = cmdDequeue(); - if (req) - { - // One request per pass should really be enough for this. - req->doWork(this); - delete req; + llinfos << " ID: " << (*iter) << llendl; } } - - -////////////////////////////////////////////////////////////////////////////// - -// Private (anonymous) class methods implementing the command scheme. - -namespace -{ - -/** - * Implements the 'Set Region' command. - * - * Thread: Thread1 (TextureFetch) - */ -bool -TFReqSetRegion::doWork(LLTextureFetch *) -{ - LLViewerAssetStatsFF::set_region_thread1(mRegionHandle); - return true; -} - - -TFReqSendMetrics::~TFReqSendMetrics() -{ - delete mMainStats; - mMainStats = 0; -} - - -/** - * Implements the 'Send Metrics' command. Takes over - * ownership of the passed LLViewerAssetStats pointer. - * - * Thread: Thread1 (TextureFetch) - */ -bool -TFReqSendMetrics::doWork(LLTextureFetch * fetcher) -{ - /* - * HTTP POST responder. Doesn't do much but tries to - * detect simple breaks in recording the metrics stream. - * - * The 'volatile' modifiers don't indicate signals, - * mmap'd memory or threads, really. They indicate that - * the referenced data is part of a pseudo-closure for - * this responder rather than being required for correct - * operation. - * - * We don't try very hard with the POST request. We give - * it one shot and that's more-or-less it. With a proper - * refactoring of the LLQueuedThread usage, these POSTs - * could be put in a request object and made more reliable. - */ - class lcl_responder : public LLHTTPClient::ResponderWithResult - { - public: - lcl_responder(LLTextureFetch * fetcher, - S32 expected_sequence, - volatile const S32 & live_sequence, - volatile bool & reporting_break, - volatile bool & reporting_started) - : mFetcher(fetcher), - mExpectedSequence(expected_sequence), - mLiveSequence(live_sequence), - mReportingBreak(reporting_break), - mReportingStarted(reporting_started) - { - mFetcher->incrCurlPOSTCount(); - } - - ~lcl_responder() - { - mFetcher->decrCurlPOSTCount(); - } - - /*virtual*/ void error(U32 status_num, const std::string & reason) - { - if (mLiveSequence == mExpectedSequence) - { - mReportingBreak = true; - } - LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service. Reason: " - << reason << LL_ENDL; - } - - /*virtual*/ void result(const LLSD & content) - { - if (mLiveSequence == mExpectedSequence) - { - mReportingBreak = false; - mReportingStarted = true; - } - } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return lcl_responder_timeout; } - /*virtual*/ char const* getName(void) const { return "lcl_responder"; } - - private: - LLTextureFetch * mFetcher; - S32 mExpectedSequence; - volatile const S32 & mLiveSequence; - volatile bool & mReportingBreak; - volatile bool & mReportingStarted; - - }; // class lcl_responder - - if (! gViewerAssetStatsThread1) - return true; - - static volatile bool reporting_started(false); - static volatile S32 report_sequence(0); - - // We've taken over ownership of the stats copy at this - // point. Get a working reference to it for merging here - // but leave it in 'this'. Destructor will rid us of it. - LLViewerAssetStats & main_stats = *mMainStats; - - // Merge existing stats into those from main, convert to LLSD - main_stats.merge(*gViewerAssetStatsThread1); - LLSD merged_llsd = main_stats.asLLSD(true); - - // Add some additional meta fields to the content - merged_llsd["session_id"] = mSessionID; - merged_llsd["agent_id"] = mAgentID; - merged_llsd["message"] = "ViewerAssetMetrics"; // Identifies the type of metrics - merged_llsd["sequence"] = report_sequence; // Sequence number - merged_llsd["initial"] = ! reporting_started; // Initial data from viewer - merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak; // Break in data prior to this report - - // Update sequence number - if (S32_MAX == ++report_sequence) - report_sequence = 0; - - // Limit the size of the stats report if necessary. - merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd); - - if (! mCapsURL.empty()) - { - LLHTTPClient::post(mCapsURL, - merged_llsd, - new lcl_responder(fetcher, - report_sequence, - report_sequence, - LLTextureFetch::svMetricsDataBreak, - reporting_started)); - } - else - { - LLTextureFetch::svMetricsDataBreak = true; - } - - // In QA mode, Metrics submode, log the result for ease of testing - if (fetcher->isQAMode()) - { - LL_INFOS("Textures") << merged_llsd << LL_ENDL; - } - - gViewerAssetStatsThread1->reset(); - - return true; -} - -bool -truncate_viewer_metrics(int max_regions, LLSD & metrics) -{ - static const LLSD::String reg_tag("regions"); - static const LLSD::String duration_tag("duration"); - - LLSD & reg_map(metrics[reg_tag]); - if (reg_map.size() <= max_regions) - { - return false; - } - - // Build map of region hashes ordered by duration - typedef std::multimap reg_ordered_list_t; - reg_ordered_list_t regions_by_duration; - - int ind(0); - LLSD::array_const_iterator it_end(reg_map.endArray()); - for (LLSD::array_const_iterator it(reg_map.beginArray()); it_end != it; ++it, ++ind) - { - LLSD::Real duration = (*it)[duration_tag].asReal(); - regions_by_duration.insert(reg_ordered_list_t::value_type(duration, ind)); - } - - // Build a replacement regions array with the longest-persistence regions - LLSD new_region(LLSD::emptyArray()); - reg_ordered_list_t::const_reverse_iterator it2_end(regions_by_duration.rend()); - reg_ordered_list_t::const_reverse_iterator it2(regions_by_duration.rbegin()); - for (int i(0); i < max_regions && it2_end != it2; ++i, ++it2) - { - new_region.append(reg_map[it2->second]); - } - reg_map = new_region; - - return true; -} - -} // end of anonymous namespace -#endif - diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index ac36fe74b..cbf8d1b50 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -46,9 +46,6 @@ class HTTPGetResponder; class LLTextureCache; class LLImageDecodeThread; class LLHost; -#if HTTP_METRICS -class LLViewerAssetStats; -#endif // Interface class class LLTextureFetch : public LLWorkerThread @@ -98,22 +95,6 @@ public: LLTextureInfo* getTextureInfo() { return &mTextureInfo; } -#if HTTP_METRICS - // Commands available to other threads to control metrics gathering operations. - void commandSetRegion(U64 region_handle); - void commandSendMetrics(const std::string & caps_url, - const LLUUID & session_id, - const LLUUID & agent_id, - LLViewerAssetStats * main_stats); - void commandDataBreak(); - - bool isQAMode() const { return mQAMode; } - - // Curl POST counter maintenance - inline void incrCurlPOSTCount() { mCurlPOSTRequestCount++; } - inline void decrCurlPOSTCount() { mCurlPOSTRequestCount--; } -#endif - protected: void addToNetworkQueue(LLTextureFetchWorker* worker); void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel); @@ -129,37 +110,6 @@ private: /*virtual*/ void threadedUpdate(void); void commonUpdate(); -#if HTTP_METRICS - // Metrics command helpers - /** - * Enqueues a command request at the end of the command queue - * and wakes up the thread as needed. - * - * Takes ownership of the TFRequest object. - * - * Method locks the command queue. - */ - void cmdEnqueue(TFRequest *); - - /** - * Returns the first TFRequest object in the command queue or - * NULL if none is present. - * - * Caller acquires ownership of the object and must dispose of it. - * - * Method locks the command queue. - */ - TFRequest * cmdDequeue(); - - /** - * Processes the first command in the queue disposing of the - * request on completion. Successive calls are needed to perform - * additional commands. - * - * Method locks the command queue. - */ - void cmdDoWork(); -#endif public: LLUUID mDebugID; @@ -172,6 +122,11 @@ private: LLMutex mQueueMutex; //to protect mRequestMap only LLMutex mNetworkQueueMutex; //to protect mNetworkQueue, mHTTPTextureQueue and mCancelQueue. +public: + static LLStat sCacheHitRate; + static LLStat sCacheReadLatency; +private: + LLTextureCache* mTextureCache; LLImageDecodeThread* mImageDecodeThread; @@ -193,30 +148,6 @@ private: //debug use U32 mTotalHTTPRequests ; -#if HTTP_METRICS - // Out-of-band cross-thread command queue. This command queue - // is logically tied to LLQueuedThread's list of - // QueuedRequest instances and so must be covered by the - // same locks. - typedef std::vector command_queue_t; - command_queue_t mCommands; - - // If true, modifies some behaviors that help with QA tasks. - const bool mQAMode; - - // Count of POST requests outstanding. We maintain the count - // indirectly in the CURL request responder's ctor and dtor and - // use it when determining whether or not to sleep the thread. Can't - // use the LLCurl module's request counter as it isn't thread compatible. - // *NOTE: Don't mix Atomic and static, apr_initialize must be called first. - LLAtomic32 mCurlPOSTRequestCount; - -public: - // A probabilistically-correct indicator that the current - // attempt to log metrics follows a break in the metrics stream - // reporting due to either startup or a problem POSTing data. - static volatile bool svMetricsDataBreak; -#endif }; #endif // LL_LLTEXTUREFETCH_H diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index 0a0eb5f08..e57fbc3a2 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -101,7 +101,7 @@ public: // Used for sorting struct sort { - bool operator()(const LLView* i1, const LLView* i2) + bool operator()(const LLView* i1, const LLView* i2) const { LLTextureBar* bar1p = (LLTextureBar*)i1; LLTextureBar* bar2p = (LLTextureBar*)i2; @@ -120,7 +120,7 @@ public: struct sort_fetch { - bool operator()(const LLView* i1, const LLView* i2) + bool operator()(const LLView* i1, const LLView* i2) const { LLTextureBar* bar1p = (LLTextureBar*)i1; LLTextureBar* bar2p = (LLTextureBar*)i2; diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 6e35d5481..d9dcf4384 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5179,6 +5179,18 @@ void process_sim_stats(LLMessageSystem *msg, void **user_data) case LL_SIM_STAT_IOPUMPTIME: LLViewerStats::getInstance()->mSimPumpIOMsec.addValue(stat_value); break; + case LL_SIM_STAT_PCTSCRIPTSRUN: + LLViewerStats::getInstance()->mSimPctScriptsRun.addValue(stat_value); + break; + case LL_SIM_STAT_SIMAISTEPTIMEMS: + LLViewerStats::getInstance()->mSimSimAIStepMsec.addValue(stat_value); + break; + case LL_SIM_STAT_SKIPPEDAISILSTEPS_PS: + LLViewerStats::getInstance()->mSimSimSkippedSilhouetteSteps.addValue(stat_value); + break; + case LL_SIM_STAT_PCTSTEPPEDCHARACTERS: + LLViewerStats::getInstance()->mSimSimPctSteppedCharacters.addValue(stat_value); + break; default: // Used to be a commented out warning. LL_DEBUGS("Messaging") << "Unknown stat id" << stat_id << LL_ENDL; @@ -5798,6 +5810,35 @@ static std::string reason_from_transaction_type(S32 transaction_type, } } +static void money_balance_group_notify(const LLUUID& group_id, + const std::string& name, + bool is_group, + std::string message, + std::string notification, + LLStringUtil::format_map_t args, + LLSD payload) +{ + args["NAME"] = name; + LLSD msg_args; + msg_args["MESSAGE"] = LLTrans::getString(message,args); + LLNotificationsUtil::add(notification,msg_args,payload); +} + +static void money_balance_avatar_notify(const LLUUID& agent_id, + const LLAvatarName& av_name, + std::string message, + std::string notification, + LLStringUtil::format_map_t args, + LLSD payload) +{ + + std::string name; + LLAvatarNameCache::getPNSName(av_name,name); + args["NAME"] = name; + LLSD msg_args; + msg_args["MESSAGE"] = LLTrans::getString(message,args); + LLNotificationsUtil::add(notification,msg_args,payload); +} static void process_money_balance_reply_extended(LLMessageSystem* msg) { // Added in server 1.40 and viewer 2.1, support for localization @@ -5830,26 +5871,6 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) return; } - std::string source_slurl; - if (is_source_group) - { - gCacheName->getGroupName(source_id, source_slurl); - } - else - { - LLAvatarNameCache::getPNSName(source_id, source_slurl); - } - - std::string dest_slurl; - if (is_dest_group) - { - gCacheName->getGroupName(dest_id, dest_slurl); - } - else - { - LLAvatarNameCache::getPNSName(dest_id, dest_slurl); - } - std::string reason = reason_from_transaction_type(transaction_type, item_description); @@ -5864,60 +5885,55 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) std::string message; static LLCachedControl no_transaction_clutter("LiruNoTransactionClutter", false); std::string notification = no_transaction_clutter ? "Payment" : "SystemMessage"; - LLSD final_args; LLSD payload; bool you_paid_someone = (source_id == gAgentID); if (you_paid_someone) { - args["NAME"] = dest_slurl; is_name_group = is_dest_group; name_id = dest_id; if (!reason.empty()) { if (dest_id.notNull()) { - message = success ? LLTrans::getString("you_paid_ldollars", args) : - LLTrans::getString("you_paid_failure_ldollars", args); + message = success ? "you_paid_ldollars" : + "you_paid_failure_ldollars"; } else { // transaction fee to the system, eg, to create a group - message = success ? LLTrans::getString("you_paid_ldollars_no_name", args) : - LLTrans::getString("you_paid_failure_ldollars_no_name", args); + message = success ? "you_paid_ldollars_no_name" : + "you_paid_failure_ldollars_no_name"; } } else { if (dest_id.notNull()) { - message = success ? LLTrans::getString("you_paid_ldollars_no_reason", args) : - LLTrans::getString("you_paid_failure_ldollars_no_reason", args); + message = success ? "you_paid_ldollars_no_reason" : + "you_paid_failure_ldollars_no_reason"; } else { // no target, no reason, you just paid money - message = success ? LLTrans::getString("you_paid_ldollars_no_info", args) : - LLTrans::getString("you_paid_failure_ldollars_no_info", args); + message = success ? "you_paid_ldollars_no_info" : + "you_paid_failure_ldollars_no_info"; } } - final_args["MESSAGE"] = message; } else { // ...someone paid you - args["NAME"] = source_slurl; is_name_group = is_source_group; name_id = source_id; if (!reason.empty()) { - message = LLTrans::getString("paid_you_ldollars", args); + message = "paid_you_ldollars"; } else { - message = LLTrans::getString("paid_you_ldollars_no_reason", args); + message = "paid_you_ldollars_no_reason"; } - final_args["MESSAGE"] = message; // make notification loggable payload["from_id"] = source_id; @@ -5929,14 +5945,15 @@ static void process_money_balance_reply_extended(LLMessageSystem* msg) if (is_name_group) { gCacheName->getGroup(name_id, - boost::bind(&LLNotificationsUtil::add, - notification, final_args, payload)); + boost::bind(&money_balance_group_notify, + _1, _2, _3, message, + notification, args, payload)); } - else - { + else { LLAvatarNameCache::get(name_id, - boost::bind(&LLNotificationsUtil::add, - notification, final_args, payload)); + boost::bind(&money_balance_avatar_notify, + _1, _2, message, + notification, args, payload)); } if (!no_transaction_clutter) LLFloaterChat::addChat(message); // Alerts won't automatically log to chat. diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 0bdee81c3..8c262fef3 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -1445,8 +1445,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, val = (U16 *) &data[count]; #endif new_angv.set(U16_to_F32(val[VX], -size, size), - U16_to_F32(val[VY], -size, size), - U16_to_F32(val[VZ], -size, size)); + U16_to_F32(val[VY], -size, size), + U16_to_F32(val[VZ], -size, size)); setAngularVelocity(new_angv); break; @@ -1471,9 +1471,10 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, new_rot.mQ[VZ] = U8_to_F32(data[11], -1.f, 1.f); new_rot.mQ[VW] = U8_to_F32(data[12], -1.f, 1.f); - setAngularVelocity( U8_to_F32(data[13], -size, size), - U8_to_F32(data[14], -size, size), - U8_to_F32(data[15], -size, size) ); + new_angv.set(U8_to_F32(data[13], -size, size), + U8_to_F32(data[14], -size, size), + U8_to_F32(data[15], -size, size) ); + setAngularVelocity(new_angv); break; } @@ -1545,9 +1546,10 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, dp->unpackU16(val[VX], "AccX"); dp->unpackU16(val[VY], "AccY"); dp->unpackU16(val[VZ], "AccZ"); - setAngularVelocity( U16_to_F32(val[VX], -64.f, 64.f), - U16_to_F32(val[VY], -64.f, 64.f), - U16_to_F32(val[VZ], -64.f, 64.f)); + new_angv.set(U16_to_F32(val[VX], -64.f, 64.f), + U16_to_F32(val[VY], -64.f, 64.f), + U16_to_F32(val[VZ], -64.f, 64.f)); + setAngularVelocity(new_angv); } break; case OUT_FULL_COMPRESSED: @@ -1591,8 +1593,8 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, if (value & 0x80) { - dp->unpackVector3(vec, "Omega"); - setAngularVelocity(vec); + dp->unpackVector3(new_angv, "Omega"); + setAngularVelocity(new_angv); } if (value & 0x20) diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index ae919f7f7..ddcb84554 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -66,6 +66,7 @@ #include "llsdutil.h" #include "llviewerregion.h" #include "llviewerstats.h" +#include "llviewerstatsrecorder.h" #include "llvovolume.h" #include "llvoavatarself.h" #include "lltoolmgr.h" @@ -113,6 +114,7 @@ extern LLPipeline gPipeline; U32 LLViewerObjectList::sSimulatorMachineIndex = 1; // Not zero deliberately, to speed up index check. std::map LLViewerObjectList::sIPAndPortToIndex; std::map LLViewerObjectList::sIndexAndLocalIDToUUID; +LLStat LLViewerObjectList::sCacheHitRate("object_cache_hits", 128); LLViewerObjectList::LLViewerObjectList() { @@ -384,11 +386,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, U8 compressed_dpbuffer[2048]; LLDataPackerBinaryBuffer compressed_dp(compressed_dpbuffer, 2048); LLDataPacker *cached_dpp = NULL; + LLViewerStatsRecorder& recorder = LLViewerStatsRecorder::instance(); for (i = 0; i < num_objects; i++) { + // timer is unused? LLTimer update_timer; BOOL justCreated = FALSE; + S32 msg_size = 0; if (cached) { @@ -396,6 +401,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, U32 crc; mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, id, i); mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_CRC, crc, i); + msg_size += sizeof(U32) * 2; // Lookup data packer and add this id to cache miss lists if necessary. U8 cache_miss_type = LLViewerRegion::CACHE_MISS_TYPE_NONE; @@ -411,9 +417,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, else { // Cache Miss. - #if LL_RECORD_VIEWER_STATS - LLViewerStatsRecorder::instance()->recordCacheMissEvent(id, update_type, cache_miss_type); - #endif + recorder.cacheMissEvent(id, update_type, cache_miss_type, msg_size); continue; // no data packer, skip this object } @@ -433,8 +437,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mesgsys->getBinaryDataFast(_PREHASH_ObjectData, _PREHASH_Data, compressed_dpbuffer, 0, i); compressed_dp.assignBuffer(compressed_dpbuffer, uncompressed_length); - - if (update_type != OUT_TERSE_IMPROVED) + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { compressed_dp.unpackUUID(fullid, "ID"); compressed_dp.unpackU32(local_id, "LocalID"); @@ -454,9 +457,11 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } } } - else if (update_type != OUT_FULL) + else if (update_type != OUT_FULL) // !compressed, !OUT_FULL ==> OUT_FULL_CACHED only? { mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); + msg_size += sizeof(U32); + getUUIDFromLocal(fullid, local_id, gMessageSystem->getSenderIP(), @@ -467,10 +472,12 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, mNumUnknownUpdates++; } } - else + else // OUT_FULL only? { mesgsys->getUUIDFast(_PREHASH_ObjectData, _PREHASH_FullID, fullid, i); mesgsys->getU32Fast(_PREHASH_ObjectData, _PREHASH_ID, local_id, i); + msg_size += sizeof(LLUUID); + msg_size += sizeof(U32); // llinfos << "Full Update, obj " << local_id << ", global ID" << fullid << "from " << mesgsys->getSender() << llendl; } objectp = findObject(fullid); @@ -515,28 +522,33 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, { if (update_type == OUT_TERSE_IMPROVED) { - // llinfos << "terse update for an unknown object:" << fullid << llendl; + // llinfos << "terse update for an unknown object (compressed):" << fullid << llendl; + recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } } - else if (cached) + else if (cached) // Cache hit only? { } else { if (update_type != OUT_FULL) { - // llinfos << "terse update for an unknown object:" << fullid << llendl; + //llinfos << "terse update for an unknown object:" << fullid << llendl; + recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } mesgsys->getU8Fast(_PREHASH_ObjectData, _PREHASH_PCode, pcode, i); + msg_size += sizeof(U8); + } #ifdef IGNORE_DEAD if (mDeadObjects.find(fullid) != mDeadObjects.end()) { mNumDeadObjectUpdates++; - // llinfos << "update for a dead object:" << fullid << llendl; + //llinfos << "update for a dead object:" << fullid << llendl; + recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } #endif @@ -553,10 +565,14 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, objectp = createObject(pcode, regionp, fullid, local_id, gMessageSystem->getSender()); if (!objectp) { + llinfos << "createObject failure for object: " << fullid << llendl; + recorder.objectUpdateFailure(local_id, update_type, msg_size); continue; } justCreated = TRUE; mNumNewObjects++; + sCacheHitRate.addValue(cached ? 100.f : 0.f); + } @@ -568,15 +584,16 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, bool bCached = false; if (compressed) { - if (update_type != OUT_TERSE_IMPROVED) + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { objectp->mLocalID = local_id; } processUpdateCore(objectp, user_data, i, update_type, &compressed_dp, justCreated); - if (update_type != OUT_TERSE_IMPROVED) + if (update_type != OUT_TERSE_IMPROVED) // OUT_FULL_COMPRESSED only? { bCached = true; - objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); + LLViewerRegion::eCacheUpdateResult result = objectp->mRegionp->cacheFullUpdate(objectp, compressed_dp); + recorder.cacheFullUpdate(local_id, update_type, result, objectp, msg_size); } } else if (cached) @@ -592,11 +609,13 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, } processUpdateCore(objectp, user_data, i, update_type, NULL, justCreated); } - + recorder.objectUpdateEvent(local_id, update_type, objectp, msg_size); objectp->setLastUpdateType(update_type); objectp->setLastUpdateCached(bCached); } + recorder.log(0.2f); + LLVOAvatar::cullAvatarsByPixelArea(); } diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index 5a48656b7..4f67c2691 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -205,6 +205,8 @@ public: std::vector mOrphanChildren; // UUID's of orphaned objects S32 mNumOrphans; + static LLStat sCacheHitRate; + typedef std::vector > vobj_list_t; vobj_list_t mObjects; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index d4cbd7821..fcfbc2e77 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -1442,11 +1442,8 @@ void LLViewerRegion::requestCacheMisses() mCacheDirty = TRUE ; // llinfos << "KILLDEBUG Sent cache miss full " << full_count << " crc " << crc_count << llendl; - #if LL_RECORD_VIEWER_STATS - LLViewerStatsRecorder::instance()->beginObjectUpdateEvents(this); - LLViewerStatsRecorder::instance()->recordRequestCacheMissesEvent(full_count + crc_count); - LLViewerStatsRecorder::instance()->endObjectUpdateEvents(); - #endif + LLViewerStatsRecorder::instance().requestCacheMissesEvent(full_count + crc_count); + LLViewerStatsRecorder::instance().log(0.2f); } void LLViewerRegion::dumpCache() diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 313673721..76b3298ec 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -1887,18 +1887,19 @@ BOOL LLViewerShaderMgr::loadShadersObject() if (success) { gObjectPreviewProgram.mName = "Simple Shader"; - gObjectPreviewProgram.mFeatures.calculatesLighting = true; - gObjectPreviewProgram.mFeatures.calculatesAtmospherics = true; - gObjectPreviewProgram.mFeatures.hasGamma = true; - gObjectPreviewProgram.mFeatures.hasAtmospherics = true; - gObjectPreviewProgram.mFeatures.hasLighting = true; + gObjectPreviewProgram.mFeatures.calculatesLighting = false; + gObjectPreviewProgram.mFeatures.calculatesAtmospherics = false; + gObjectPreviewProgram.mFeatures.hasGamma = false; + gObjectPreviewProgram.mFeatures.hasAtmospherics = false; + gObjectPreviewProgram.mFeatures.hasLighting = false; gObjectPreviewProgram.mFeatures.mIndexedTextureChannels = 0; gObjectPreviewProgram.mFeatures.disableTextureIndex = true; gObjectPreviewProgram.mShaderFiles.clear(); gObjectPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewV.glsl", GL_VERTEX_SHADER_ARB)); - gObjectPreviewProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB)); + gObjectPreviewProgram.mShaderFiles.push_back(make_pair("objects/previewF.glsl", GL_FRAGMENT_SHADER_ARB)); gObjectPreviewProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT]; success = gObjectPreviewProgram.createShader(NULL, NULL); + gObjectPreviewProgram.mFeatures.hasLighting = true; } if (success) diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index eeb96dfa6..16f494715 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -239,6 +239,9 @@ LLViewerStats::LLViewerStats() : mSimSimPhysicsStepMsec("simsimphysicsstepmsec"), mSimSimPhysicsShapeUpdateMsec("simsimphysicsshapeupdatemsec"), mSimSimPhysicsOtherMsec("simsimphysicsothermsec"), + mSimSimAIStepMsec("simsimaistepmsec"), + mSimSimSkippedSilhouetteSteps("simsimskippedsilhouettesteps"), + mSimSimPctSteppedCharacters("simsimpctsteppedcharacters"), mSimAgentMsec("simagentmsec"), mSimImagesMsec("simimagesmsec"), mSimScriptMsec("simscriptmsec"), @@ -250,6 +253,7 @@ LLViewerStats::LLViewerStats() : mSimObjects("simobjects"), mSimActiveObjects("simactiveobjects"), mSimActiveScripts("simactivescripts"), + mSimPctScriptsRun("simpctscriptsrun"), mSimInPPS("siminpps"), mSimOutPPS("simoutpps"), mSimPendingDownloads("simpendingdownloads"), @@ -292,19 +296,19 @@ LLViewerStats::~LLViewerStats() void LLViewerStats::resetStats() { - LLViewerStats::getInstance()->mKBitStat.reset(); - LLViewerStats::getInstance()->mLayersKBitStat.reset(); - LLViewerStats::getInstance()->mObjectKBitStat.reset(); - LLViewerStats::getInstance()->mTextureKBitStat.reset(); - LLViewerStats::getInstance()->mVFSPendingOperations.reset(); - LLViewerStats::getInstance()->mAssetKBitStat.reset(); - LLViewerStats::getInstance()->mPacketsInStat.reset(); - LLViewerStats::getInstance()->mPacketsLostStat.reset(); - LLViewerStats::getInstance()->mPacketsOutStat.reset(); - LLViewerStats::getInstance()->mFPSStat.reset(); - LLViewerStats::getInstance()->mTexturePacketsStat.reset(); - - LLViewerStats::getInstance()->mAgentPositionSnaps.reset(); + LLViewerStats& stats = LLViewerStats::instance(); + stats.mKBitStat.reset(); + stats.mLayersKBitStat.reset(); + stats.mObjectKBitStat.reset(); + stats.mTextureKBitStat.reset(); + stats.mVFSPendingOperations.reset(); + stats.mAssetKBitStat.reset(); + stats.mPacketsInStat.reset(); + stats.mPacketsLostStat.reset(); + stats.mPacketsOutStat.reset(); + stats.mFPSStat.reset(); + stats.mTexturePacketsStat.reset(); + stats.mAgentPositionSnaps.reset(); } @@ -329,55 +333,55 @@ void LLViewerStats::updateFrameStats(const F64 time_diff) { if (mPacketsLostPercentStat.getCurrent() > 5.0) { - incStat(LLViewerStats::ST_LOSS_05_SECONDS, time_diff); + incStat(ST_LOSS_05_SECONDS, time_diff); } if (mSimFPS.getCurrent() < 20.f && mSimFPS.getCurrent() > 0.f) { - incStat(LLViewerStats::ST_SIM_FPS_20_SECONDS, time_diff); + incStat(ST_SIM_FPS_20_SECONDS, time_diff); } if (mSimPhysicsFPS.getCurrent() < 20.f && mSimPhysicsFPS.getCurrent() > 0.f) { - incStat(LLViewerStats::ST_PHYS_FPS_20_SECONDS, time_diff); + incStat(ST_PHYS_FPS_20_SECONDS, time_diff); } if (time_diff >= 0.5) { - incStat(LLViewerStats::ST_FPS_2_SECONDS, time_diff); + incStat(ST_FPS_2_SECONDS, time_diff); } if (time_diff >= 0.125) { - incStat(LLViewerStats::ST_FPS_8_SECONDS, time_diff); + incStat(ST_FPS_8_SECONDS, time_diff); } if (time_diff >= 0.1) { - incStat(LLViewerStats::ST_FPS_10_SECONDS, time_diff); + incStat(ST_FPS_10_SECONDS, time_diff); } if (gFrameCount && mLastTimeDiff > 0.0) { // new "stutter" meter - setStat(LLViewerStats::ST_FPS_DROP_50_RATIO, - (getStat(LLViewerStats::ST_FPS_DROP_50_RATIO) * (F64)(gFrameCount - 1) + + setStat(ST_FPS_DROP_50_RATIO, + (getStat(ST_FPS_DROP_50_RATIO) * (F64)(gFrameCount - 1) + (time_diff >= 2.0 * mLastTimeDiff ? 1.0 : 0.0)) / gFrameCount); // old stats that were never really used - setStat(LLViewerStats::ST_FRAMETIME_JITTER, - (getStat(LLViewerStats::ST_FRAMETIME_JITTER) * (gFrameCount - 1) + + setStat(ST_FRAMETIME_JITTER, + (getStat(ST_FRAMETIME_JITTER) * (gFrameCount - 1) + fabs(mLastTimeDiff - time_diff) / mLastTimeDiff) / gFrameCount); F32 average_frametime = gRenderStartTime.getElapsedTimeF32() / (F32)gFrameCount; - setStat(LLViewerStats::ST_FRAMETIME_SLEW, - (getStat(LLViewerStats::ST_FRAMETIME_SLEW) * (gFrameCount - 1) + + setStat(ST_FRAMETIME_SLEW, + (getStat(ST_FRAMETIME_SLEW) * (gFrameCount - 1) + fabs(average_frametime - time_diff) / average_frametime) / gFrameCount); F32 max_bandwidth = gViewerThrottle.getMaxBandwidth(); F32 delta_bandwidth = gViewerThrottle.getCurrentBandwidth() - max_bandwidth; - setStat(LLViewerStats::ST_DELTA_BANDWIDTH, delta_bandwidth / 1024.f); + setStat(ST_DELTA_BANDWIDTH, delta_bandwidth / 1024.f); - setStat(LLViewerStats::ST_MAX_BANDWIDTH, max_bandwidth / 1024.f); + setStat(ST_MAX_BANDWIDTH, max_bandwidth / 1024.f); } @@ -571,25 +575,20 @@ F32 gWorstLandCompression = 0.f, gWorstWaterCompression = 0.f; U32 gTotalWorldBytes = 0, gTotalObjectBytes = 0, gTotalTextureBytes = 0, gSimPingCount = 0; U32 gObjectBits = 0; F32 gAvgSimPing = 0.f; -U32 gTotalTextureBytesPerBoostLevel[LLViewerTexture::MAX_GL_IMAGE_CATEGORY] = {0}; +U32 gTotalTextureBytesPerBoostLevel[LLGLTexture::MAX_GL_IMAGE_CATEGORY] = {0}; extern U32 gVisCompared; extern U32 gVisTested; -std::map gDebugTimers; -std::map gDebugTimerLabel; +LLFrameTimer gTextureTimer; -void init_statistics() -{ - // Label debug timers - gDebugTimerLabel[0] = "Texture"; -} - -void update_statistics(U32 frame_count) +void update_statistics() { gTotalWorldBytes += gVLManager.getTotalBytes(); gTotalObjectBytes += gObjectBits / 8; + LLViewerStats& stats = LLViewerStats::instance(); + // make sure we have a valid time delta for this frame if (gFrameIntervalSeconds > 0.f) { @@ -606,51 +605,51 @@ void update_statistics(U32 frame_count) LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TOOLBOX_SECONDS, gFrameIntervalSeconds); } } - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_ENABLE_VBO, (F64)gSavedSettings.getBOOL("RenderVBOEnable")); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gPipeline.getLightingDetail()); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_DRAW_DIST, (F64)gSavedSettings.getF32("RenderFarClip")); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CHAT_BUBBLES, (F64)gSavedSettings.getBOOL("UseChatBubbles")); + stats.setStat(LLViewerStats::ST_ENABLE_VBO, (F64)gSavedSettings.getBOOL("RenderVBOEnable")); + stats.setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gPipeline.getLightingDetail()); + stats.setStat(LLViewerStats::ST_DRAW_DIST, (F64)gSavedSettings.getF32("RenderFarClip")); + stats.setStat(LLViewerStats::ST_CHAT_BUBBLES, (F64)gSavedSettings.getBOOL("UseChatBubbles")); #if 0 // 1.9.2 LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_OBJECTS, (F64)gSavedSettings.getS32("VertexShaderLevelObject")); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_AVATAR, (F64)gSavedSettings.getBOOL("VertexShaderLevelAvatar")); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_ENVIRONMENT, (F64)gSavedSettings.getBOOL("VertexShaderLevelEnvironment")); #endif - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime("Frame")); + stats.setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime("Frame")); F64 idle_secs = gDebugView->mFastTimerView->getTime("Idle"); F64 network_secs = gDebugView->mFastTimerView->getTime("Network"); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_UPDATE_SECS, idle_secs - network_secs); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_NETWORK_SECS, network_secs); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime("Update Images")); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime("Sort Draw State")); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime("Geometry")); + stats.setStat(LLViewerStats::ST_UPDATE_SECS, idle_secs - network_secs); + stats.setStat(LLViewerStats::ST_NETWORK_SECS, network_secs); + stats.setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime("Update Images")); + stats.setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime("Sort Draw State")); + stats.setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime("Geometry")); LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); if (cdp) { - LLViewerStats::getInstance()->mSimPingStat.addValue(cdp->getPingDelay()); + stats.mSimPingStat.addValue(cdp->getPingDelay()); gAvgSimPing = ((gAvgSimPing * (F32)gSimPingCount) + (F32)(cdp->getPingDelay())) / ((F32)gSimPingCount + 1); gSimPingCount++; } else { - LLViewerStats::getInstance()->mSimPingStat.addValue(10000); + stats.mSimPingStat.addValue(10000); } - LLViewerStats::getInstance()->mFPSStat.addValue(1); + stats.mFPSStat.addValue(1); F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits()); - LLViewerStats::getInstance()->mLayersKBitStat.addValue(layer_bits/1024.f); - LLViewerStats::getInstance()->mObjectKBitStat.addValue(gObjectBits/1024.f); - LLViewerStats::getInstance()->mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending()); - LLViewerStats::getInstance()->mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f); + stats.mLayersKBitStat.addValue(layer_bits/1024.f); + stats.mObjectKBitStat.addValue(gObjectBits/1024.f); + stats.mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending()); + stats.mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f); gTransferManager.resetTransferBitsIn(LLTCT_ASSET); if (LLAppViewer::getTextureFetch()->getNumRequests() == 0) { - gDebugTimers[0].pause(); + gTextureTimer.pause(); } else { - gDebugTimers[0].unpause(); + gTextureTimer.unpause(); } { @@ -662,7 +661,7 @@ void update_statistics(U32 frame_count) visible_avatar_frames = 1.f; avg_visible_avatars = (avg_visible_avatars * (F32)(visible_avatar_frames - 1.f) + visible_avatars) / visible_avatar_frames; } - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_VISIBLE_AVATARS, (F64)avg_visible_avatars); + stats.setStat(LLViewerStats::ST_VISIBLE_AVATARS, (F64)avg_visible_avatars); } LLWorld::getInstance()->updateNetStats(); LLWorld::getInstance()->requestCacheMisses(); @@ -672,14 +671,14 @@ void update_statistics(U32 frame_count) gObjectBits = 0; // gDecodedBits = 0; - //Update bandwidth stats often because texture fetch relies on them. + // Only update texture stats periodically so that they are less noisy { - static const F32 texture_stats_freq = 0.1f; + static const F32 texture_stats_freq = 10.f; static LLFrameTimer texture_stats_timer; if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq) { - LLViewerStats::getInstance()->mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f); - LLViewerStats::getInstance()->mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets); + stats.mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f); + stats.mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets); LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerTextureList::sTextureBits/1024.f/texture_stats_timer.getElapsedTimeF32()); gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8; LLViewerTextureList::sTextureBits = 0; @@ -693,7 +692,7 @@ void update_statistics(U32 frame_count) static LLFrameTimer mem_stats_timer; if (mem_stats_timer.getElapsedTimeF32() >= mem_stats_freq) { - LLViewerStats::getInstance()->mMallocStat.addValue(SGMemStat::getMalloc()/1024.f/1024.f); + stats.mMallocStat.addValue(SGMemStat::getMalloc()/1024.f/1024.f); mem_stats_timer.reset(); } } @@ -813,6 +812,7 @@ void send_stats() system["gpu_class"] = (S32)LLFeatureManager::getInstance()->getGPUClass(); system["gpu_vendor"] = gGLManager.mGLVendorShort; system["gpu_version"] = gGLManager.mDriverVersionVendorString; + system["opengl_version"] = gGLManager.mGLVersionString; LLSD &download = body["downloads"]; @@ -859,10 +859,7 @@ void send_stats() S32 window_height = gViewerWindow->getWindowHeightRaw(); S32 window_size = (window_width * window_height) / 1024; misc["string_1"] = llformat("%d", window_size); - if (gDebugTimers.find(0) != gDebugTimers.end() && gFrameTimeSeconds > 0) - { - misc["string_2"] = llformat("Texture Time: %.2f, Total Time: %.2f", gDebugTimers[0].getElapsedTimeF32(), gFrameTimeSeconds); - } + misc["string_2"] = llformat("Texture Time: %.2f, Total Time: %.2f", gTextureTimer.getElapsedTimeF32(), gFrameTimeSeconds); // misc["int_1"] = LLSD::Integer(gSavedSettings.getU32("RenderQualityPerformance")); // Steve: 1.21 // misc["int_2"] = LLSD::Integer(gFrameStalls); // Steve: 1.21 diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index 93d482da7..264b02bf2 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -39,88 +39,91 @@ class LLViewerStats : public LLSingleton { public: - LLStat mKBitStat; - LLStat mLayersKBitStat; - LLStat mObjectKBitStat; - LLStat mAssetKBitStat; - LLStat mTextureKBitStat; - LLStat mVFSPendingOperations; - LLStat mObjectsDrawnStat; - LLStat mObjectsCulledStat; - LLStat mObjectsTestedStat; - LLStat mObjectsComparedStat; - LLStat mObjectsOccludedStat; - LLStat mFPSStat; - LLStat mPacketsInStat; - LLStat mPacketsLostStat; - LLStat mPacketsOutStat; - LLStat mPacketsLostPercentStat; - LLStat mTexturePacketsStat; - LLStat mActualInKBitStat; // From the packet ring (when faking a bad connection) - LLStat mActualOutKBitStat; // From the packet ring (when faking a bad connection) - LLStat mTrianglesDrawnStat; - LLStat mMallocStat; + LLStat mKBitStat, + mLayersKBitStat, + mObjectKBitStat, + mAssetKBitStat, + mTextureKBitStat, + mVFSPendingOperations, + mObjectsDrawnStat, + mObjectsCulledStat, + mObjectsTestedStat, + mObjectsComparedStat, + mObjectsOccludedStat, + mFPSStat, + mPacketsInStat, + mPacketsLostStat, + mPacketsOutStat, + mPacketsLostPercentStat, + mTexturePacketsStat, + mActualInKBitStat, // From the packet ring (when faking a bad connection) + mActualOutKBitStat, // From the packet ring (when faking a bad connection) + mTrianglesDrawnStat, + mMallocStat; // Simulator stats - LLStat mSimTimeDilation; + LLStat mSimTimeDilation, - LLStat mSimFPS; - LLStat mSimPhysicsFPS; - LLStat mSimAgentUPS; - LLStat mSimScriptEPS; + mSimFPS, + mSimPhysicsFPS, + mSimAgentUPS, + mSimScriptEPS, - LLStat mSimFrameMsec; - LLStat mSimNetMsec; - LLStat mSimSimOtherMsec; - LLStat mSimSimPhysicsMsec; + mSimFrameMsec, + mSimNetMsec, + mSimSimOtherMsec, + mSimSimPhysicsMsec, - LLStat mSimSimPhysicsStepMsec; - LLStat mSimSimPhysicsShapeUpdateMsec; - LLStat mSimSimPhysicsOtherMsec; + mSimSimPhysicsStepMsec, + mSimSimPhysicsShapeUpdateMsec, + mSimSimPhysicsOtherMsec, + mSimSimAIStepMsec, + mSimSimSkippedSilhouetteSteps, + mSimSimPctSteppedCharacters, - LLStat mSimAgentMsec; - LLStat mSimImagesMsec; - LLStat mSimScriptMsec; - LLStat mSimSpareMsec; - LLStat mSimSleepMsec; - LLStat mSimPumpIOMsec; + mSimAgentMsec, + mSimImagesMsec, + mSimScriptMsec, + mSimSpareMsec, + mSimSleepMsec, + mSimPumpIOMsec, - LLStat mSimMainAgents; - LLStat mSimChildAgents; - LLStat mSimObjects; - LLStat mSimActiveObjects; - LLStat mSimActiveScripts; + mSimMainAgents, + mSimChildAgents, + mSimObjects, + mSimActiveObjects, + mSimActiveScripts, + mSimPctScriptsRun, - LLStat mSimInPPS; - LLStat mSimOutPPS; - LLStat mSimPendingDownloads; - LLStat mSimPendingUploads; - LLStat mSimPendingLocalUploads; - LLStat mSimTotalUnackedBytes; + mSimInPPS, + mSimOutPPS, + mSimPendingDownloads, + mSimPendingUploads, + mSimPendingLocalUploads, + mSimTotalUnackedBytes, - LLStat mPhysicsPinnedTasks; - LLStat mPhysicsLODTasks; - LLStat mPhysicsMemoryAllocated; + mPhysicsPinnedTasks, + mPhysicsLODTasks, + mPhysicsMemoryAllocated, - LLStat mSimPingStat; + mSimPingStat, - LLStat mNumImagesStat; - LLStat mNumRawImagesStat; - LLStat mGLTexMemStat; - LLStat mGLBoundMemStat; - LLStat mRawMemStat; - LLStat mFormattedMemStat; + mNumImagesStat, + mNumRawImagesStat, + mGLTexMemStat, + mGLBoundMemStat, + mRawMemStat, + mFormattedMemStat, - LLStat mNumObjectsStat; - LLStat mNumActiveObjectsStat; - LLStat mNumNewObjectsStat; - LLStat mNumSizeCulledStat; - LLStat mNumVisCulledStat; + mNumObjectsStat, + mNumActiveObjectsStat, + mNumNewObjectsStat, + mNumSizeCulledStat, + mNumVisCulledStat; void resetStats(); public: - // If you change this, please also add a corresponding text label - // in statTypeToText in llviewerstats.cpp + // If you change this, please also add a corresponding text label in llviewerstats.cpp enum EStatType { ST_VERSION = 0, @@ -251,7 +254,7 @@ public: inline F32 getStdDev() const { const F32 mean = getMean(); - return (mCount == 0) ? 0.f : sqrt( mSumOfSquares/mCount - (mean * mean) ); + return (mCount < 2) ? 0.f : sqrt(llmax(0.f,mSumOfSquares/mCount - (mean * mean))); } inline U32 getCount() const @@ -291,14 +294,12 @@ private: static const F32 SEND_STATS_PERIOD = 300.0f; // The following are from (older?) statistics code found in appviewer. -void init_statistics(); void reset_statistics(); void output_statistics(void*); -void update_statistics(U32 frame_count); +void update_statistics(); void send_stats(); -extern std::map gDebugTimers; -extern std::map gDebugTimerLabel; +extern LLFrameTimer gTextureTimer; extern U32 gTotalTextureBytes; extern U32 gTotalObjectBytes; extern U32 gTotalTextureBytesPerBoostLevel[] ; diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp index e9d21b484..91e485d01 100644 --- a/indra/newview/llviewerstatsrecorder.cpp +++ b/indra/newview/llviewerstatsrecorder.cpp @@ -27,7 +27,6 @@ #include "llviewerprecompiledheaders.h" #include "llviewerstatsrecorder.h" -#if LL_RECORD_VIEWER_STATS #include "llfile.h" #include "llviewerregion.h" @@ -45,9 +44,8 @@ LLViewerStatsRecorder* LLViewerStatsRecorder::sInstance = NULL; LLViewerStatsRecorder::LLViewerStatsRecorder() : mObjectCacheFile(NULL), mTimer(), - mRegionp(NULL), - mStartTime(0.f), - mProcessingTime(0.f) + mStartTime(0.0), + mLastSnapshotTime(0.0) { if (NULL != sInstance) { @@ -61,112 +59,77 @@ LLViewerStatsRecorder::~LLViewerStatsRecorder() { if (mObjectCacheFile != NULL) { + // last chance snapshot + writeToLog(0.f); LLFile::close(mObjectCacheFile); mObjectCacheFile = NULL; } } -// static -void LLViewerStatsRecorder::initClass() -{ - sInstance = new LLViewerStatsRecorder(); -} - -// static -void LLViewerStatsRecorder::cleanupClass() -{ - delete sInstance; - sInstance = NULL; -} - - -void LLViewerStatsRecorder::initStatsRecorder(LLViewerRegion *regionp) -{ - if (mObjectCacheFile == NULL) - { - mStartTime = LLTimer::getTotalTime(); - mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb"); - if (mObjectCacheFile) - { // Write column headers - std::ostringstream data_msg; - data_msg << "EventTime, " - << "ProcessingTime, " - << "CacheHits, " - << "CacheFullMisses, " - << "CacheCrcMisses, " - << "FullUpdates, " - << "TerseUpdates, " - << "CacheMissRequests, " - << "CacheMissResponses, " - << "CacheUpdateDupes, " - << "CacheUpdateChanges, " - << "CacheUpdateAdds, " - << "CacheUpdateReplacements, " - << "UpdateFailures" - << "\n"; - - fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); - } - } -} - -void LLViewerStatsRecorder::beginObjectUpdateEvents(LLViewerRegion *regionp) -{ - initStatsRecorder(regionp); - mRegionp = regionp; - mProcessingTime = LLTimer::getTotalTime(); - clearStats(); -} - void LLViewerStatsRecorder::clearStats() { mObjectCacheHitCount = 0; + mObjectCacheHitSize = 0; mObjectCacheMissFullCount = 0; + mObjectCacheMissFullSize = 0; mObjectCacheMissCrcCount = 0; + mObjectCacheMissCrcSize = 0; mObjectFullUpdates = 0; + mObjectFullUpdatesSize = 0; mObjectTerseUpdates = 0; + mObjectTerseUpdatesSize = 0; mObjectCacheMissRequests = 0; mObjectCacheMissResponses = 0; + mObjectCacheMissResponsesSize = 0; mObjectCacheUpdateDupes = 0; mObjectCacheUpdateChanges = 0; mObjectCacheUpdateAdds = 0; mObjectCacheUpdateReplacements = 0; mObjectUpdateFailures = 0; + mObjectUpdateFailuresSize = 0; + mTextureFetchSize = 0; } -void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type) +void LLViewerStatsRecorder::recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type, S32 msg_size) { mObjectUpdateFailures++; + mObjectUpdateFailuresSize += msg_size; } -void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type) +void LLViewerStatsRecorder::recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type, S32 msg_size) { if (LLViewerRegion::CACHE_MISS_TYPE_FULL == cache_miss_type) { mObjectCacheMissFullCount++; + mObjectCacheMissFullSize += msg_size; } else { mObjectCacheMissCrcCount++; + mObjectCacheMissCrcSize += msg_size; } } -void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp) +void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp, S32 msg_size) { switch (update_type) { case OUT_FULL: mObjectFullUpdates++; + mObjectFullUpdatesSize += msg_size; break; case OUT_TERSE_IMPROVED: mObjectTerseUpdates++; + mObjectTerseUpdatesSize += msg_size; break; case OUT_FULL_COMPRESSED: mObjectCacheMissResponses++; + mObjectCacheMissResponsesSize += msg_size; break; case OUT_FULL_CACHED: mObjectCacheHitCount++; + mObjectCacheHitSize += msg_size; break; default: llwarns << "Unknown update_type" << llendl; @@ -174,7 +137,7 @@ void LLViewerStatsRecorder::recordObjectUpdateEvent(U32 local_id, const EObjectU }; } -void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp) +void LLViewerStatsRecorder::recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp, S32 msg_size) { switch (update_result) { @@ -201,9 +164,15 @@ void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count) mObjectCacheMissRequests += count; } -void LLViewerStatsRecorder::endObjectUpdateEvents() +void LLViewerStatsRecorder::writeToLog( F32 interval ) { - llinfos << "ILX: " + F64 delta_time = LLTimer::getTotalSeconds() - mLastSnapshotTime; + S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures; + + if ( delta_time < interval || total_objects == 0) return; + + mLastSnapshotTime = LLTimer::getTotalSeconds(); + lldebugs << "ILX: " << mObjectCacheHitCount << " hits, " << mObjectCacheMissFullCount << " full misses, " << mObjectCacheMissCrcCount << " crc misses, " @@ -218,41 +187,81 @@ void LLViewerStatsRecorder::endObjectUpdateEvents() << mObjectUpdateFailures << " update failures" << llendl; - S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures; - if (mObjectCacheFile != NULL && - total_objects > 0) + if (mObjectCacheFile == NULL) { - std::ostringstream data_msg; - F32 processing32 = (F32) ((LLTimer::getTotalTime() - mProcessingTime) / 1000.0); + mStartTime = LLTimer::getTotalSeconds(); + mObjectCacheFile = LLFile::fopen(STATS_FILE_NAME, "wb"); + if (mObjectCacheFile) + { // Write column headers + std::ostringstream data_msg; + data_msg << "EventTime(ms)\t" + << "Cache Hits\t" + << "Cache Full Misses\t" + << "Cache Crc Misses\t" + << "Full Updates\t" + << "Terse Updates\t" + << "Cache Miss Requests\t" + << "Cache Miss Responses\t" + << "Cache Update Dupes\t" + << "Cache Update Changes\t" + << "Cache Update Adds\t" + << "Cache Update Replacements\t" + << "Update Failures\t" + << "Cache Hits bps\t" + << "Cache Full Misses bps\t" + << "Cache Crc Misses bps\t" + << "Full Updates bps\t" + << "Terse Updates bps\t" + << "Cache Miss Responses bps\t" + << "Texture Fetch bps\t" + << "\n"; - data_msg << getTimeSinceStart() - << ", " << processing32 - << ", " << mObjectCacheHitCount - << ", " << mObjectCacheMissFullCount - << ", " << mObjectCacheMissCrcCount - << ", " << mObjectFullUpdates - << ", " << mObjectTerseUpdates - << ", " << mObjectCacheMissRequests - << ", " << mObjectCacheMissResponses - << ", " << mObjectCacheUpdateDupes - << ", " << mObjectCacheUpdateChanges - << ", " << mObjectCacheUpdateAdds - << ", " << mObjectCacheUpdateReplacements - << ", " << mObjectUpdateFailures - << "\n"; - - fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); + fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); + } + else + { + llwarns << "Couldn't open " << STATS_FILE_NAME << " for logging." << llendl; + return; + } } + std::ostringstream data_msg; + + data_msg << getTimeSinceStart() + << "\t " << mObjectCacheHitCount + << "\t" << mObjectCacheMissFullCount + << "\t" << mObjectCacheMissCrcCount + << "\t" << mObjectFullUpdates + << "\t" << mObjectTerseUpdates + << "\t" << mObjectCacheMissRequests + << "\t" << mObjectCacheMissResponses + << "\t" << mObjectCacheUpdateDupes + << "\t" << mObjectCacheUpdateChanges + << "\t" << mObjectCacheUpdateAdds + << "\t" << mObjectCacheUpdateReplacements + << "\t" << mObjectUpdateFailures + << "\t" << (mObjectCacheHitSize * 8 / delta_time) + << "\t" << (mObjectCacheMissFullSize * 8 / delta_time) + << "\t" << (mObjectCacheMissCrcSize * 8 / delta_time) + << "\t" << (mObjectFullUpdatesSize * 8 / delta_time) + << "\t" << (mObjectTerseUpdatesSize * 8 / delta_time) + << "\t" << (mObjectCacheMissResponsesSize * 8 / delta_time) + << "\t" << (mTextureFetchSize * 8 / delta_time) + << "\n"; + + fwrite(data_msg.str().c_str(), 1, data_msg.str().size(), mObjectCacheFile ); clearStats(); } F32 LLViewerStatsRecorder::getTimeSinceStart() { - return (F32) ((LLTimer::getTotalTime() - mStartTime) / 1000.0); + return (F32) (LLTimer::getTotalSeconds() - mStartTime); } -#endif +void LLViewerStatsRecorder::recordTextureFetch( S32 msg_size ) +{ + mTextureFetchSize += msg_size; +} diff --git a/indra/newview/llviewerstatsrecorder.h b/indra/newview/llviewerstatsrecorder.h index 612ac380f..d1744f491 100644 --- a/indra/newview/llviewerstatsrecorder.h +++ b/indra/newview/llviewerstatsrecorder.h @@ -35,63 +35,111 @@ #define LL_RECORD_VIEWER_STATS 0 -#if LL_RECORD_VIEWER_STATS #include "llframetimer.h" #include "llviewerobject.h" #include "llviewerregion.h" class LLMutex; -class LLViewerRegion; class LLViewerObject; -class LLViewerStatsRecorder +class LLViewerStatsRecorder : public LLSingleton { public: + LOG_CLASS(LLViewerStatsRecorder); LLViewerStatsRecorder(); ~LLViewerStatsRecorder(); - static void initClass(); - static void cleanupClass(); - static LLViewerStatsRecorder* instance() {return sInstance; } + void objectUpdateFailure(U32 local_id, const EObjectUpdateType update_type, S32 msg_size) + { +#if LL_RECORD_VIEWER_STATS + recordObjectUpdateFailure(local_id, update_type, msg_size); +#endif + } - void initStatsRecorder(LLViewerRegion *regionp); + void cacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type, S32 msg_size) + { +#if LL_RECORD_VIEWER_STATS + recordCacheMissEvent(local_id, update_type, cache_miss_type, msg_size); +#endif + } - void beginObjectUpdateEvents(LLViewerRegion *regionp); - void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type); - void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type); - void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp); - void recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp); - void recordRequestCacheMissesEvent(S32 count); - void endObjectUpdateEvents(); + void objectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp, S32 msg_size) + { +#if LL_RECORD_VIEWER_STATS + recordObjectUpdateEvent(local_id, update_type, objectp, msg_size); +#endif + } + + void cacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp, S32 msg_size) + { +#if LL_RECORD_VIEWER_STATS + recordCacheFullUpdate(local_id, update_type, update_result, objectp, msg_size); +#endif + } + + void requestCacheMissesEvent(S32 count) + { +#if LL_RECORD_VIEWER_STATS + recordRequestCacheMissesEvent(count); +#endif + } + + void textureFetch(S32 msg_size) + { +#if LL_RECORD_VIEWER_STATS + recordTextureFetch(msg_size); +#endif + } + + void log(F32 interval) + { +#if LL_RECORD_VIEWER_STATS + writeToLog(interval); +#endif + } F32 getTimeSinceStart(); private: + void recordObjectUpdateFailure(U32 local_id, const EObjectUpdateType update_type, S32 msg_size); + void recordCacheMissEvent(U32 local_id, const EObjectUpdateType update_type, U8 cache_miss_type, S32 msg_size); + void recordObjectUpdateEvent(U32 local_id, const EObjectUpdateType update_type, LLViewerObject * objectp, S32 msg_size); + void recordCacheFullUpdate(U32 local_id, const EObjectUpdateType update_type, LLViewerRegion::eCacheUpdateResult update_result, LLViewerObject* objectp, S32 msg_size); + void recordRequestCacheMissesEvent(S32 count); + void recordTextureFetch(S32 msg_size); + void writeToLog(F32 interval); + static LLViewerStatsRecorder* sInstance; LLFILE * mObjectCacheFile; // File to write data into LLFrameTimer mTimer; - LLViewerRegion* mRegionp; F64 mStartTime; - F64 mProcessingTime; + F64 mLastSnapshotTime; S32 mObjectCacheHitCount; + S32 mObjectCacheHitSize; S32 mObjectCacheMissFullCount; + S32 mObjectCacheMissFullSize; S32 mObjectCacheMissCrcCount; + S32 mObjectCacheMissCrcSize; S32 mObjectFullUpdates; + S32 mObjectFullUpdatesSize; S32 mObjectTerseUpdates; + S32 mObjectTerseUpdatesSize; S32 mObjectCacheMissRequests; S32 mObjectCacheMissResponses; + S32 mObjectCacheMissResponsesSize; S32 mObjectCacheUpdateDupes; S32 mObjectCacheUpdateChanges; S32 mObjectCacheUpdateAdds; S32 mObjectCacheUpdateReplacements; S32 mObjectUpdateFailures; + S32 mObjectUpdateFailuresSize; + S32 mTextureFetchSize; void clearStats(); }; -#endif // LL_RECORD_VIEWER_STATS #endif // LLVIEWERSTATSRECORDER_H diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 981421b99..d57a05a46 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -980,14 +980,6 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) break; } } - //if (fetch_count == 0) - //{ - // gDebugTimers[0].pause(); - //} - //else - //{ - // gDebugTimers[0].unpause(); - //} return image_op_timer.getElapsedTimeF32(); } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ec152271b..fb3ccab1a 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -318,27 +318,24 @@ public: static const LLCachedControl debug_show_time("DebugShowTime"); if (debug_show_time) { - const U32 y_inc2 = 15; - for (std::map::reverse_iterator iter = gDebugTimers.rbegin(); - iter != gDebugTimers.rend(); ++iter) { - S32 idx = iter->first; - LLFrameTimer& timer = iter->second; + const U32 y_inc2 = 15; + LLFrameTimer& timer = gTextureTimer; F32 time = timer.getElapsedTimeF32(); S32 hours = (S32)(time / (60*60)); S32 mins = (S32)((time - hours*(60*60)) / 60); S32 secs = (S32)((time - hours*(60*60) - mins*60)); - std::string label = gDebugTimerLabel[idx]; - if (label.empty()) label = llformat("Debug: %d", idx); - addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2; + addText(xpos, ypos, llformat("Texture: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc2; } + { F32 time = gFrameTimeSeconds; S32 hours = (S32)(time / (60*60)); S32 mins = (S32)((time - hours*(60*60)) / 60); S32 secs = (S32)((time - hours*(60*60) - mins*60)); addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc; } + } #if LL_WINDOWS static const LLCachedControl debug_show_memory("DebugShowMemory"); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 8108d2bd3..fee8c5253 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -567,10 +567,15 @@ SHClientTagMgr::SHClientTagMgr() gSavedSettings.getControl("AscentFriendColor")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); gSavedSettings.getControl("AscentMutedColor")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); + //Following group of settings all actually manipulate the tag cache for agent avatar. Even if the tag system is 'disabled', we still allow an + //entry to exist for the agent avatar. gSavedSettings.getControl("AscentUseCustomTag")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); gSavedSettings.getControl("AscentCustomTagColor")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); gSavedSettings.getControl("AscentCustomTagLabel")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); + //And because there can be an entry for the self avatar, always perform this as well. + gSavedSettings.getControl("AscentShowSelfTag")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); + if(!getIsEnabled()) return; @@ -578,12 +583,14 @@ SHClientTagMgr::SHClientTagMgr() fetchDefinitions(); parseDefinitions(); - //These only matter to the agent avatar. Don't iterate over everything. - gSavedSettings.getControl("AscentUseTag")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); + //Tags for other users only exist if the tag system is enabled. No point in registering this callback if non-agent avatars can't have tags. + gSavedSettings.getControl("AscentShowOthersTag")->getSignal()->connect(boost::bind(&LLVOAvatar::invalidateNameTags)); + + //Update the cached tag for the agent avatar. AscentReportClientUUID dictates what tag the agent avatar sees on their self. gSavedSettings.getControl("AscentReportClientUUID")->getSignal()->connect(boost::bind(&SHClientTagMgr::updateAgentAvatarTag, this)); - //Fire off a AgentSetAppearance update if these change. - gSavedSettings.getControl("AscentUseTag")->getSignal()->connect(boost::bind(&LLAgent::sendAgentSetAppearance, &gAgent)); + //Fire off a AgentSetAppearance update if these change. Essentially, forces the new clientid (or lack thereof) to be sent off to the server for others to see. + gSavedSettings.getControl("AscentBroadcastTag")->getSignal()->connect(boost::bind(&LLAgent::sendAgentSetAppearance, &gAgent)); gSavedSettings.getControl("AscentReportClientUUID")->getSignal()->connect(boost::bind(&LLAgent::sendAgentSetAppearance, &gAgent)); } @@ -682,7 +689,6 @@ const LLSD SHClientTagMgr::generateClientTag(const LLVOAvatar* pAvatar) const if (pAvatar->isSelf()) { - static const LLCachedControl ascent_use_tag("AscentUseTag",true); static const LLCachedControl ascent_use_custom_tag("AscentUseCustomTag", false); static const LLCachedControl ascent_custom_tag_color("AscentCustomTagColor", LLColor4(.5f,1.f,.25f,1.f)); static const LLCachedControl ascent_custom_tag_label("AscentCustomTagLabel","custom"); @@ -699,7 +705,7 @@ const LLSD SHClientTagMgr::generateClientTag(const LLVOAvatar* pAvatar) const { return LLSD(); } - else if (ascent_use_tag) + else { id.set(ascent_report_client_uuid,false); } @@ -796,24 +802,32 @@ void SHClientTagMgr::updateAvatarTag(LLVOAvatar* pAvatar) if(new_tag.isUndefined()) mAvatarTags.erase(id); else - mAvatarTags.insert(std::pair(id, new_tag)); + mAvatarTags[id]=new_tag; pAvatar->clearNameTag(); //LLVOAvatar::idleUpdateNameTag will pick up on mNameString being cleared. } } const std::string SHClientTagMgr::getClientName(const LLVOAvatar* pAvatar, bool is_friend) const { static LLCachedControl ascent_show_friends_tag("AscentShowFriendsTag", false); + static LLCachedControl ascent_show_self_tag("AscentShowSelfTag", false); + static LLCachedControl ascent_show_others_tag("AscentShowOthersTag", false); if(is_friend && ascent_show_friends_tag) return "Friend"; else { - LLSD tag; - std::map::const_iterator it = mAvatarTags.find(pAvatar->getID()); - if(it != mAvatarTags.end()) + if((!pAvatar->isSelf() && ascent_show_others_tag) || + (pAvatar->isSelf() && ascent_show_self_tag)) { - tag = it->second.get("name"); + LLSD tag; + std::map::const_iterator it = mAvatarTags.find(pAvatar->getID()); + if(it != mAvatarTags.end()) + { + tag = it->second.get("name"); + } + return tag.asString(); } - return tag.asString(); + else + return std::string(); } } const LLUUID SHClientTagMgr::getClientID(const LLVOAvatar* pAvatar) const @@ -3222,7 +3236,13 @@ void LLVOAvatar::idleUpdateNameTagText(BOOL new_name) while ((index = line.find("%f")) != std::string::npos) line.replace(index, 2, firstnameText); while ((index = line.find("%l")) != std::string::npos) - line.replace(index, 2, lastnameText); + { + llinfos << "'" << line.substr(index) << "'" << llendl; + if(lastnameText.empty() && line[index+2] == ' ') //Entire displayname string crammed into firstname + line.replace(index, 3, ""); //so eat the extra space. + else + line.replace(index, 2, lastnameText); + } while ((index = line.find("%g")) != std::string::npos) line.replace(index, 2, groupText); while ((index = line.find("%t")) != std::string::npos) diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index 78daf033c..566f773b1 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -2589,7 +2589,7 @@ bool LLVOAvatarSelf::sendAppearanceMessage(LLMessageSystem *mesgsys) const { LLTextureEntry* entry = getTE((U8) index); texture_id[index] = entry->getID(); - if (SHClientTagMgr::instance().getIsEnabled() && index == 0 && gSavedSettings.getBOOL("AscentUseTag")) + if (SHClientTagMgr::instance().getIsEnabled() && index == 0 && gSavedSettings.getBOOL("AscentBroadcastTag")) entry->setID(LLUUID(gSavedSettings.getString("AscentReportClientUUID"))); else entry->setID(IMG_DEFAULT_AVATAR); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index bd3fb344a..2af2dc14b 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -926,20 +926,32 @@ void LLVOVolume::sculpt() if (discard_level > max_discard) discard_level = max_discard; // clamp to the best we can do - S32 current_discard = getVolume()->getSculptLevel(); + S32 current_discard = getVolume()->getSculptLevel() ; if(current_discard < -2) { - llwarns << "WARNING!!: Current discard of sculpty at " << current_discard - << " is less than -2." << llendl; + static S32 low_sculpty_discard_warning_count = 100; + if (++low_sculpty_discard_warning_count >= 100) + { // Log first time, then every 100 afterwards otherwise this can flood the logs + llwarns << "WARNING!!: Current discard for sculpty " << mSculptTexture->getID() + << " at " << current_discard + << " is less than -2." << llendl; + low_sculpty_discard_warning_count = 0; + } // corrupted volume... don't update the sculpty return; } else if (current_discard > MAX_DISCARD_LEVEL) { - llwarns << "WARNING!!: Current discard of sculpty at " << current_discard - << " is more than than allowed max of " << MAX_DISCARD_LEVEL << llendl; - + static S32 high_sculpty_discard_warning_count = 100; + if (++high_sculpty_discard_warning_count >= 100) + { // Log first time, then every 100 afterwards otherwise this can flood the logs + llwarns << "WARNING!!: Current discard for sculpty " << mSculptTexture->getID() + << " at " << current_discard + << " is more than than allowed max of " << MAX_DISCARD_LEVEL << llendl; + high_sculpty_discard_warning_count = 0; + } + // corrupted volume... don't update the sculpty return; } diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 88b9f9c20..fff60e992 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -489,7 +489,10 @@ void LLPipeline::init() //gSavedSettings.getControl("RenderDelayVBUpdate")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("UseOcclusion")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("VertexShaderEnable")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderDeferred")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); gSavedSettings.getControl("RenderFSAASamples")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("RenderAvatarVP")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); + gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLPipeline::refreshCachedSettings)); } LLPipeline::~LLPipeline() @@ -631,7 +634,16 @@ void LLPipeline::resizeScreenTexture() GLuint resX = gViewerWindow->getWorldViewWidthRaw(); GLuint resY = gViewerWindow->getWorldViewHeightRaw(); - allocateScreenBuffer(resX,resY); + if (!allocateScreenBuffer(resX,resY)) + { //FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled + //NOTE: if the session closes successfully after this call, deferred rendering will be + // disabled on future sessions + if (LLPipeline::sRenderDeferred) + { + gSavedSettings.setBOOL("RenderDeferred", FALSE); + LLPipeline::refreshCachedSettings(); + } + } } } @@ -902,6 +914,8 @@ void LLPipeline::refreshCachedSettings() && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion") && gSavedSettings.getBOOL("UseOcclusion") && gGLManager.mHasOcclusionQuery) ? 2 : 0; + + updateRenderDeferred(); } void LLPipeline::releaseGLBuffers() @@ -5412,7 +5426,6 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) if (light->isLightSpotlight() // directional (spot-)light && (LLPipeline::sRenderDeferred || RenderSpotLightsInNondeferred)) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on { - LLVector3 spotparams = light->getSpotLightParams(); LLQuaternion quat = light->getRenderRotation(); LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction at_axis *= quat; @@ -5460,7 +5473,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) F32 light_radius = 16.f; - F32 x = 3.f; + F32 x = 3.f; float linatten = x / (light_radius); // % of brightness at radius mHWLightColors[2] = light_color; @@ -5624,7 +5637,7 @@ void LLPipeline::enableLightsPreview() LLVector4 light_pos(dir0, 0.0f); - LLLightState* light = gGL.getLight(0); + LLLightState* light = gGL.getLight(1); light->enable(); light->setPosition(light_pos); @@ -5636,7 +5649,7 @@ void LLPipeline::enableLightsPreview() light_pos = LLVector4(dir1, 0.f); - light = gGL.getLight(1); + light = gGL.getLight(2); light->enable(); light->setPosition(light_pos); light->setDiffuse(diffuse1); @@ -5646,7 +5659,7 @@ void LLPipeline::enableLightsPreview() light->setSpotCutoff(180.f); light_pos = LLVector4(dir2, 0.f); - light = gGL.getLight(2); + light = gGL.getLight(3); light->enable(); light->setPosition(light_pos); light->setDiffuse(diffuse2); diff --git a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml index 8142c0f2b..cb9d8cfda 100644 --- a/indra/newview/skins/default/xui/en-us/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en-us/floater_snapshot.xml @@ -53,16 +53,16 @@