Merge remote-tracking branch 'origin/main' into release/materials_featurette

master
Brad Linden 2024-04-09 14:17:34 -07:00
commit 5a47a3cb23
740 changed files with 3501 additions and 3096 deletions

View File

@ -73,7 +73,7 @@ jobs:
uses: actions/checkout@v4
with:
repository: secondlife/build-variables
ref: viewer
ref: master
path: .build-variables
- name: Checkout master-message-template

View File

@ -1538,11 +1538,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>e50ea94bbaa4ff41bf53b84b7192df1a694c5337</string>
<string>3a3e14563cd5fc019c3f139b82aa46ec79847709</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/llca/releases/download/v202310121525.0-d22bd98/llca-202310121530.0-common-d22bd98.tar.zst</string>
<string>https://github.com/secondlife/llca/releases/download/v202312051403.17-0f5d9c3/llca-202312051404.0-common-0f5d9c3.tar.zst</string>
</map>
<key>name</key>
<string>common</string>
@ -1556,7 +1556,7 @@
<string>Copyright (c) 2016, Linden Research, Inc.; data provided by the Mozilla NSS Project.
</string>
<key>version</key>
<string>202310121530.0</string>
<string>202312051404.0</string>
<key>name</key>
<string>llca</string>
</map>

View File

@ -112,7 +112,8 @@ installer_CYGWIN()
fi
}
[[ -n "$GITHUB_OUTPUT" ]] || fatal "Need to export GITHUB_OUTPUT"
# if someone wants to run build.sh outside the GitHub environment
[[ -n "$GITHUB_OUTPUT" ]] || export GITHUB_OUTPUT='/dev/null'
# The following is based on the Warning for GitHub multiline output strings:
# https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings
EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64)

View File

@ -295,6 +295,7 @@ Beq Janus
SL-18637
SL-19317
SL-19660
SL-20610
Beth Walcher
Bezilon Kasei
Biancaluce Robbiani

View File

@ -119,11 +119,11 @@ public:
* ClassicCallback must not itself be copied or moved! Once you've passed
* get_userdata() to some API, this object MUST remain at that address.
*/
// However, we can't yet count on C++17 Class Template Argument Deduction,
// which means makeClassicCallback() is still useful, which means we MUST
// be able to return one to construct into caller's instance (move ctor).
// Possible defense: bool 'referenced' data member set by get_userdata(),
// with an llassert_always(! referenced) check in the move constructor.
// However, makeClassicCallback() is useful for deducing the CALLABLE
// type, which means we MUST be able to return one to construct into
// caller's instance (move ctor). Possible defense: bool 'referenced' data
// member set by get_userdata(), with an llassert_always(! referenced)
// check in the move constructor.
ClassicCallback(ClassicCallback const&) = delete;
ClassicCallback(ClassicCallback&&) = default; // delete;
ClassicCallback& operator=(ClassicCallback const&) = delete;

View File

@ -104,7 +104,6 @@ BOOL LLApp::sLogInSignal = FALSE;
// Keeps track of application status
LLScalarCond<LLApp::EAppStatus> LLApp::sStatus{LLApp::APP_STATUS_STOPPED};
LLAppErrorHandler LLApp::sErrorHandler = NULL;
BOOL LLApp::sErrorThreadRunning = FALSE;
LLApp::LLApp()
@ -787,13 +786,8 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *)
return;
}
// Flag status to ERROR, so thread_error does its work.
// Flag status to ERROR
LLApp::setError();
// Block in the signal handler until somebody says that we're done.
while (LLApp::sErrorThreadRunning && !LLApp::isStopped())
{
ms_sleep(10);
}
if (LLApp::sLogInSignal)
{

View File

@ -291,7 +291,6 @@ protected:
static void setStatus(EAppStatus status); // Use this to change the application status.
static LLScalarCond<EAppStatus> sStatus; // Reflects current application status
static BOOL sErrorThreadRunning; // Set while the error thread is running
static BOOL sDisableCrashlogger; // Let the OS handle crashes for us.
std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting.

View File

@ -42,7 +42,7 @@ std::string LLBase64::encode(const U8* input, size_t input_size)
&& input_size > 0)
{
// Yes, it returns int.
int b64_buffer_length = apr_base64_encode_len(narrow(input_size));
int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(input_size));
char* b64_buffer = new char[b64_buffer_length];
// This is faster than apr_base64_encode() if you know
@ -52,7 +52,7 @@ std::string LLBase64::encode(const U8* input, size_t input_size)
b64_buffer_length = apr_base64_encode_binary(
b64_buffer,
input,
narrow(input_size));
narrow<size_t>(input_size));
output.assign(b64_buffer);
delete[] b64_buffer;
}

View File

@ -123,7 +123,7 @@ LLCoros::LLCoros():
// Previously we used
// boost::context::guarded_stack_allocator::default_stacksize();
// empirically this is insufficient.
mStackSize(768*1024),
mStackSize(900*1024),
// mCurrent does NOT own the current CoroData instance -- it simply
// points to it. So initialize it with a no-op deleter.
mCurrent{ [](CoroData*){} }

View File

@ -87,11 +87,10 @@ protected:
}
void addEntry(Index index, Entry *entry)
{
if (lookup(index))
if (!this->emplace(index, entry).second)
{
LL_ERRS() << "Dictionary entry already added (attempted to add duplicate entry)" << LL_ENDL;
}
(*this)[index] = entry;
}
};

View File

@ -46,33 +46,32 @@
template <class Type> class LLPointer
{
public:
LLPointer() :
LLPointer() :
mPointer(NULL)
{
}
LLPointer(Type* ptr) :
LLPointer(Type* ptr) :
mPointer(ptr)
{
ref();
}
LLPointer(const LLPointer<Type>& ptr) :
LLPointer(const LLPointer<Type>& ptr) :
mPointer(ptr.mPointer)
{
ref();
}
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
// Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLPointer(const LLPointer<Subclass>& ptr) :
LLPointer(const LLPointer<Subclass>& ptr) :
mPointer(ptr.get())
{
ref();
}
~LLPointer()
~LLPointer()
{
unref();
}
@ -83,39 +82,39 @@ public:
const Type& operator*() const { return *mPointer; }
Type& operator*() { return *mPointer; }
operator BOOL() const { return (mPointer != NULL); }
operator bool() const { return (mPointer != NULL); }
operator BOOL() const { return (mPointer != NULL); }
operator bool() const { return (mPointer != NULL); }
bool operator!() const { return (mPointer == NULL); }
bool isNull() const { return (mPointer == NULL); }
bool notNull() const { return (mPointer != NULL); }
operator Type*() const { return mPointer; }
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
operator Type*() const { return mPointer; }
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
LLPointer<Type>& operator =(Type* ptr)
{
LLPointer<Type>& operator =(Type* ptr)
{
assign(ptr);
return *this;
return *this;
}
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
{
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
{
assign(ptr);
return *this;
return *this;
}
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
{
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
{
assign(ptr.get());
return *this;
return *this;
}
// Just exchange the pointers, which will not change the reference counts.
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
{
@ -129,16 +128,6 @@ protected:
void ref();
void unref();
#else
void assign(const LLPointer<Type>& ptr)
{
if( mPointer != ptr.mPointer )
{
unref();
mPointer = ptr.mPointer;
ref();
}
}
void ref()
{
if (mPointer)
@ -161,7 +150,18 @@ protected:
}
}
}
#endif
#endif // LL_LIBRARY_INCLUDE
void assign(const LLPointer<Type>& ptr)
{
if (mPointer != ptr.mPointer)
{
unref();
mPointer = ptr.mPointer;
ref();
}
}
protected:
Type* mPointer;
};
@ -169,18 +169,18 @@ protected:
template <class Type> class LLConstPointer
{
public:
LLConstPointer() :
LLConstPointer() :
mPointer(NULL)
{
}
LLConstPointer(const Type* ptr) :
LLConstPointer(const Type* ptr) :
mPointer(ptr)
{
ref();
}
LLConstPointer(const LLConstPointer<Type>& ptr) :
LLConstPointer(const LLConstPointer<Type>& ptr) :
mPointer(ptr.mPointer)
{
ref();
@ -188,7 +188,7 @@ public:
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLConstPointer(const LLConstPointer<Subclass>& ptr) :
LLConstPointer(const LLConstPointer<Subclass>& ptr) :
mPointer(ptr.get())
{
ref();
@ -203,55 +203,55 @@ public:
const Type* operator->() const { return mPointer; }
const Type& operator*() const { return *mPointer; }
operator BOOL() const { return (mPointer != NULL); }
operator bool() const { return (mPointer != NULL); }
operator BOOL() const { return (mPointer != NULL); }
operator bool() const { return (mPointer != NULL); }
bool operator!() const { return (mPointer == NULL); }
bool isNull() const { return (mPointer == NULL); }
bool notNull() const { return (mPointer != NULL); }
operator const Type*() const { return mPointer; }
bool operator !=(const Type* ptr) const { return (mPointer != ptr); }
bool operator ==(const Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLConstPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
bool operator < (const LLConstPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
bool operator > (const LLConstPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
operator const Type*() const { return mPointer; }
bool operator !=(const Type* ptr) const { return (mPointer != ptr); }
bool operator ==(const Type* ptr) const { return (mPointer == ptr); }
bool operator ==(const LLConstPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
bool operator < (const LLConstPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
bool operator > (const LLConstPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
LLConstPointer<Type>& operator =(const Type* ptr)
LLConstPointer<Type>& operator =(const Type* ptr)
{
if( mPointer != ptr )
{
unref();
mPointer = ptr;
unref();
mPointer = ptr;
ref();
}
return *this;
return *this;
}
LLConstPointer<Type>& operator =(const LLConstPointer<Type>& ptr)
{
LLConstPointer<Type>& operator =(const LLConstPointer<Type>& ptr)
{
if( mPointer != ptr.mPointer )
{
unref();
unref();
mPointer = ptr.mPointer;
ref();
}
return *this;
return *this;
}
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
template<typename Subclass>
LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr)
{
LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr)
{
if( mPointer != ptr.get() )
{
unref();
unref();
mPointer = ptr.get();
ref();
}
return *this;
return *this;
}
// Just exchange the pointers, which will not change the reference counts.
static void swap(LLConstPointer<Type>& a, LLConstPointer<Type>& b)
{
@ -262,11 +262,11 @@ public:
protected:
#ifdef LL_LIBRARY_INCLUDE
void ref();
void ref();
void unref();
#else
void ref()
{
#else // LL_LIBRARY_INCLUDE
void ref()
{
if (mPointer)
{
mPointer->ref();
@ -277,9 +277,9 @@ protected:
{
if (mPointer)
{
const Type *tempp = mPointer;
const Type *temp = mPointer;
mPointer = NULL;
tempp->unref();
temp->unref();
if (mPointer != NULL)
{
LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL;
@ -287,7 +287,8 @@ protected:
}
}
}
#endif
#endif // LL_LIBRARY_INCLUDE
protected:
const Type* mPointer;
};
@ -297,13 +298,13 @@ class LLCopyOnWritePointer : public LLPointer<Type>
{
public:
typedef LLCopyOnWritePointer<Type> self_t;
typedef LLPointer<Type> pointer_t;
LLCopyOnWritePointer()
typedef LLPointer<Type> pointer_t;
LLCopyOnWritePointer()
: mStayUnique(false)
{}
LLCopyOnWritePointer(Type* ptr)
LLCopyOnWritePointer(Type* ptr)
: LLPointer<Type>(ptr),
mStayUnique(false)
{}

View File

@ -58,7 +58,9 @@
* to restore uniform distribution.
*/
static LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed());
// gRandomGenerator is a stateful static object, which is therefore not
// inherently thread-safe.
static thread_local LLRandLagFib2281 gRandomGenerator(LLUUID::getRandomSeed());
// no default implementation, only specific F64 and F32 specializations
template <typename REAL>
@ -71,7 +73,7 @@ inline F64 ll_internal_random<F64>()
// CPUs (or at least multi-threaded processes) seem to
// occasionally give an obviously incorrect random number -- like
// 5^15 or something. Sooooo, clamp it as described above.
F64 rv = gRandomGenerator();
F64 rv{ gRandomGenerator() };
if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0);
return rv;
}
@ -79,7 +81,13 @@ inline F64 ll_internal_random<F64>()
template <>
inline F32 ll_internal_random<F32>()
{
return F32(ll_internal_random<F64>());
// *HACK: clamp the result as described above.
// Per Monty, it's important to clamp using the correct fmodf() rather
// than expanding to F64 for fmod() and then truncating back to F32. Prior
// to this change, we were getting sporadic ll_frand() == 1.0 results.
F32 rv{ narrow<F32>(gRandomGenerator()) };
if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f);
return rv;
}
/*------------------------------ F64 aliases -------------------------------*/

View File

@ -30,7 +30,7 @@
#include "llerror.h"
// maximum reference count before sounding memory leak alarm
const S32 gMaxRefCount = S32_MAX;
const S32 gMaxRefCount = LL_REFCOUNT_FREE;
LLRefCount::LLRefCount(const LLRefCount& other)
: mRef(0)
@ -49,7 +49,7 @@ LLRefCount::LLRefCount() :
}
LLRefCount::~LLRefCount()
{
{
if (mRef != LL_REFCOUNT_FREE && mRef != 0)
{
LL_ERRS() << "deleting non-zero reference" << LL_ENDL;

View File

@ -51,24 +51,20 @@ protected:
public:
LLRefCount();
inline void validateRefCount() const
{
llassert(mRef > 0); // ref count below 0, likely corrupted
llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak
}
inline void ref() const
{
mRef++;
validateRefCount();
}
{
llassert(mRef != LL_REFCOUNT_FREE); // object is deleted
mRef++;
llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak
}
inline S32 unref() const
{
validateRefCount();
llassert(mRef != LL_REFCOUNT_FREE); // object is deleted
llassert(mRef > 0); // ref count below 1, likely corrupted
if (0 == --mRef)
{
mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging
mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging
delete this;
return 0;
}
@ -82,8 +78,8 @@ public:
return mRef;
}
private:
mutable S32 mRef;
private:
mutable S32 mRef;
};
@ -106,7 +102,7 @@ protected:
public:
LLThreadSafeRefCount();
LLThreadSafeRefCount(const LLThreadSafeRefCount&);
LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref)
LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref)
{
mRef = 0;
return *this;
@ -114,8 +110,8 @@ public:
void ref()
{
mRef++;
}
mRef++;
}
void unref()
{
@ -136,36 +132,36 @@ public:
return currentVal;
}
private:
LLAtomicS32 mRef;
private:
LLAtomicS32 mRef;
};
/**
* intrusive pointer support for LLThreadSafeRefCount
* this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type
*/
inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p)
inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p)
{
p->ref();
}
inline void intrusive_ptr_release(LLThreadSafeRefCount* p)
inline void intrusive_ptr_release(LLThreadSafeRefCount* p)
{
p->unref();
p->unref();
}
/**
* intrusive pointer support
* this allows you to use boost::intrusive_ptr with any LLRefCount-derived type
*/
inline void intrusive_ptr_add_ref(LLRefCount* p)
inline void intrusive_ptr_add_ref(LLRefCount* p)
{
p->ref();
}
inline void intrusive_ptr_release(LLRefCount* p)
inline void intrusive_ptr_release(LLRefCount* p)
{
p->unref();
p->unref();
}
#endif

View File

@ -197,12 +197,12 @@ public:
typename std::enable_if<std::is_integral<VALUE>::value &&
! std::is_same<VALUE, Boolean>::value,
bool>::type = true>
LLSD(VALUE v): LLSD(Integer(narrow(v))) {}
LLSD(VALUE v): LLSD(Integer(narrow<VALUE>(v))) {}
// support construction from F32 et al.
template <typename VALUE,
typename std::enable_if<std::is_floating_point<VALUE>::value,
bool>::type = true>
LLSD(VALUE v): LLSD(Real(narrow(v))) {}
LLSD(VALUE v): LLSD(Real(narrow<VALUE>(v))) {}
//@}
/** @name Scalar Assignment */

View File

@ -2174,7 +2174,7 @@ std::string zip_llsd(LLSD& data)
U8 out[CHUNK];
strm.avail_in = narrow(source.size());
strm.avail_in = narrow<size_t>(source.size());
strm.next_in = (U8*) source.data();
U8* output = NULL;

View File

@ -196,12 +196,12 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr,
// *FIX: memory inefficient.
// *TODO: convert to use LLBase64
ostr << pre << "<binary encoding=\"base64\">";
int b64_buffer_length = apr_base64_encode_len(narrow(buffer.size()));
int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(buffer.size()));
char* b64_buffer = new char[b64_buffer_length];
b64_buffer_length = apr_base64_encode_binary(
b64_buffer,
&buffer[0],
narrow(buffer.size()));
narrow<size_t>(buffer.size()));
ostr.write(b64_buffer, b64_buffer_length - 1);
delete[] b64_buffer;
ostr << "</binary>" << post;
@ -404,11 +404,18 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
if (buffer)
{
((char*) buffer)[count ? count - 1 : 0] = '\0';
if (mEmitErrors)
{
LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*)buffer << LL_ENDL;
}
}
if (mEmitErrors)
{
LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << LL_ENDL;
}
else
{
if (mEmitErrors)
{
LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR, null buffer" << LL_ENDL;
}
}
data = LLSD();
return LLSDParser::PARSE_FAILURE;
}

View File

@ -1406,9 +1406,17 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token,
}
else
{
#if 0
// EXT-1565 : Zai Lynch, James Linden : 15/Oct/09
// [BSI] Feedback: Viewer clock mentions SLT, but would prefer it to show PST/PDT
// "slt" = Second Life Time, which is deprecated.
// If not utc or user local time, fallback to Pacific time
replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST";
#else
// SL-20370 : Steeltoe Linden : 29/Sep/23
// Change "PDT" to "SLT" on menu bar
replacement = "SLT";
#endif
}
return true;
}

View File

@ -917,7 +917,7 @@ void LLMemoryInfo::stream(std::ostream& s) const
// Now stream stats
BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap))
{
s << pfx << std::setw(narrow(key_width+1)) << (pair.first + ':') << ' ';
s << pfx << std::setw(narrow<size_t>(key_width+1)) << (pair.first + ':') << ' ';
LLSD value(pair.second);
if (value.isInteger())
s << std::setw(12) << value.asInteger();

View File

@ -113,15 +113,16 @@ LL_COMMON_API bool on_main_thread()
return (LLThread::currentID() == main_thread());
}
LL_COMMON_API void assert_main_thread()
LL_COMMON_API bool assert_main_thread()
{
auto curr = LLThread::currentID();
auto main = main_thread();
if (curr != main)
{
LL_WARNS() << "Illegal execution from thread id " << curr
<< " outside main thread " << main << LL_ENDL;
}
if (curr == main)
return true;
LL_WARNS() << "Illegal execution from thread id " << curr
<< " outside main thread " << main << LL_ENDL;
return false;
}
// this function has become moot

View File

@ -152,7 +152,7 @@ public:
//============================================================================
extern LL_COMMON_API void assert_main_thread();
extern LL_COMMON_API bool assert_main_thread();
extern LL_COMMON_API bool on_main_thread();
#endif // LL_LLTHREAD_H

View File

@ -33,8 +33,6 @@
namespace LLTrace
{
MemStatHandle gTraceMemStat("LLTrace");
StatBase::StatBase( const char* name, const char* description )
: mName(name),
mDescription(description ? description : "")
@ -65,7 +63,7 @@ void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent )
llassert_always(parent != mBlock);
llassert_always(parent != NULL);
TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow(parent->getIndex()));
TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow<size_t>(parent->getIndex()));
if (!parent_tree_node) return;
if (mParent)

View File

@ -193,61 +193,6 @@ void add(CountStatHandle<T>& count, VALUE_T value)
#endif
}
template<>
class StatType<MemAccumulator::AllocationFacet>
: public StatType<MemAccumulator>
{
public:
StatType(const char* name, const char* description = "")
: StatType<MemAccumulator>(name, description)
{}
};
template<>
class StatType<MemAccumulator::DeallocationFacet>
: public StatType<MemAccumulator>
{
public:
StatType(const char* name, const char* description = "")
: StatType<MemAccumulator>(name, description)
{}
};
class MemStatHandle : public StatType<MemAccumulator>
{
public:
typedef StatType<MemAccumulator> stat_t;
MemStatHandle(const char* name, const char* description = "")
: stat_t(name, description)
{
mName = name;
}
void setName(const char* name)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mName = name;
setKey(name);
}
/*virtual*/ const char* getUnitLabel() const { return "KB"; }
StatType<MemAccumulator::AllocationFacet>& allocations()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return static_cast<StatType<MemAccumulator::AllocationFacet>&>(*(StatType<MemAccumulator>*)this);
}
StatType<MemAccumulator::DeallocationFacet>& deallocations()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return static_cast<StatType<MemAccumulator::DeallocationFacet>&>(*(StatType<MemAccumulator>*)this);
}
};
// measures effective memory footprint of specified type
// specialize to cover different types
template<typename T, typename IS_MEM_TRACKABLE = void, typename IS_UNITS = void>
@ -334,33 +279,6 @@ struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES>
}
};
template<typename T>
inline void claim_alloc(MemStatHandle& measurement, const T& value)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
#if LL_TRACE_ENABLED
auto size = MeasureMem<T>::measureFootprint(value);
if(size == 0) return;
MemAccumulator& accumulator = measurement.getCurrentAccumulator();
accumulator.mSize.sample(accumulator.mSize.hasValue() ? accumulator.mSize.getLastValue() + (F64)size : (F64)size);
accumulator.mAllocations.record(size);
#endif
}
template<typename T>
inline void disclaim_alloc(MemStatHandle& measurement, const T& value)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
#if LL_TRACE_ENABLED
auto size = MeasureMem<T>::measureFootprint(value);
if(size == 0) return;
MemAccumulator& accumulator = measurement.getCurrentAccumulator();
accumulator.mSize.sample(accumulator.mSize.hasValue() ? accumulator.mSize.getLastValue() - (F64)size : -(F64)size);
accumulator.mDeallocations.add(size);
#endif
}
}
#endif // LL_LLTRACE_H

View File

@ -1,24 +1,24 @@
/**
/**
* @file lltracesampler.cpp
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
@ -32,73 +32,52 @@
namespace LLTrace
{
extern MemStatHandle gTraceMemStat;
///////////////////////////////////////////////////////////////////////
// AccumulatorBufferGroup
///////////////////////////////////////////////////////////////////////
AccumulatorBufferGroup::AccumulatorBufferGroup()
AccumulatorBufferGroup::AccumulatorBufferGroup()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
claim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator));
claim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator));
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
}
AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& other)
: mCounts(other.mCounts),
mSamples(other.mSamples),
mEvents(other.mEvents),
mStackTimers(other.mStackTimers),
mMemStats(other.mMemStats)
mStackTimers(other.mStackTimers)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
claim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator));
claim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator));
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
}
AccumulatorBufferGroup::~AccumulatorBufferGroup()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator));
disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator));
disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator));
disclaim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator));
disclaim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator));
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
}
void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
other.mCounts.reset(&mCounts);
other.mSamples.reset(&mSamples);
other.mEvents.reset(&mEvents);
other.mStackTimers.reset(&mStackTimers);
other.mMemStats.reset(&mMemStats);
}
void AccumulatorBufferGroup::makeCurrent()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mCounts.makeCurrent();
mSamples.makeCurrent();
mEvents.makeCurrent();
mStackTimers.makeCurrent();
mMemStats.makeCurrent();
ThreadRecorder* thread_recorder = get_thread_recorder();
AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers;
// update stacktimer parent pointers
for (size_t i = 0, end_i = mStackTimers.size(); i < end_i; i++)
{
TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow(i));
TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow<size_t>(i));
if (tree_node)
{
timer_accumulator_buffer[i].mParent = tree_node->mParent;
@ -109,12 +88,11 @@ void AccumulatorBufferGroup::makeCurrent()
//static
void AccumulatorBufferGroup::clearCurrent()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
AccumulatorBuffer<CountAccumulator>::clearCurrent();
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
AccumulatorBuffer<CountAccumulator>::clearCurrent();
AccumulatorBuffer<SampleAccumulator>::clearCurrent();
AccumulatorBuffer<EventAccumulator>::clearCurrent();
AccumulatorBuffer<TimeBlockAccumulator>::clearCurrent();
AccumulatorBuffer<MemAccumulator>::clearCurrent();
}
bool AccumulatorBufferGroup::isCurrent() const
@ -124,44 +102,39 @@ bool AccumulatorBufferGroup::isCurrent() const
void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mCounts.addSamples(other.mCounts, SEQUENTIAL);
mSamples.addSamples(other.mSamples, SEQUENTIAL);
mEvents.addSamples(other.mEvents, SEQUENTIAL);
mMemStats.addSamples(other.mMemStats, SEQUENTIAL);
mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL);
}
void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mCounts.addSamples(other.mCounts, NON_SEQUENTIAL);
mSamples.addSamples(other.mSamples, NON_SEQUENTIAL);
mEvents.addSamples(other.mEvents, NON_SEQUENTIAL);
mMemStats.addSamples(other.mMemStats, NON_SEQUENTIAL);
// for now, hold out timers from merge, need to be displayed per thread
//mStackTimers.addSamples(other.mStackTimers, NON_SEQUENTIAL);
}
void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mCounts.reset(other ? &other->mCounts : NULL);
mSamples.reset(other ? &other->mSamples : NULL);
mEvents.reset(other ? &other->mEvents : NULL);
mStackTimers.reset(other ? &other->mStackTimers : NULL);
mMemStats.reset(other ? &other->mMemStats : NULL);
}
void AccumulatorBufferGroup::sync()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
if (isCurrent())
{
F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
mSamples.sync(time_stamp);
mMemStats.sync(time_stamp);
}
}
@ -197,10 +170,9 @@ F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const Samp
return a.getSumOfSquares();
}
void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type )
{
if (append_type == NON_SEQUENTIAL)
if (append_type == NON_SEQUENTIAL)
{
return;
}
@ -299,7 +271,7 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT
void EventAccumulator::reset( const EventAccumulator* other )
{
mNumSamples = 0;
mNumSamples = 0;
mSum = 0;
mMin = F32(NaN);
mMax = F32(NaN);
@ -308,5 +280,4 @@ void EventAccumulator::reset( const EventAccumulator* other )
mLastValue = other ? other->mLastValue : NaN;
}
}

View File

@ -1,26 +1,26 @@
/**
/**
* @file lltraceaccumulators.h
* @brief Storage for accumulating statistics
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
@ -28,7 +28,6 @@
#ifndef LL_LLTRACEACCUMULATORS_H
#define LL_LLTRACEACCUMULATORS_H
#include "stdtypes.h"
#include "llpreprocessor.h"
#include "llunits.h"
@ -66,7 +65,7 @@ namespace LLTrace
: mStorageSize(0),
mStorage(NULL)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
const AccumulatorBuffer& other = *getDefaultBuffer();
resize(sNextStorageSlot);
for (S32 i = 0; i < sNextStorageSlot; i++)
@ -77,7 +76,7 @@ namespace LLTrace
~AccumulatorBuffer()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
if (isCurrent())
{
LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
@ -85,14 +84,14 @@ namespace LLTrace
delete[] mStorage;
}
LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index)
{
return mStorage[index];
LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index)
{
return mStorage[index];
}
LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const
{
return mStorage[index];
{
return mStorage[index];
}
@ -100,7 +99,7 @@ namespace LLTrace
: mStorageSize(0),
mStorage(NULL)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
resize(sNextStorageSlot);
for (S32 i = 0; i < sNextStorageSlot; i++)
{
@ -110,7 +109,7 @@ namespace LLTrace
void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
for (size_t i = 0; i < sNextStorageSlot; i++)
{
@ -120,7 +119,7 @@ namespace LLTrace
void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot);
for (size_t i = 0; i < sNextStorageSlot; i++)
{
@ -130,7 +129,7 @@ namespace LLTrace
void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
llassert(mStorageSize >= sNextStorageSlot);
for (size_t i = 0; i < sNextStorageSlot; i++)
{
@ -140,7 +139,7 @@ namespace LLTrace
void sync(F64SecondsImplicit time_stamp)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
llassert(mStorageSize >= sNextStorageSlot);
for (size_t i = 0; i < sNextStorageSlot; i++)
{
@ -160,13 +159,13 @@ namespace LLTrace
static void clearCurrent()
{
LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL);
}
// NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned
size_t reserveSlot()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
size_t next_slot = sNextStorageSlot++;
if (next_slot >= mStorageSize)
{
@ -180,7 +179,7 @@ namespace LLTrace
void resize(size_t new_size)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
if (new_size <= mStorageSize) return;
ACCUMULATOR* old_storage = mStorage;
@ -214,14 +213,14 @@ namespace LLTrace
return mStorageSize;
}
static size_t getNumIndices()
static size_t getNumIndices()
{
return sNextStorageSlot;
}
static self_t* getDefaultBuffer()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
static bool sInitialized = false;
if (!sInitialized)
{
@ -336,7 +335,7 @@ namespace LLTrace
void sample(F64 value)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds();
// store effect of last value
@ -399,7 +398,7 @@ namespace LLTrace
F64 mMean,
mSumOfSquares;
F64SecondsImplicit
F64SecondsImplicit
mLastSampleTimeStamp,
mTotalSamplingTime;
@ -409,7 +408,7 @@ namespace LLTrace
S32 mNumSamples;
// distinct from mNumSamples, since we might have inherited a last value from
// a previous sampling period
bool mHasValue;
bool mHasValue;
};
class CountAccumulator
@ -457,14 +456,14 @@ namespace LLTrace
class alignas(32) TimeBlockAccumulator
{
public:
public:
typedef F64Seconds value_t;
static F64Seconds getDefaultValue() { return F64Seconds(0); }
typedef TimeBlockAccumulator self_t;
// fake classes that allows us to view different facets of underlying statistic
struct CallCountFacet
struct CallCountFacet
{
typedef S32 value_t;
};
@ -515,12 +514,12 @@ namespace LLTrace
BlockTimerStatHandle* getParent() { return mParent; }
BlockTimerStatHandle* mBlock;
BlockTimerStatHandle* mParent;
BlockTimerStatHandle* mParent;
std::vector<BlockTimerStatHandle*> mChildren;
bool mCollapsed;
bool mNeedsSorting;
};
struct BlockTimerStackRecord
{
class BlockTimer* mActiveTimer;
@ -528,65 +527,6 @@ namespace LLTrace
U64 mChildTime;
};
struct MemAccumulator
{
typedef F64Bytes value_t;
static F64Bytes getDefaultValue() { return F64Bytes(0); }
typedef MemAccumulator self_t;
// fake classes that allows us to view different facets of underlying statistic
struct AllocationFacet
{
typedef F64Bytes value_t;
static F64Bytes getDefaultValue() { return F64Bytes(0); }
};
struct DeallocationFacet
{
typedef F64Bytes value_t;
static F64Bytes getDefaultValue() { return F64Bytes(0); }
};
void addSamples(const MemAccumulator& other, EBufferAppendType append_type)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mAllocations.addSamples(other.mAllocations, append_type);
mDeallocations.addSamples(other.mDeallocations, append_type);
if (append_type == SEQUENTIAL)
{
mSize.addSamples(other.mSize, SEQUENTIAL);
}
else
{
F64 allocation_delta(other.mAllocations.getSum() - other.mDeallocations.getSum());
mSize.sample(mSize.hasValue()
? mSize.getLastValue() + allocation_delta
: allocation_delta);
}
}
void reset(const MemAccumulator* other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mSize.reset(other ? &other->mSize : NULL);
mAllocations.reset(other ? &other->mAllocations : NULL);
mDeallocations.reset(other ? &other->mDeallocations : NULL);
}
void sync(F64SecondsImplicit time_stamp)
{
mSize.sync(time_stamp);
}
bool hasValue() const { return mSize.hasValue(); }
SampleAccumulator mSize;
EventAccumulator mAllocations;
CountAccumulator mDeallocations;
};
struct AccumulatorBufferGroup : public LLRefCount
{
AccumulatorBufferGroup();
@ -607,9 +547,7 @@ namespace LLTrace
AccumulatorBuffer<SampleAccumulator> mSamples;
AccumulatorBuffer<EventAccumulator> mEvents;
AccumulatorBuffer<TimeBlockAccumulator> mStackTimers;
AccumulatorBuffer<MemAccumulator> mMemStats;
};
}
#endif // LL_LLTRACEACCUMULATORS_H

View File

@ -1,24 +1,24 @@
/**
/**
* @file lltracesampler.cpp
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
@ -32,7 +32,7 @@
#include "lltracethreadrecorder.h"
#include "llthread.h"
inline F64 lerp(F64 a, F64 b, F64 u)
inline F64 lerp(F64 a, F64 b, F64 u)
{
return a + ((b - a) * u);
}
@ -40,34 +40,29 @@ inline F64 lerp(F64 a, F64 b, F64 u)
namespace LLTrace
{
extern MemStatHandle gTraceMemStat;
///////////////////////////////////////////////////////////////////////
// Recording
///////////////////////////////////////////////////////////////////////
Recording::Recording(EPlayState state)
Recording::Recording(EPlayState state)
: mElapsedSeconds(0),
mActiveBuffers(NULL)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
claim_alloc(gTraceMemStat, this);
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mBuffers = new AccumulatorBufferGroup();
claim_alloc(gTraceMemStat, mBuffers);
setPlayState(state);
}
Recording::Recording( const Recording& other )
: mActiveBuffers(NULL)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
claim_alloc(gTraceMemStat, this);
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
*this = other;
}
Recording& Recording::operator = (const Recording& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
// this will allow us to seamlessly start without affecting any data we've acquired from other
setPlayState(PAUSED);
@ -85,14 +80,11 @@ Recording& Recording::operator = (const Recording& other)
return *this;
}
Recording::~Recording()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
disclaim_alloc(gTraceMemStat, this);
disclaim_alloc(gTraceMemStat, mBuffers);
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
// allow recording destruction without thread recorder running,
// allow recording destruction without thread recorder running,
// otherwise thread shutdown could crash if a recording outlives the thread recorder
// besides, recording construction and destruction is fine without a recorder...just don't attempt to start one
if (isStarted() && LLTrace::get_thread_recorder() != NULL)
@ -107,14 +99,14 @@ void Recording::update()
#if LL_TRACE_ENABLED
if (isStarted())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
// must have
llassert(mActiveBuffers != NULL
// must have
llassert(mActiveBuffers != NULL
&& LLTrace::get_thread_recorder() != NULL);
if(!mActiveBuffers->isCurrent() && LLTrace::get_thread_recorder() != NULL)
if (!mActiveBuffers->isCurrent() && LLTrace::get_thread_recorder() != NULL)
{
AccumulatorBufferGroup* buffers = mBuffers.write();
LLTrace::get_thread_recorder()->deactivate(buffers);
@ -128,7 +120,7 @@ void Recording::update()
void Recording::handleReset()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
#if LL_TRACE_ENABLED
mBuffers.write()->reset();
@ -139,7 +131,7 @@ void Recording::handleReset()
void Recording::handleStart()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
#if LL_TRACE_ENABLED
mSamplingTimer.reset();
mBuffers.setStayUnique(true);
@ -151,7 +143,7 @@ void Recording::handleStart()
void Recording::handleStop()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
#if LL_TRACE_ENABLED
mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
// must have thread recorder running on this thread
@ -204,7 +196,6 @@ F64Seconds Recording::getSum(const StatType<TimeBlockAccumulator::SelfTimeFacet>
return F64Seconds(((F64)(accumulator.mSelfTimeCounter) + (F64)(active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) / (F64)LLTrace::BlockTimer::countsPerSecond());
}
S32 Recording::getSum(const StatType<TimeBlockAccumulator::CallCountFacet>& stat)
{
update();
@ -219,7 +210,7 @@ F64Seconds Recording::getPerSec(const StatType<TimeBlockAccumulator>& stat)
const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL;
return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0))
return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0))
/ ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value()));
}
@ -241,144 +232,9 @@ F32 Recording::getPerSec(const StatType<TimeBlockAccumulator::CallCountFacet>& s
return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / mElapsedSeconds.value();
}
bool Recording::hasValue(const StatType<MemAccumulator>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return accumulator.mSize.hasValue() || (active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.hasValue() : false);
}
F64Kilobytes Recording::getMin(const StatType<MemAccumulator>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return F64Bytes(llmin(accumulator.mSize.getMin(), (active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMin() : F32_MAX)));
}
F64Kilobytes Recording::getMean(const StatType<MemAccumulator>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
if (active_accumulator && active_accumulator->mSize.hasValue())
{
F32 t = 0.0f;
S32 div = accumulator.mSize.getSampleCount() + active_accumulator->mSize.getSampleCount();
if (div > 0)
{
t = active_accumulator->mSize.getSampleCount() / div;
}
return F64Bytes(lerp(accumulator.mSize.getMean(), active_accumulator->mSize.getMean(), t));
}
else
{
return F64Bytes(accumulator.mSize.getMean());
}
}
F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return F64Bytes(llmax(accumulator.mSize.getMax(), active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMax() : F32_MIN));
}
F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
if (active_accumulator && active_accumulator->hasValue())
{
F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator.mSize, active_accumulator->mSize);
return F64Bytes(sqrtf(sum_of_squares / (accumulator.mSize.getSamplingTime().value() + active_accumulator->mSize.getSamplingTime().value())));
}
else
{
return F64Bytes(accumulator.mSize.getStandardDeviation());
}
}
F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return F64Bytes(active_accumulator ? active_accumulator->mSize.getLastValue() : accumulator.mSize.getLastValue());
}
bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return accumulator.mAllocations.hasValue() || (active_accumulator ? active_accumulator->mAllocations.hasValue() : false);
}
F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return F64Bytes(accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0));
}
F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return F64Bytes((accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)) / mElapsedSeconds.value());
}
S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return accumulator.mAllocations.getSampleCount() + (active_accumulator ? active_accumulator->mAllocations.getSampleCount() : 0);
}
bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return accumulator.mDeallocations.hasValue() || (active_accumulator ? active_accumulator->mDeallocations.hasValue() : false);
}
F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return F64Bytes(accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0));
}
F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFacet>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return F64Bytes((accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)) / mElapsedSeconds.value());
}
S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& stat)
{
update();
const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()];
const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL;
return accumulator.mDeallocations.getSampleCount() + (active_accumulator ? active_accumulator->mDeallocations.getSampleCount() : 0);
}
bool Recording::hasValue(const StatType<CountAccumulator>& stat)
{
update();
update();
const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false);
@ -386,7 +242,7 @@ bool Recording::hasValue(const StatType<CountAccumulator>& stat)
F64 Recording::getSum(const StatType<CountAccumulator>& stat)
{
update();
update();
const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0);
@ -394,7 +250,7 @@ F64 Recording::getSum(const StatType<CountAccumulator>& stat)
F64 Recording::getPerSec( const StatType<CountAccumulator>& stat )
{
update();
update();
const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0);
@ -403,7 +259,7 @@ F64 Recording::getPerSec( const StatType<CountAccumulator>& stat )
S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat )
{
update();
update();
const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()];
const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL;
return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0);
@ -411,7 +267,7 @@ S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat )
bool Recording::hasValue(const StatType<SampleAccumulator>& stat)
{
update();
update();
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue());
@ -419,7 +275,7 @@ bool Recording::hasValue(const StatType<SampleAccumulator>& stat)
F64 Recording::getMin( const StatType<SampleAccumulator>& stat )
{
update();
update();
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX);
@ -427,7 +283,7 @@ F64 Recording::getMin( const StatType<SampleAccumulator>& stat )
F64 Recording::getMax( const StatType<SampleAccumulator>& stat )
{
update();
update();
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN);
@ -435,17 +291,17 @@ F64 Recording::getMax( const StatType<SampleAccumulator>& stat )
F64 Recording::getMean( const StatType<SampleAccumulator>& stat )
{
update();
update();
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
if (active_accumulator && active_accumulator->hasValue())
{
F32 t = 0.0f;
S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount();
if (div > 0)
{
t = active_accumulator->getSampleCount() / div;
}
F32 t = 0.0f;
S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount();
if (div > 0)
{
t = active_accumulator->getSampleCount() / div;
}
return lerp(accumulator.getMean(), active_accumulator->getMean(), t);
}
else
@ -456,7 +312,7 @@ F64 Recording::getMean( const StatType<SampleAccumulator>& stat )
F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat )
{
update();
update();
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
@ -473,7 +329,7 @@ F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat )
F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat )
{
update();
update();
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue());
@ -481,7 +337,7 @@ F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat )
S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat )
{
update();
update();
const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()];
const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL;
return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0);
@ -489,7 +345,7 @@ S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat )
bool Recording::hasValue(const StatType<EventAccumulator>& stat)
{
update();
update();
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue());
@ -497,7 +353,7 @@ bool Recording::hasValue(const StatType<EventAccumulator>& stat)
F64 Recording::getSum( const StatType<EventAccumulator>& stat)
{
update();
update();
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0));
@ -505,7 +361,7 @@ F64 Recording::getSum( const StatType<EventAccumulator>& stat)
F64 Recording::getMin( const StatType<EventAccumulator>& stat )
{
update();
update();
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX);
@ -513,7 +369,7 @@ F64 Recording::getMin( const StatType<EventAccumulator>& stat )
F64 Recording::getMax( const StatType<EventAccumulator>& stat )
{
update();
update();
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN);
@ -521,17 +377,17 @@ F64 Recording::getMax( const StatType<EventAccumulator>& stat )
F64 Recording::getMean( const StatType<EventAccumulator>& stat )
{
update();
update();
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
if (active_accumulator && active_accumulator->hasValue())
{
F32 t = 0.0f;
S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount();
if (div > 0)
{
t = active_accumulator->getSampleCount() / div;
}
S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount();
if (div > 0)
{
t = active_accumulator->getSampleCount() / div;
}
return lerp(accumulator.getMean(), active_accumulator->getMean(), t);
}
else
@ -542,7 +398,7 @@ F64 Recording::getMean( const StatType<EventAccumulator>& stat )
F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat )
{
update();
update();
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
@ -559,7 +415,7 @@ F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat )
F64 Recording::getLastValue( const StatType<EventAccumulator>& stat )
{
update();
update();
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue();
@ -567,7 +423,7 @@ F64 Recording::getLastValue( const StatType<EventAccumulator>& stat )
S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat )
{
update();
update();
const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()];
const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL;
return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0);
@ -577,7 +433,7 @@ S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat )
// PeriodicRecording
///////////////////////////////////////////////////////////////////////
PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state)
PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state)
: mAutoResize(num_periods == 0),
mCurPeriod(0),
mNumRecordedPeriods(0),
@ -585,15 +441,13 @@ PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state)
// code in several methods.
mRecordingPeriods(num_periods ? num_periods : 1)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
setPlayState(state);
claim_alloc(gTraceMemStat, this);
}
PeriodicRecording::~PeriodicRecording()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
disclaim_alloc(gTraceMemStat, this);
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
}
void PeriodicRecording::nextPeriod()
@ -615,12 +469,11 @@ void PeriodicRecording::nextPeriod()
void PeriodicRecording::appendRecording(Recording& recording)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
getCurRecording().appendRecording(recording);
nextPeriod();
}
void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
@ -693,16 +546,14 @@ F64Seconds PeriodicRecording::getDuration() const
return duration;
}
LLTrace::Recording PeriodicRecording::snapshotCurRecording() const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
Recording recording_copy(getCurRecording());
recording_copy.stop();
return recording_copy;
}
Recording& PeriodicRecording::getLastRecording()
{
return getPrevRecording(1);
@ -737,19 +588,19 @@ const Recording& PeriodicRecording::getPrevRecording( size_t offset ) const
void PeriodicRecording::handleStart()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
getCurRecording().start();
}
void PeriodicRecording::handleStop()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
getCurRecording().pause();
}
void PeriodicRecording::handleReset()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
getCurRecording().stop();
if (mAutoResize)
@ -771,13 +622,13 @@ void PeriodicRecording::handleReset()
void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
getCurRecording().splitTo(other.getCurRecording());
}
F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
@ -792,14 +643,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, siz
}
}
return has_value
? min_val
return has_value
? min_val
: NaN;
}
F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
@ -814,15 +665,15 @@ F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, siz
}
}
return has_value
? max_val
return has_value
? max_val
: NaN;
}
// calculates means using aggregates per period
F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64 mean = 0;
@ -838,14 +689,14 @@ F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, si
}
}
return valid_period_count
return valid_period_count
? mean / (F64)valid_period_count
: NaN;
}
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64 period_mean = getPeriodMean(stat, num_periods);
@ -870,7 +721,7 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulat
F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
@ -885,14 +736,14 @@ F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, si
}
}
return has_value
? min_val
return has_value
? min_val
: NaN;
}
F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
@ -907,15 +758,15 @@ F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, siz
}
}
return has_value
? max_val
return has_value
? max_val
: NaN;
}
F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
S32 valid_period_count = 0;
@ -938,7 +789,7 @@ F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, s
F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
std::vector<F64> buf;
@ -964,7 +815,7 @@ F64 PeriodicRecording::getPeriodMedian( const StatType<SampleAccumulator>& stat,
F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64 period_mean = getPeriodMean(stat, num_periods);
@ -987,105 +838,13 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumula
: NaN;
}
F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64Kilobytes min_val(std::numeric_limits<F64>::max());
for (size_t i = 1; i <= num_periods; i++)
{
Recording& recording = getPrevRecording(i);
min_val = llmin(min_val, recording.getMin(stat));
}
return min_val;
}
F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, size_t num_periods)
{
return getPeriodMin(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
}
F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64Kilobytes max_val(0.0);
for (size_t i = 1; i <= num_periods; i++)
{
Recording& recording = getPrevRecording(i);
max_val = llmax(max_val, recording.getMax(stat));
}
return max_val;
}
F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, size_t num_periods)
{
return getPeriodMax(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
}
F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64Kilobytes mean(0);
for (size_t i = 1; i <= num_periods; i++)
{
Recording& recording = getPrevRecording(i);
mean += recording.getMean(stat);
}
return mean / F64(num_periods);
}
F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, size_t num_periods)
{
return getPeriodMean(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
}
F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, size_t num_periods /*= std::numeric_limits<size_t>::max()*/ )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64Kilobytes period_mean = getPeriodMean(stat, num_periods);
S32 valid_period_count = 0;
F64 sum_of_squares = 0;
for (size_t i = 1; i <= num_periods; i++)
{
Recording& recording = getPrevRecording(i);
if (recording.hasValue(stat))
{
F64Kilobytes delta = recording.getMean(stat) - period_mean;
sum_of_squares += delta.value() * delta.value();
valid_period_count++;
}
}
return F64Kilobytes(valid_period_count
? sqrt(sum_of_squares / (F64)valid_period_count)
: NaN);
}
F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods)
{
return getPeriodStandardDeviation(static_cast<const StatType<MemAccumulator>&>(stat), num_periods);
}
///////////////////////////////////////////////////////////////////////
// ExtendableRecording
///////////////////////////////////////////////////////////////////////
void ExtendableRecording::extend()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
// push the data back to accepted recording
mAcceptedRecording.appendRecording(mPotentialRecording);
// flush data, so we can start from scratch
@ -1094,76 +853,72 @@ void ExtendableRecording::extend()
void ExtendableRecording::handleStart()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mPotentialRecording.start();
}
void ExtendableRecording::handleStop()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mPotentialRecording.pause();
}
void ExtendableRecording::handleReset()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mAcceptedRecording.reset();
mPotentialRecording.reset();
}
void ExtendableRecording::handleSplitTo(ExtendableRecording& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mPotentialRecording.splitTo(other.mPotentialRecording);
}
///////////////////////////////////////////////////////////////////////
// ExtendablePeriodicRecording
///////////////////////////////////////////////////////////////////////
ExtendablePeriodicRecording::ExtendablePeriodicRecording()
: mAcceptedRecording(0),
ExtendablePeriodicRecording::ExtendablePeriodicRecording()
: mAcceptedRecording(0),
mPotentialRecording(0)
{}
void ExtendablePeriodicRecording::extend()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
// push the data back to accepted recording
mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
// flush data, so we can start from scratch
mPotentialRecording.reset();
}
void ExtendablePeriodicRecording::handleStart()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mPotentialRecording.start();
}
void ExtendablePeriodicRecording::handleStop()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mPotentialRecording.pause();
}
void ExtendablePeriodicRecording::handleReset()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mAcceptedRecording.reset();
mPotentialRecording.reset();
}
void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
mPotentialRecording.splitTo(other.mPotentialRecording);
}
PeriodicRecording& get_frame_recording()
{
static thread_local PeriodicRecording sRecording(200, PeriodicRecording::STARTED);
@ -1174,7 +929,7 @@ PeriodicRecording& get_frame_recording()
void LLStopWatchControlsMixinCommon::start()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
switch (mPlayState)
{
case STOPPED:
@ -1196,7 +951,7 @@ void LLStopWatchControlsMixinCommon::start()
void LLStopWatchControlsMixinCommon::stop()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
switch (mPlayState)
{
case STOPPED:
@ -1216,7 +971,7 @@ void LLStopWatchControlsMixinCommon::stop()
void LLStopWatchControlsMixinCommon::pause()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
switch (mPlayState)
{
case STOPPED:
@ -1236,7 +991,7 @@ void LLStopWatchControlsMixinCommon::pause()
void LLStopWatchControlsMixinCommon::unpause()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
switch (mPlayState)
{
case STOPPED:
@ -1256,7 +1011,7 @@ void LLStopWatchControlsMixinCommon::unpause()
void LLStopWatchControlsMixinCommon::resume()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
switch (mPlayState)
{
case STOPPED:
@ -1277,7 +1032,7 @@ void LLStopWatchControlsMixinCommon::resume()
void LLStopWatchControlsMixinCommon::restart()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
switch (mPlayState)
{
case STOPPED:
@ -1301,13 +1056,13 @@ void LLStopWatchControlsMixinCommon::restart()
void LLStopWatchControlsMixinCommon::reset()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
handleReset();
}
void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state )
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
switch(state)
{
case STOPPED:

View File

@ -1,25 +1,25 @@
/**
/**
* @file lltracerecording.h
* @brief Sampling object for collecting runtime statistics originating from lltrace.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2012, 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$
*/
@ -112,7 +112,6 @@ private:
// atomically stop this object while starting the other
// no data can be missed in between stop and start
virtual void handleSplitTo(DERIVED& other) {};
};
namespace LLTrace
@ -129,8 +128,6 @@ namespace LLTrace
template<typename T>
class EventStatHandle;
class MemStatHandle;
template<typename T>
struct RelatedTypes
{
@ -152,7 +149,7 @@ namespace LLTrace
typedef S32 sum_t;
};
class Recording
class Recording
: public LLStopWatchControlsMixin<Recording>
{
public:
@ -182,24 +179,6 @@ namespace LLTrace
F64Seconds getPerSec(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat);
F32 getPerSec(const StatType<TimeBlockAccumulator::CallCountFacet>& stat);
// Memory accessors
bool hasValue(const StatType<MemAccumulator>& stat);
F64Kilobytes getMin(const StatType<MemAccumulator>& stat);
F64Kilobytes getMean(const StatType<MemAccumulator>& stat);
F64Kilobytes getMax(const StatType<MemAccumulator>& stat);
F64Kilobytes getStandardDeviation(const StatType<MemAccumulator>& stat);
F64Kilobytes getLastValue(const StatType<MemAccumulator>& stat);
bool hasValue(const StatType<MemAccumulator::AllocationFacet>& stat);
F64Kilobytes getSum(const StatType<MemAccumulator::AllocationFacet>& stat);
F64Kilobytes getPerSec(const StatType<MemAccumulator::AllocationFacet>& stat);
S32 getSampleCount(const StatType<MemAccumulator::AllocationFacet>& stat);
bool hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat);
F64Kilobytes getSum(const StatType<MemAccumulator::DeallocationFacet>& stat);
F64Kilobytes getPerSec(const StatType<MemAccumulator::DeallocationFacet>& stat);
S32 getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& stat);
// CountStatHandle accessors
bool hasValue(const StatType<CountAccumulator>& stat);
F64 getSum(const StatType<CountAccumulator>& stat);
@ -318,7 +297,7 @@ namespace LLTrace
/*virtual*/ void handleSplitTo(Recording& other);
// returns data for current thread
class ThreadRecorder* getThreadRecorder();
class ThreadRecorder* getThreadRecorder();
LLTimer mSamplingTimer;
F64Seconds mElapsedSeconds;
@ -335,10 +314,10 @@ namespace LLTrace
~PeriodicRecording();
void nextPeriod();
auto getNumRecordedPeriods()
{
auto getNumRecordedPeriods()
{
// current period counts if not active
return mNumRecordedPeriods + (isStarted() ? 0 : 1);
return mNumRecordedPeriods + (isStarted() ? 0 : 1);
}
F64Seconds getDuration() const;
@ -367,7 +346,7 @@ namespace LLTrace
}
return num_samples;
}
//
// PERIODIC MIN
//
@ -376,7 +355,7 @@ namespace LLTrace
template <typename T>
typename T::value_t getPeriodMin(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
@ -391,15 +370,15 @@ namespace LLTrace
}
}
return has_value
? min_val
return has_value
? min_val
: T::getDefaultValue();
}
template<typename T>
T getPeriodMin(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
@ -407,7 +386,7 @@ namespace LLTrace
template<typename T>
T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
}
@ -415,17 +394,14 @@ namespace LLTrace
template<typename T>
T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
}
F64Kilobytes getPeriodMin(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
F64Kilobytes getPeriodMin(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max());
@ -440,7 +416,7 @@ namespace LLTrace
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
@ -452,7 +428,7 @@ namespace LLTrace
template <typename T>
typename T::value_t getPeriodMax(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
bool has_value = false;
@ -467,15 +443,15 @@ namespace LLTrace
}
}
return has_value
? max_val
return has_value
? max_val
: T::getDefaultValue();
}
template<typename T>
T getPeriodMax(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
@ -483,7 +459,7 @@ namespace LLTrace
template<typename T>
T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
}
@ -491,17 +467,14 @@ namespace LLTrace
template<typename T>
T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
}
F64Kilobytes getPeriodMax(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
F64Kilobytes getPeriodMax(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
F64 max_val = std::numeric_limits<F64>::min();
@ -516,7 +489,7 @@ namespace LLTrace
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
@ -528,7 +501,7 @@ namespace LLTrace
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
typename RelatedTypes<typename T::value_t>::fractional_t mean(0);
@ -549,14 +522,14 @@ namespace LLTrace
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
F64 getPeriodMean(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
}
@ -564,17 +537,14 @@ namespace LLTrace
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
}
F64Kilobytes getPeriodMean(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
F64Kilobytes getPeriodMean(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template <typename T>
typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
num_periods = llmin(num_periods, getNumRecordedPeriods());
typename RelatedTypes<typename T::value_t>::fractional_t mean = 0;
@ -596,7 +566,7 @@ namespace LLTrace
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods));
}
@ -635,10 +605,10 @@ namespace LLTrace
F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
template<typename T>
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods));
}
@ -646,13 +616,10 @@ namespace LLTrace
template<typename T>
typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, size_t num_periods = std::numeric_limits<size_t>::max())
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS;
return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods));
}
F64Kilobytes getPeriodStandardDeviation(const StatType<MemAccumulator>& stat, size_t num_periods = std::numeric_limits<size_t>::max());
F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, size_t num_periods = std::numeric_limits<size_t>::max());
private:
// implementation for LLStopWatchControlsMixin
/*virtual*/ void handleStart();
@ -731,7 +698,7 @@ namespace LLTrace
PeriodicRecording& getResults() { return mAcceptedRecording; }
const PeriodicRecording& getResults() const {return mAcceptedRecording;}
void nextPeriod() { mPotentialRecording.nextPeriod(); }
private:

View File

@ -32,7 +32,7 @@
namespace LLTrace
{
extern MemStatHandle gTraceMemStat;
//extern MemStatHandle gTraceMemStat;
static ThreadRecorder* sMasterThreadRecorder = NULL;
@ -81,9 +81,9 @@ void ThreadRecorder::init()
BlockTimer::getRootTimeBlock().getCurrentAccumulator().mActiveCount = 1;
claim_alloc(gTraceMemStat, this);
claim_alloc(gTraceMemStat, mRootTimer);
claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes);
//claim_alloc(gTraceMemStat, this);
//claim_alloc(gTraceMemStat, mRootTimer);
//claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes);
#endif
}
@ -101,9 +101,9 @@ ThreadRecorder::~ThreadRecorder()
#if LL_TRACE_ENABLED
LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(NULL);
disclaim_alloc(gTraceMemStat, this);
disclaim_alloc(gTraceMemStat, sizeof(BlockTimer));
disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes);
//disclaim_alloc(gTraceMemStat, this);
//disclaim_alloc(gTraceMemStat, sizeof(BlockTimer));
//disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes);
deactivate(&mThreadRecordingBuffers);

View File

@ -164,8 +164,10 @@ void LLUriParser::extractParts()
#if LL_DARWIN
typedef void(*sighandler_t)(int);
jmp_buf return_to_normalize;
static int sLastSignal = 0;
void uri_signal_handler(int signal)
{
sLastSignal = signal;
// Apparently signal handler throwing an exception doesn't work.
// This is ugly and unsafe due to not unwinding content of uriparser library,
// but unless we have a way to catch this as NSexception, jump appears to be the only option.
@ -179,8 +181,10 @@ S32 LLUriParser::normalize()
if (!mRes)
{
#if LL_DARWIN
sighandler_t last_handler;
last_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction
sighandler_t last_sigill_handler, last_sigbus_handler;
last_sigill_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction
last_sigbus_handler = signal(SIGBUS, &uri_signal_handler);
if (setjmp(return_to_normalize))
{
// Issue: external library crashed via signal
@ -194,8 +198,9 @@ S32 LLUriParser::normalize()
// if this can be handled by NSexception, it needs to be remade
llassert(0);
LL_WARNS() << "Uriparser crashed with SIGILL, while processing: " << mNormalizedUri << LL_ENDL;
signal(SIGILL, last_handler);
LL_WARNS() << "Uriparser crashed with " << sLastSignal << " , while processing: " << mNormalizedUri << LL_ENDL;
signal(SIGILL, last_sigill_handler);
signal(SIGBUS, last_sigbus_handler);
return 1;
}
#endif
@ -203,7 +208,8 @@ S32 LLUriParser::normalize()
mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST);
#if LL_DARWIN
signal(SIGILL, last_handler);
signal(SIGILL, last_sigill_handler);
signal(SIGBUS, last_sigbus_handler);
#endif
if (!mRes)
@ -226,7 +232,7 @@ S32 LLUriParser::normalize()
}
}
if(mTmpScheme)
if(mTmpScheme && mNormalizedUri.size() > 7)
{
mNormalizedUri = mNormalizedUri.substr(7);
mTmpScheme = false;

View File

@ -156,18 +156,15 @@ typedef int intptr_t;
* type.
*/
// narrow_holder is a struct that accepts the passed value as its original
// type and provides templated conversion functions to other types. Once we're
// building with compilers that support Class Template Argument Deduction, we
// can rename this class template 'narrow' and eliminate the narrow() factory
// function below.
// type and provides templated conversion functions to other types.
template <typename FROM>
class narrow_holder
class narrow
{
private:
FROM mValue;
public:
narrow_holder(FROM value): mValue(value) {}
narrow(FROM value): mValue(value) {}
/*---------------------- Narrowing unsigned to signed ----------------------*/
template <typename TO,
@ -207,13 +204,4 @@ public:
}
};
/// narrow() factory function returns a narrow_holder<FROM>(), which can be
/// implicitly converted to the target type.
template <typename FROM>
inline
narrow_holder<FROM> narrow(FROM value)
{
return { value };
}
#endif

View File

@ -46,11 +46,12 @@ namespace tut
// the real time required for each push() call. Explicitly increment
// the timestamp for each one -- but since we're passing explicit
// timestamps, make the queue reorder them.
queue.push(Queue::TimeTuple(Queue::Clock::now() + 200ms, "ghi"));
auto now{ Queue::Clock::now() };
queue.push(Queue::TimeTuple(now + 200ms, "ghi"));
// Given the various push() overloads, you have to match the type
// exactly: conversions are ambiguous.
queue.push("abc"s);
queue.push(Queue::Clock::now() + 100ms, "def");
queue.push(now + 100ms, "def");
queue.close();
auto entry = queue.pop();
ensure_equals("failed to pop first", std::get<0>(entry), "abc"s);

View File

@ -60,12 +60,15 @@ struct sleepy_robin: public boost::fibers::algo::round_robin
/*****************************************************************************
* ThreadPoolBase
*****************************************************************************/
LL::ThreadPoolBase::ThreadPoolBase(const std::string& name, size_t threads,
WorkQueueBase* queue):
LL::ThreadPoolBase::ThreadPoolBase(const std::string& name,
size_t threads,
WorkQueueBase* queue,
bool auto_shutdown):
super(name),
mName("ThreadPool:" + name),
mThreadCount(getConfiguredWidth(name, threads)),
mQueue(queue)
mQueue(queue),
mAutomaticShutdown(auto_shutdown)
{}
void LL::ThreadPoolBase::start()
@ -79,6 +82,14 @@ void LL::ThreadPoolBase::start()
run(tname);
});
}
if (!mAutomaticShutdown)
{
// Some threads, like main window's might need to run a bit longer
// to wait for a proper shutdown message
return;
}
// Listen on "LLApp", and when the app is shutting down, close the queue
// and join the workers.
LLEventPumps::instance().obtain("LLApp").listen(
@ -109,8 +120,11 @@ void LL::ThreadPoolBase::close()
mQueue->close();
for (auto& pair: mThreads)
{
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
pair.second.join();
if (pair.second.joinable())
{
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
pair.second.join();
}
}
LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL;
}

View File

@ -40,7 +40,7 @@ namespace LL
* overrides this parameter.
*/
ThreadPoolBase(const std::string& name, size_t threads,
WorkQueueBase* queue);
WorkQueueBase* queue, bool auto_shutdown = true);
virtual ~ThreadPoolBase();
/**
@ -55,7 +55,7 @@ namespace LL
* ThreadPool listens for application shutdown messages on the "LLApp"
* LLEventPump. Call close() to shut down this ThreadPool early.
*/
void close();
virtual void close();
std::string getName() const { return mName; }
size_t getWidth() const { return mThreads.size(); }
@ -87,13 +87,14 @@ namespace LL
protected:
std::unique_ptr<WorkQueueBase> mQueue;
std::vector<std::pair<std::string, std::thread>> mThreads;
bool mAutomaticShutdown;
private:
void run(const std::string& name);
std::string mName;
size_t mThreadCount;
std::vector<std::pair<std::string, std::thread>> mThreads;
};
/**
@ -117,8 +118,11 @@ namespace LL
* Constraining the queue can cause a submitter to block. Do not
* constrain any ThreadPool accepting work from the main thread.
*/
ThreadPoolUsing(const std::string& name, size_t threads=1, size_t capacity=1024*1024):
ThreadPoolBase(name, threads, new queue_t(name, capacity))
ThreadPoolUsing(const std::string& name,
size_t threads=1,
size_t capacity=1024*1024,
bool auto_shutdown = true):
ThreadPoolBase(name, threads, new queue_t(name, capacity), auto_shutdown)
{}
~ThreadPoolUsing() override {}

View File

@ -288,7 +288,7 @@ int BufferArray::findBlock(size_t pos, size_t * ret_offset)
if (pos >= mLen)
return -1; // Doesn't exist
const int block_limit(narrow(mBlocks.size()));
const int block_limit(narrow<size_t>(mBlocks.size()));
for (int i(0); i < block_limit; ++i)
{
if (pos < mBlocks[i]->mUsed)

View File

@ -50,6 +50,7 @@ bool LLImageDimensionsInfo::load(const std::string& src_filename,U32 codec)
if (file_size == 0)
{
mWarning = "texture_load_empty_file";
setLastError("File is empty",src_filename);
return false;
}
@ -90,6 +91,7 @@ bool LLImageDimensionsInfo::getImageDimensionsBmp()
if (signature[0] != 'B' || signature[1] != 'M')
{
LL_WARNS() << "Not a BMP" << LL_ENDL;
mWarning = "texture_load_format_error";
return false;
}
@ -140,6 +142,7 @@ bool LLImageDimensionsInfo::getImageDimensionsPng()
if (memcmp(signature, png_magic, PNG_MAGIC_SIZE) != 0)
{
LL_WARNS() << "Not a PNG" << LL_ENDL;
mWarning = "texture_load_format_error";
return false;
}
@ -183,6 +186,7 @@ bool LLImageDimensionsInfo::getImageDimensionsJpeg()
if (memcmp(signature, jpeg_magic, JPEG_MAGIC_SIZE) != 0)
{
LL_WARNS() << "Not a JPEG" << LL_ENDL;
mWarning = "texture_load_format_error";
return false;
}
fseek(fp, 0, SEEK_SET); // go back to start of the file

View File

@ -55,6 +55,12 @@ public:
{
return mLastError;
}
const std::string& getWarningName()
{
return mWarning;
}
protected:
void clean()
@ -129,6 +135,7 @@ protected:
std::string mSrcFilename;
std::string mLastError;
std::string mWarning;
U8* mData;

View File

@ -35,8 +35,10 @@ class ImageRequest
{
public:
ImageRequest(const LLPointer<LLImageFormatted>& image,
S32 discard, BOOL needs_aux,
const LLPointer<LLImageDecodeThread::Responder>& responder);
S32 discard,
BOOL needs_aux,
const LLPointer<LLImageDecodeThread::Responder>& responder,
U32 request_id);
virtual ~ImageRequest();
/*virtual*/ bool processRequest();
@ -48,6 +50,7 @@ private:
// input
LLPointer<LLImageFormatted> mFormattedImage;
S32 mDiscardLevel;
U32 mRequestId;
BOOL mNeedsAux;
// output
LLPointer<LLImageRaw> mDecodedImageRaw;
@ -62,6 +65,7 @@ private:
// MAIN THREAD
LLImageDecodeThread::LLImageDecodeThread(bool /*threaded*/)
: mDecodeCount(0)
{
mThreadPool.reset(new LL::ThreadPool("ImageDecode", 8));
mThreadPool->start();
@ -92,9 +96,10 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
U32 decode_id = ++mDecodeCount;
// Instantiate the ImageRequest right in the lambda, why not?
bool posted = mThreadPool->getQueue().post(
[req = ImageRequest(image, discard, needs_aux, responder)]
[req = ImageRequest(image, discard, needs_aux, responder, decode_id)]
() mutable
{
auto done = req.processRequest();
@ -103,13 +108,10 @@ LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(
if (! posted)
{
LL_DEBUGS() << "Tried to start decoding on shutdown" << LL_ENDL;
// should this return 0?
return 0;
}
// It's important to our consumer (LLTextureFetchWorker) that we return a
// nonzero handle. It is NOT important that the nonzero handle be unique:
// nothing is ever done with it except to compare it to zero, or zero it.
return 17;
return decode_id;
}
void LLImageDecodeThread::shutdown()
@ -123,15 +125,18 @@ LLImageDecodeThread::Responder::~Responder()
//----------------------------------------------------------------------------
ImageRequest::ImageRequest(const LLPointer<LLImageFormatted>& image,
S32 discard, BOOL needs_aux,
const LLPointer<LLImageDecodeThread::Responder>& responder)
ImageRequest::ImageRequest(const LLPointer<LLImageFormatted>& image,
S32 discard,
BOOL needs_aux,
const LLPointer<LLImageDecodeThread::Responder>& responder,
U32 request_id)
: mFormattedImage(image),
mDiscardLevel(discard),
mNeedsAux(needs_aux),
mDecodedRaw(FALSE),
mDecodedAux(FALSE),
mResponder(responder)
mResponder(responder),
mRequestId(request_id)
{
}
@ -199,7 +204,7 @@ void ImageRequest::finishRequest(bool completed)
if (mResponder.notNull())
{
bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux);
mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux, mRequestId);
}
// Will automatically be deleted
}

View File

@ -39,7 +39,7 @@ public:
protected:
virtual ~Responder();
public:
virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0;
virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux, U32 request_id) = 0;
};
public:
@ -53,6 +53,7 @@ public:
const LLPointer<Responder>& responder);
size_t getPending();
size_t update(F32 max_time_ms);
S32 getTotalDecodeCount() { return mDecodeCount; }
void shutdown();
private:
@ -60,6 +61,7 @@ private:
// LLQueuedThread - instead this is the API by which we submit work to the
// "ImageDecode" ThreadPool.
std::unique_ptr<LL::ThreadPool> mThreadPool;
LLAtomicU32 mDecodeCount;
};
#endif

View File

@ -5592,9 +5592,9 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
U32 stream_count = data.w.empty() ? 4 : 5;
U32 vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count);
size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count);
if (vert_count < 65535)
if (vert_count < 65535 && vert_count != 0)
{
std::vector<U32> indices;
indices.resize(mNumIndices);
@ -5613,6 +5613,13 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
{
U32 src_idx = i;
U32 dst_idx = remap[i];
if (dst_idx >= mNumVertices)
{
dst_idx = mNumVertices - 1;
// Shouldn't happen, figure out what gets returned in remap and why.
llassert(false);
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL;
}
mIndices[i] = dst_idx;
mPositions[dst_idx].load3(data.p[src_idx].mV);
@ -5646,6 +5653,10 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
}
else
{
if (vert_count == 0)
{
LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL;
}
// blew past the max vertex size limit, use legacy tangent generation which never adds verts
createTangents();
}

View File

@ -386,12 +386,3 @@ std::ostream& operator<< (std::ostream& os, LLXfer &hh)
os << hh.getFileName() ;
return os;
}

View File

@ -1041,7 +1041,12 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
weight_map::iterator iterPos = mSkinWeights.begin();
weight_map::iterator iterEnd = mSkinWeights.end();
llassert(!mSkinWeights.empty());
if (mSkinWeights.empty())
{
// function calls iter->second on all return paths
// everything that calls this function should precheck that there is data.
LL_ERRS() << "called getJointInfluences with empty weights list" << LL_ENDL;
}
for ( ; iterPos!=iterEnd; ++iterPos )
{
@ -1068,11 +1073,16 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
const F32 epsilon = 1e-5f;
weight_map::iterator iter_up = mSkinWeights.lower_bound(pos);
weight_map::iterator iter_down = iter_up;
if (iter_up != mSkinWeights.end())
{
iter_down = ++iter_up;
}
weight_map::iterator best = iter_up;
weight_map::iterator best = iter_up;
if (iter_up != mSkinWeights.end())
{
iter_down = ++iter_up;
}
else
{
// Assumes that there is at least one element
--best;
}
F32 min_dist = (iter->first - pos).magVec();

View File

@ -94,6 +94,17 @@ void APIENTRY gl_debug_callback(GLenum source,
return;
}*/
if (gGLManager.mIsDisabled &&
severity == GL_DEBUG_SEVERITY_HIGH_ARB &&
source == GL_DEBUG_SOURCE_API_ARB &&
type == GL_DEBUG_TYPE_ERROR_ARB &&
id == GL_INVALID_VALUE)
{
// Suppress messages about deleting already deleted objects called from LLViewerWindow::stopGL()
// "GL_INVALID_VALUE error generated. Handle does not refer to an object generated by OpenGL."
return;
}
// list of messages to suppress
const char* suppress[] =
{
@ -148,8 +159,9 @@ void APIENTRY gl_debug_callback(GLenum source,
glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_SIZE, &ubo_size);
glGetBufferParameteriv(GL_UNIFORM_BUFFER, GL_BUFFER_IMMUTABLE_STORAGE, &ubo_immutable);
}
if (severity == GL_DEBUG_SEVERITY_HIGH)
// No needs to halt when is called from LLViewerWindow::stopGL()
if (severity == GL_DEBUG_SEVERITY_HIGH && !gGLManager.mIsDisabled)
{
LL_ERRS() << "Halting on GL Error" << LL_ENDL;
}

View File

@ -126,12 +126,12 @@ public:
void setSelected(bool is_selected);
bool getCollapsible() {return mCollapsible;};
bool getCollapsible() { return mCollapsible; };
void setCollapsible(bool collapsible) {mCollapsible = collapsible;};
void setCollapsible(bool collapsible) { mCollapsible = collapsible; };
void changeOpenClose(bool is_open);
void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close;};
void canOpenClose(bool can_open_close) { mCanOpenClose = can_open_close; };
bool canOpenClose() const { return mCanOpenClose; };
virtual BOOL postBuild();
@ -142,8 +142,8 @@ public:
void draw();
void storeOpenCloseState ();
void restoreOpenCloseState ();
void storeOpenCloseState();
void restoreOpenCloseState();
protected:
LLAccordionCtrlTab(const LLAccordionCtrlTab::Params&);

View File

@ -288,7 +288,7 @@ void LLContainerView::setLabel(const std::string& label)
mLabel = label;
}
void LLContainerView::setDisplayChildren(const BOOL displayChildren)
void LLContainerView::setDisplayChildren(BOOL displayChildren)
{
mDisplayChildren = displayChildren;
for (child_list_const_iter_t child_iter = getChildList()->begin();

View File

@ -78,7 +78,7 @@ public:
void setLabel(const std::string& label);
void showLabel(BOOL show) { mShowLabel = show; }
void setDisplayChildren(const BOOL displayChildren);
void setDisplayChildren(BOOL displayChildren);
BOOL getDisplayChildren() { return mDisplayChildren; }
void setScrollContainer(LLScrollContainer* scroll) {mScrollContainer = scroll;}

View File

@ -1361,26 +1361,28 @@ void LLFlatListViewEx::setForceShowingUnmatchedItems(bool show)
mForceShowingUnmatchedItems = show;
}
void LLFlatListViewEx::setFilterSubString(const std::string& filter_str)
void LLFlatListViewEx::setFilterSubString(const std::string& filter_str, bool notify_parent)
{
if (0 != LLStringUtil::compareInsensitive(filter_str, mFilterSubString))
{
mFilterSubString = filter_str;
updateNoItemsMessage(mFilterSubString);
filterItems();
filterItems(false, notify_parent);
}
}
void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
bool LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
{
if (!item) return;
if (!item)
return false;
BOOL visible = TRUE;
// 0 signifies that filter is matched,
// i.e. we don't hide items that don't support 'match_filter' action, separators etc.
if (0 == item->notify(action))
{
mHasMatchedItems = true;
item->setVisible(true);
}
else
{
@ -1388,34 +1390,45 @@ void LLFlatListViewEx::updateItemVisibility(LLPanel* item, const LLSD &action)
if (!mForceShowingUnmatchedItems)
{
selectItem(item, false);
visible = FALSE;
}
item->setVisible(mForceShowingUnmatchedItems);
}
if (item->getVisible() != visible)
{
item->setVisible(visible);
return true;
}
return false;
}
void LLFlatListViewEx::filterItems()
void LLFlatListViewEx::filterItems(bool re_sort, bool notify_parent)
{
typedef std::vector <LLPanel*> item_panel_list_t;
std::string cur_filter = mFilterSubString;
LLStringUtil::toUpper(cur_filter);
LLSD action;
action.with("match_filter", cur_filter);
item_panel_list_t items;
getItems(items);
mHasMatchedItems = false;
item_panel_list_t::iterator iter = items.begin(), iter_end = items.end();
while (iter < iter_end)
bool visibility_changed = false;
pairs_const_iterator_t iter = getItemPairs().begin(), iter_end = getItemPairs().end();
while (iter != iter_end)
{
LLPanel* pItem = *(iter++);
updateItemVisibility(pItem, action);
LLPanel* pItem = (*(iter++))->first;
visibility_changed |= updateItemVisibility(pItem, action);
}
sort();
notifyParentItemsRectChanged();
if (re_sort)
{
sort();
}
if (visibility_changed && notify_parent)
{
notifyParentItemsRectChanged();
}
}
bool LLFlatListViewEx::hasMatchedItems()

View File

@ -300,6 +300,7 @@ public:
virtual S32 notify(const LLSD& info) ;
virtual ~LLFlatListView();
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
@ -375,7 +376,9 @@ protected:
LLRect getLastSelectedItemRect();
void ensureSelectedVisible();
void ensureSelectedVisible();
const pairs_list_t& getItemPairs() { return mItemPairs; }
private:
@ -482,14 +485,14 @@ public:
/**
* Sets up new filter string and filters the list.
*/
void setFilterSubString(const std::string& filter_str);
void setFilterSubString(const std::string& filter_str, bool notify_parent);
std::string getFilterSubString() { return mFilterSubString; }
/**
* Filters the list, rearranges and notifies parent about shape changes.
* Derived classes may want to overload rearrangeItems() to exclude repeated separators after filtration.
*/
void filterItems();
void filterItems(bool re_sort, bool notify_parent);
/**
* Returns true if last call of filterItems() found at least one matching item
@ -513,7 +516,7 @@ protected:
* @param item - item we are changing
* @param item - action - parameters to determin visibility from
*/
void updateItemVisibility(LLPanel* item, const LLSD &action);
bool updateItemVisibility(LLPanel* item, const LLSD &action);
private:
std::string mNoFilteredItemsMsg;

View File

@ -506,7 +506,6 @@ void LLFloater::enableResizeCtrls(bool enable, bool width, bool height)
void LLFloater::destroy()
{
gFloaterView->onDestroyFloater(this);
// LLFloaterReg should be synchronized with "dead" floater to avoid returning dead instance before
// it was deleted via LLMortician::updateClass(). See EXT-8458.
LLFloaterReg::removeInstance(mInstanceName, mKey);
@ -2407,8 +2406,7 @@ LLFloaterView::LLFloaterView (const Params& p)
mFocusCycleMode(FALSE),
mMinimizePositionVOffset(0),
mSnapOffsetBottom(0),
mSnapOffsetRight(0),
mFrontChild(NULL)
mSnapOffsetRight(0)
{
mSnapView = getHandle();
}
@ -2564,7 +2562,8 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore
if (!child)
return;
if (mFrontChild == child)
LLFloater* front_child = mFrontChildHandle.get();
if (front_child == child)
{
if (give_focus && child->canFocusStealFrontmost() && !gFocusMgr.childHasKeyboardFocus(child))
{
@ -2573,12 +2572,12 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore
return;
}
if (mFrontChild)
if (front_child && front_child->getVisible())
{
mFrontChild->goneFromFront();
front_child->goneFromFront();
}
mFrontChild = child;
mFrontChildHandle = child->getHandle();
// *TODO: make this respect floater's mAutoFocus value, instead of
// using parameter
@ -3077,7 +3076,8 @@ LLFloater *LLFloaterView::getBackmost() const
void LLFloaterView::syncFloaterTabOrder()
{
if (mFrontChild && !mFrontChild->isDead() && mFrontChild->getIsChrome())
LLFloater* front_child = mFrontChildHandle.get();
if (front_child && front_child->getIsChrome())
return;
// look for a visible modal dialog, starting from first
@ -3115,11 +3115,12 @@ void LLFloaterView::syncFloaterTabOrder()
LLFloater* floaterp = dynamic_cast<LLFloater*>(*child_it);
if (gFocusMgr.childHasKeyboardFocus(floaterp))
{
if (mFrontChild != floaterp)
LLFloater* front_child = mFrontChildHandle.get();
if (front_child != floaterp)
{
// Grab a list of the top floaters that want to stay on top of the focused floater
std::list<LLFloater*> listTop;
if (mFrontChild && !mFrontChild->canFocusStealFrontmost())
if (front_child && !front_child->canFocusStealFrontmost())
{
for (LLView* childp : *getChildList())
{
@ -3139,7 +3140,7 @@ void LLFloaterView::syncFloaterTabOrder()
{
sendChildToFront(childp);
}
mFrontChild = listTop.back();
mFrontChildHandle = listTop.back()->getHandle();
}
}
@ -3235,14 +3236,6 @@ void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LL
}
}
void LLFloaterView::onDestroyFloater(LLFloater* floater)
{
if (mFrontChild == floater)
{
mFrontChild = nullptr;
}
}
void LLFloater::setInstanceName(const std::string& name)
{
if (name != mInstanceName)

View File

@ -607,7 +607,6 @@ public:
LLFloater* getFrontmostClosableFloater();
void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect);
void onDestroyFloater(LLFloater* floater);
private:
void hiddenFloaterClosed(LLFloater* floater);
@ -623,7 +622,7 @@ private:
S32 mMinimizePositionVOffset;
typedef std::vector<std::pair<LLHandle<LLFloater>, boost::signals2::connection> > hidden_floaters_t;
hidden_floaters_t mHiddenFloaters;
LLFloater * mFrontChild;
LLHandle<LLFloater> mFrontChildHandle;
};
//

View File

@ -187,14 +187,18 @@ LLFolderViewItem::~LLFolderViewItem()
BOOL LLFolderViewItem::postBuild()
{
LLFolderViewModelItem& vmi = *getViewModelItem();
// getDisplayName() is expensive (due to internal getLabelSuffix() and name building)
// it also sets search strings so it requires a filter reset
mLabel = vmi.getDisplayName();
setToolTip(vmi.getName());
LLFolderViewModelItem* vmi = getViewModelItem();
llassert(vmi); // not supposed to happen, if happens, find out why and fix
if (vmi)
{
// getDisplayName() is expensive (due to internal getLabelSuffix() and name building)
// it also sets search strings so it requires a filter reset
mLabel = vmi->getDisplayName();
setToolTip(vmi->getName());
// Dirty the filter flag of the model from the view (CHUI-849)
vmi.dirtyFilter();
// Dirty the filter flag of the model from the view (CHUI-849)
vmi->dirtyFilter();
}
// Don't do full refresh on constructor if it is possible to avoid
// it significantly slows down bulk view creation.

View File

@ -479,7 +479,7 @@ LLTrace::BlockTimerStatHandle FTM_SYNTAX_COLORING("Syntax Coloring");
// Walk through a string, applying the rules specified by the keyword token list and
// create a list of color segments.
void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLWString& wtext, const LLColor4 &defaultColor, LLTextEditor& editor)
void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLWString& wtext, LLTextEditor& editor, LLStyleConstSP style)
{
LL_RECORD_BLOCK_TIME(FTM_SYNTAX_COLORING);
seg_list->clear();
@ -491,7 +491,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
S32 text_len = wtext.size() + 1;
seg_list->push_back( new LLNormalTextSegment( defaultColor, 0, text_len, editor ) );
seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) );
const llwchar* base = wtext.c_str();
const llwchar* cur = base;
@ -501,9 +501,9 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
{
if( *cur == '\n' )
{
LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(cur-base);
LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, cur-base);
text_segment->setToken( 0 );
insertSegment( *seg_list, text_segment, text_len, defaultColor, editor);
insertSegment( *seg_list, text_segment, text_len, style, editor);
cur++;
if( !*cur || *cur == '\n' )
{
@ -541,7 +541,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
S32 seg_end = cur - base;
//create segments from seg_start to seg_end
insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, defaultColor, editor);
insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor);
line_done = TRUE; // to break out of second loop.
break;
}
@ -648,7 +648,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
seg_end = seg_start + between_delimiters + cur_delimiter->getLengthHead();
}
insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, defaultColor, editor);
insertSegments(wtext, *seg_list,cur_delimiter, text_len, seg_start, seg_end, style, editor);
/*
LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_delimiter->getColor(), seg_start, seg_end, editor );
text_segment->setToken( cur_delimiter );
@ -682,7 +682,7 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
// LL_INFOS("SyntaxLSL") << "Seg: [" << word.c_str() << "]" << LL_ENDL;
insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, defaultColor, editor);
insertSegments(wtext, *seg_list,cur_token, text_len, seg_start, seg_end, style, editor);
}
cur += seg_len;
continue;
@ -697,30 +697,32 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
}
}
void LLKeywords::insertSegments(const LLWString& wtext, std::vector<LLTextSegmentPtr>& seg_list, LLKeywordToken* cur_token, S32 text_len, S32 seg_start, S32 seg_end, const LLColor4 &defaultColor, LLTextEditor& editor )
void LLKeywords::insertSegments(const LLWString& wtext, std::vector<LLTextSegmentPtr>& seg_list, LLKeywordToken* cur_token, S32 text_len, S32 seg_start, S32 seg_end, LLStyleConstSP style, LLTextEditor& editor )
{
std::string::size_type pos = wtext.find('\n',seg_start);
LLStyleConstSP cur_token_style = new LLStyle(LLStyle::Params().font(style->getFont()).color(cur_token->getColor()));
while (pos!=-1 && pos < (std::string::size_type)seg_end)
{
if (pos!=seg_start)
{
LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, pos, editor );
LLTextSegmentPtr text_segment = new LLNormalTextSegment(cur_token_style, seg_start, pos, editor);
text_segment->setToken( cur_token );
insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
insertSegment( seg_list, text_segment, text_len, style, editor);
}
LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(pos);
LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, pos);
text_segment->setToken( cur_token );
insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
insertSegment( seg_list, text_segment, text_len, style, editor);
seg_start = pos+1;
pos = wtext.find('\n',seg_start);
}
LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, seg_end, editor );
LLTextSegmentPtr text_segment = new LLNormalTextSegment(cur_token_style, seg_start, seg_end, editor);
text_segment->setToken( cur_token );
insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
insertSegment( seg_list, text_segment, text_len, style, editor);
}
void LLKeywords::insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, LLTextEditor& editor )
@ -744,6 +746,27 @@ void LLKeywords::insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSe
}
}
void LLKeywords::insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, LLStyleConstSP style, LLTextEditor& editor )
{
LLTextSegmentPtr last = seg_list.back();
S32 new_seg_end = new_segment->getEnd();
if( new_segment->getStart() == last->getStart() )
{
seg_list.pop_back();
}
else
{
last->setEnd( new_segment->getStart() );
}
seg_list.push_back( new_segment );
if( new_seg_end < text_len )
{
seg_list.push_back( new LLNormalTextSegment( style, new_seg_end, text_len, editor ) );
}
}
#ifdef _DEBUG
void LLKeywords::dump()
{

View File

@ -29,6 +29,7 @@
#include "lldir.h"
#include "llstyle.h"
#include "llstring.h"
#include "v3color.h"
#include "v4color.h"
@ -115,8 +116,8 @@ public:
void findSegments(std::vector<LLTextSegmentPtr> *seg_list,
const LLWString& text,
const LLColor4 &defaultColor,
class LLTextEditor& editor);
class LLTextEditor& editor,
LLStyleConstSP style);
void initialize(LLSD SyntaxXML);
void processTokens();
@ -181,9 +182,11 @@ protected:
S32 text_len,
S32 seg_start,
S32 seg_end,
const LLColor4 &defaultColor,
LLStyleConstSP style,
LLTextEditor& editor);
void insertSegment(std::vector<LLTextSegmentPtr>& seg_list, LLTextSegmentPtr new_segment, S32 text_len, LLStyleConstSP style, LLTextEditor& editor );
bool mLoaded;
LLSD mSyntax;
word_token_map_t mWordTokenMap;

View File

@ -1788,7 +1788,8 @@ LLMenuGL::LLMenuGL(const LLMenuGL::Params& p)
mNeedsArrange(FALSE),
mAlwaysShowMenu(FALSE),
mResetScrollPositionOnShow(true),
mShortcutPad(p.shortcut_pad)
mShortcutPad(p.shortcut_pad),
mFont(p.font)
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
boost::char_separator<char> sep("_");
@ -3647,6 +3648,7 @@ BOOL LLMenuBarGL::appendMenu( LLMenuGL* menu )
p.disabled_color=LLUIColorTable::instance().getColor("MenuItemDisabledColor");
p.highlight_bg_color=LLUIColorTable::instance().getColor("MenuItemHighlightBgColor");
p.highlight_fg_color=LLUIColorTable::instance().getColor("MenuItemHighlightFgColor");
p.font = menu->getFont();
LLMenuItemBranchDownGL* branch = LLUICtrlFactory::create<LLMenuItemBranchDownGL>(p);
success &= branch->addToAcceleratorList(&mAccelerators);

View File

@ -562,7 +562,9 @@ public:
// add a context menu branch
BOOL appendContextSubMenu(LLMenuGL *menu);
protected:
const LLFontGL *getFont() const { return mFont; }
protected:
void createSpilloverBranch();
void cleanupSpilloverBranch();
// Add the menu item to this menu.
@ -594,6 +596,9 @@ protected:
BOOL mKeepFixedSize;
BOOL mNeedsArrange;
// Font for top menu items only
const LLFontGL* mFont;
private:

View File

@ -181,7 +181,7 @@ LLStatBar::LLStatBar(const Params& p)
mTargetMinBar(llmin(p.bar_min, p.bar_max)),
mTargetMaxBar(llmax(p.bar_max, p.bar_min)),
mCurMaxBar(p.bar_max),
mCurMinBar(0),
mCurMinBar(0),
mDecimalDigits(p.decimal_digits),
mNumHistoryFrames(p.num_frames),
mNumShortHistoryFrames(p.num_frames_short),
@ -222,9 +222,6 @@ BOOL LLStatBar::handleHover(S32 x, S32 y, MASK mask)
case STAT_SAMPLE:
LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.sampleStatp->getDescription()).sticky_rect(calcScreenRect()));
break;
case STAT_MEM:
LLToolTipMgr::instance().show(LLToolTip::Params().message(mStat.memStatp->getDescription()).sticky_rect(calcScreenRect()));
break;
default:
break;
}
@ -373,18 +370,6 @@ void LLStatBar::draw()
}
}
break;
case STAT_MEM:
{
const LLTrace::StatType<LLTrace::MemAccumulator>& mem_stat = *mStat.memStatp;
unit_label = mUnitLabel.empty() ? mem_stat.getUnitLabel() : mUnitLabel;
current = last_frame_recording.getLastValue(mem_stat).value();
min = frame_recording.getPeriodMin(mem_stat, num_frames).value();
max = frame_recording.getPeriodMax(mem_stat, num_frames).value();
mean = frame_recording.getPeriodMean(mem_stat, num_frames).value();
display_value = current;
}
break;
default:
break;
}
@ -500,11 +485,6 @@ void LLStatBar::draw()
max_value = recording.getMax(*mStat.sampleStatp);
num_samples = recording.getSampleCount(*mStat.sampleStatp);
break;
case STAT_MEM:
min_value = recording.getMin(*mStat.memStatp).value();
max_value = recording.getMax(*mStat.memStatp).value();
num_samples = 1;
break;
default:
break;
}
@ -583,14 +563,8 @@ void LLStatBar::setStat(const std::string& stat_name)
mStat.sampleStatp = sample_stat.get();
mStatType = STAT_SAMPLE;
}
else if (auto mem_stat = StatType<MemAccumulator>::getInstance(stat_name))
{
mStat.memStatp = mem_stat.get();
mStatType = STAT_MEM;
}
}
void LLStatBar::setRange(F32 bar_min, F32 bar_max)
{
mTargetMinBar = llmin(bar_min, bar_max);

View File

@ -95,17 +95,15 @@ private:
STAT_NONE,
STAT_COUNT,
STAT_EVENT,
STAT_SAMPLE,
STAT_MEM
STAT_SAMPLE
} mStatType;
union
{
void* valid;
void* valid;
const LLTrace::StatType<LLTrace::CountAccumulator>* countStatp;
const LLTrace::StatType<LLTrace::EventAccumulator>* eventStatp;
const LLTrace::StatType<LLTrace::SampleAccumulator>* sampleStatp;
const LLTrace::StatType<LLTrace::MemAccumulator>* memStatp;
const LLTrace::StatType<LLTrace::SampleAccumulator>* sampleStatp;
} mStat;
LLUIString mLabel;

View File

@ -58,10 +58,7 @@ LLStatView::~LLStatView()
}
}
static StatViewRegistry::Register<LLStatBar> r1("stat_bar");
static StatViewRegistry::Register<LLStatView> r2("stat_view");
// stat_view can be a child of panels/etc.
static LLDefaultChildRegistry::Register<LLStatView> r3("stat_view");

View File

@ -63,7 +63,7 @@ protected:
friend class LLUICtrlFactory;
protected:
std::string mSetting;
const std::string mSetting;
};
#endif // LL_STATVIEW_

View File

@ -1516,25 +1516,23 @@ BOOL LLTabContainer::selectTab(S32 which)
LLTabTuple* selected_tuple = getTab(which);
if (!selected_tuple)
{
return FALSE;
}
LLSD cbdata;
if (selected_tuple->mTabPanel)
cbdata = selected_tuple->mTabPanel->getName();
BOOL res = FALSE;
if( !mValidateSignal || (*mValidateSignal)( this, cbdata ) )
BOOL result = FALSE;
if (!mValidateSignal || (*mValidateSignal)(this, cbdata))
{
res = setTab(which);
if (res && mCommitSignal)
result = setTab(which);
if (result && mCommitSignal)
{
(*mCommitSignal)(this, cbdata);
}
}
return res;
return result;
}
// private

View File

@ -3470,7 +3470,7 @@ BOOL LLNormalTextSegment::handleToolTip(S32 x, S32 y, MASK mask)
if (mToken && !mToken->getToolTip().empty())
{
const LLWString& wmsg = mToken->getToolTip();
LLToolTipMgr::instance().show(wstring_to_utf8str(wmsg));
LLToolTipMgr::instance().show(wstring_to_utf8str(wmsg), (mToken->getType() == LLKeywordToken::TT_FUNCTION));
return TRUE;
}
// or do we have an explicitly set tooltip (e.g., for Urls)

View File

@ -1862,7 +1862,8 @@ BOOL LLTextEditor::handleKeyHere(KEY key, MASK mask )
}
if (mEnableTooltipPaste &&
LLToolTipMgr::instance().toolTipVisible() &&
LLToolTipMgr::instance().toolTipVisible() &&
LLToolTipMgr::instance().isTooltipPastable() &&
KEY_TAB == key)
{ // Paste the first line of a tooltip into the editor
std::string message;

View File

@ -154,7 +154,8 @@ LLToolTip::Params::Params()
text_color("text_color"),
time_based_media("time_based_media", false),
web_based_media("web_based_media", false),
media_playing("media_playing", false)
media_playing("media_playing", false),
allow_paste_tooltip("allow_paste_tooltip", false)
{
changeDefault(chrome, true);
}
@ -167,7 +168,8 @@ LLToolTip::LLToolTip(const LLToolTip::Params& p)
mTextBox(NULL),
mInfoButton(NULL),
mPlayMediaButton(NULL),
mHomePageButton(NULL)
mHomePageButton(NULL),
mIsTooltipPastable(p.allow_paste_tooltip)
{
LLTextBox::Params params;
params.name = params.initial_value().asString();
@ -289,6 +291,8 @@ void LLToolTip::initFromParams(const LLToolTip::Params& p)
mTextBox->setText(p.message());
}
mIsTooltipPastable = p.allow_paste_tooltip;
updateTextBox();
snapToChildren();
}
@ -483,9 +487,9 @@ void LLToolTipMgr::createToolTip(const LLToolTip::Params& params)
}
void LLToolTipMgr::show(const std::string& msg)
void LLToolTipMgr::show(const std::string& msg, bool allow_paste_tooltip)
{
show(LLToolTip::Params().message(msg));
show(LLToolTip::Params().message(msg).allow_paste_tooltip(allow_paste_tooltip));
}
void LLToolTipMgr::show(const LLToolTip::Params& params)
@ -626,5 +630,13 @@ void LLToolTipMgr::getToolTipMessage(std::string & message)
}
}
bool LLToolTipMgr::isTooltipPastable()
{
if (toolTipVisible())
{
return mToolTip->isTooltipPastable();
}
return false;
}
// EOF

View File

@ -94,6 +94,8 @@ public:
padding;
Optional<bool> wrap;
Optional<bool> allow_paste_tooltip;
Params();
};
/*virtual*/ void draw();
@ -109,6 +111,7 @@ public:
virtual void initFromParams(const LLToolTip::Params& params);
void getToolTipMessage(std::string & message);
bool isTooltipPastable() { return mIsTooltipPastable; }
protected:
void updateTextBox();
@ -125,6 +128,8 @@ protected:
bool mHasClickCallback;
S32 mPadding; // pixels
S32 mMaxWidth;
bool mIsTooltipPastable;
};
// used for the inspector tooltips which need different background images etc.
@ -142,7 +147,7 @@ class LLToolTipMgr : public LLSingleton<LLToolTipMgr>
public:
void show(const LLToolTip::Params& params);
void show(const std::string& message);
void show(const std::string& message, bool allow_paste_tooltip = false);
void unblockToolTips();
void blockToolTips();
@ -154,6 +159,7 @@ public:
void updateToolTipVisibility();
void getToolTipMessage(std::string & message);
bool isTooltipPastable();
private:
void createToolTip(const LLToolTip::Params& params);

View File

@ -234,14 +234,20 @@ bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const
std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const
{
if (url.empty())
{
return url;
}
LLUriParser up(escapeUrl(url));
up.normalize();
if (up.normalize() == 0)
{
std::string label;
up.extractParts();
up.glueFirst(label);
std::string label;
up.extractParts();
up.glueFirst(label);
return unescapeUrl(label);
return unescapeUrl(label);
}
return std::string();
}
std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const

View File

@ -221,8 +221,10 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
if (match_entry == mUrlEntryTrusted)
{
LLUriParser up(url);
up.normalize();
url = up.normalizedUri();
if (up.normalize() == 0)
{
url = up.normalizedUri();
}
}
match.setValues(match_start, match_end,

View File

@ -351,6 +351,10 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
LLWindowWin32Thread();
void run() override;
void close() override;
// closes queue, wakes thread, waits until thread closes
void wakeAndDestroy();
void glReady()
{
@ -363,6 +367,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
// initialize D3D (if DXGI cannot be used)
void initD3D();
//clean up DXGI/D3D resources
void cleanupDX();
// call periodically to update available VRAM
void updateVRAMUsage();
@ -412,8 +419,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
using FuncType = std::function<void()>;
// call GetMessage() and pull enqueue messages for later processing
void gatherInput();
HWND mWindowHandle = NULL;
HDC mhDC = 0;
HWND mWindowHandleThrd = NULL;
HDC mhDCThrd = 0;
// *HACK: Attempt to prevent startup crashes by deferring memory accounting
// until after some graphics setup. See SL-20177. -Cosmic,2023-09-18
@ -987,46 +994,10 @@ void LLWindowWin32::close()
LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
mWindowThread->post([=]()
{
if (IsWindow(mWindowHandle))
{
if (mhDC)
{
if (!ReleaseDC(mWindowHandle, mhDC))
{
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
}
}
// Make sure we don't leave a blank toolbar button.
ShowWindow(mWindowHandle, SW_HIDE);
// This causes WM_DESTROY to be sent *immediately*
if (!destroy_window_handler(mWindowHandle))
{
OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
mCallbacks->translateString("MBShutdownErr"),
OSMB_OK);
}
}
else
{
// Something killed the window while we were busy destroying gl or handle somehow got broken
LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
}
});
// Window thread might be waiting for a getMessage(), give it
// a push to enshure it will process destroy_window_handler
kickWindowThread();
// Even though the above lambda might not yet have run, we've already
// bound mWindowHandle into it by value, which should suffice for the
// operations we're asking. That's the last time WE should touch it.
mhDC = NULL;
mWindowHandle = NULL;
mWindowThread->close();
mWindowThread->wakeAndDestroy();
}
BOOL LLWindowWin32::isValid()
@ -1777,8 +1748,8 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
()
{
LL_DEBUGS("Window") << "recreateWindow(): window_work entry" << LL_ENDL;
self->mWindowHandle = 0;
self->mhDC = 0;
self->mWindowHandleThrd = 0;
self->mhDCThrd = 0;
if (oldWindowHandle)
{
@ -1813,20 +1784,20 @@ void LLWindowWin32::recreateWindow(RECT window_rect, DWORD dw_ex_style, DWORD dw
{
// Failed to create window: clear the variables. This
// assignment is valid because we're running on mWindowThread.
self->mWindowHandle = NULL;
self->mhDC = 0;
self->mWindowHandleThrd = NULL;
self->mhDCThrd = 0;
}
else
{
// Update mWindowThread's own mWindowHandle and mhDC.
self->mWindowHandle = handle;
self->mhDC = GetDC(handle);
self->mWindowHandleThrd = handle;
self->mhDCThrd = GetDC(handle);
}
updateWindowRect();
// It's important to wake up the future either way.
promise.set_value(std::make_pair(self->mWindowHandle, self->mhDC));
promise.set_value(std::make_pair(self->mWindowHandleThrd, self->mhDCThrd));
LL_DEBUGS("Window") << "recreateWindow(): window_work done" << LL_ENDL;
};
// But how we pass window_work to the window thread depends on whether we
@ -3656,6 +3627,9 @@ void LLSplashScreenWin32::showImpl()
NULL, // no parent
(DLGPROC) LLSplashScreenWin32::windowProc);
ShowWindow(mWindow, SW_SHOW);
// Should set taskbar text without creating a header for the window (caption)
SetWindowTextA(mWindow, "Second Life");
}
@ -4589,11 +4563,25 @@ U32 LLWindowWin32::getAvailableVRAMMegabytes()
#endif // LL_WINDOWS
inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread()
: LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE)
: LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/)
{
LL::ThreadPool::start();
}
void LLWindowWin32::LLWindowWin32Thread::close()
{
if (!mQueue->isClosed())
{
LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL;
LL::ThreadPool::close();
// Workaround for SL-18721 in case window closes too early and abruptly
LLSplashScreen::show();
LLSplashScreen::update("..."); // will be updated later
}
}
/**
* LogChange is to log changes in status while trying to avoid spamming the
* log with repeated messages, especially in a tight loop. It refuses to log
@ -4745,7 +4733,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D()
{
if (!mGLReady) { return; }
if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandle != 0)
if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0)
{
mD3D = Direct3DCreate9(D3D_SDK_VERSION);
@ -4755,7 +4743,7 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D()
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandle, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice);
HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice);
if (FAILED(res))
{
@ -4768,6 +4756,28 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D()
}
}
void LLWindowWin32::LLWindowWin32Thread::cleanupDX()
{
//clean up DXGI/D3D resources
if (mDXGIAdapter)
{
mDXGIAdapter->Release();
mDXGIAdapter = nullptr;
}
if (mD3DDevice)
{
mD3DDevice->Release();
mD3DDevice = nullptr;
}
if (mD3D)
{
mD3D->Release();
mD3D = nullptr;
}
}
void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
{
LL_PROFILE_ZONE_SCOPED;
@ -4861,7 +4871,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
// lazily call initD3D inside this loop to catch when mGLReady has been set to true
initDX();
if (mWindowHandle != 0)
if (mWindowHandleThrd != 0)
{
// lazily call initD3D inside this loop to catch when mWindowHandle has been set, and mGLReady has been set to true
// *TODO: Shutdown if this fails when mWindowHandle exists
@ -4869,16 +4879,16 @@ void LLWindowWin32::LLWindowWin32Thread::run()
MSG msg;
BOOL status;
if (mhDC == 0)
if (mhDCThrd == 0)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - PeekMessage");
logger.onChange("PeekMessage(", std::hex, mWindowHandle, ")");
status = PeekMessage(&msg, mWindowHandle, 0, 0, PM_REMOVE);
logger.onChange("PeekMessage(", std::hex, mWindowHandleThrd, ")");
status = PeekMessage(&msg, mWindowHandleThrd, 0, 0, PM_REMOVE);
}
else
{
LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("w32t - GetMessage");
logger.always("GetMessage(", std::hex, mWindowHandle, ")");
logger.always("GetMessage(", std::hex, mWindowHandleThrd, ")");
status = GetMessage(&msg, NULL, 0, 0);
}
if (status > 0)
@ -4915,25 +4925,110 @@ void LLWindowWin32::LLWindowWin32Thread::run()
#endif
}
//clean up DXGI/D3D resources
if (mDXGIAdapter)
cleanupDX();
}
void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
{
if (mQueue->isClosed())
{
mDXGIAdapter->Release();
mDXGIAdapter = nullptr;
LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL;
return;
}
if (mD3DDevice)
// Make sure we don't leave a blank toolbar button.
// Also hiding window now prevents user from suspending it
// via some action (like dragging it around)
ShowWindow(mWindowHandleThrd, SW_HIDE);
// Schedule destruction
HWND old_handle = mWindowHandleThrd;
post([this]()
{
if (IsWindow(mWindowHandleThrd))
{
if (mhDCThrd)
{
if (!ReleaseDC(mWindowHandleThrd, mhDCThrd))
{
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
}
mhDCThrd = NULL;
}
// This causes WM_DESTROY to be sent *immediately*
if (!destroy_window_handler(mWindowHandleThrd))
{
LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL;
}
}
else
{
// Something killed the window while we were busy destroying gl or handle somehow got broken
LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
}
mWindowHandleThrd = NULL;
mhDCThrd = NULL;
mGLReady = false;
});
LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL;
mQueue->close();
// Post a nonsense user message to wake up the thread in
// case it is waiting for a getMessage()
if (old_handle)
{
mD3DDevice->Release();
mD3DDevice = nullptr;
WPARAM wparam{ 0xB0B0 };
LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
<< ", " << WM_DUMMY_
<< ", " << wparam << ")" << std::dec << LL_ENDL;
PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
}
if (mD3D)
// There are cases where window will refuse to close,
// can't wait forever on join, check state instead
LLTimer timeout;
timeout.setTimerExpirySec(2.0);
while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd)
{
mD3D->Release();
mD3D = nullptr;
ms_sleep(100);
}
if (getQueue().done() || mWindowHandleThrd == NULL)
{
// Window is closed, started closing or is cleaning up
// now wait for our single thread to die.
if (mWindowHandleThrd)
{
LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
}
else
{
LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
}
for (auto& pair : mThreads)
{
pair.second.join();
}
}
else
{
// Something suspended window thread, can't afford to wait forever
// so kill thread instead
// Ex: This can happen if user starts dragging window arround (if it
// was visible) or a modal notification pops up
LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL;
for (auto& pair : mThreads)
{
// very unsafe
TerminateThread(pair.second.native_handle(), 0);
pair.second.detach();
cleanupDX();
}
}
LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
}
void LLWindowWin32::post(const std::function<void()>& func)

View File

@ -1 +1 @@
7.1.5
7.1.6

View File

@ -5387,6 +5387,17 @@
<key>Value</key>
<string>http://wiki.secondlife.com/wiki/[LSL_STRING]</string>
</map>
<key>LSLFontSizeName</key>
<map>
<key>Comment</key>
<string>Text font size in LSL editor</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
<string>Monospace</string>
</map>
<key>GridStatusRSS</key>
<map>
<key>Comment</key>
@ -7463,10 +7474,21 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatBasic</key>
<map>
<key>Comment</key>
<string>Expand Basic performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatAdvanced</key>
<map>
<key>Comment</key>
<string>Expand advanced performance stats display</string>
<string>Expand Advanced performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -7474,43 +7496,10 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>OpenDebugStatBasic</key>
<map>
<key>Comment</key>
<string>Expand basic performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatNet</key>
<map>
<key>Comment</key>
<string>Expand network stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatRender</key>
<map>
<key>Comment</key>
<string>Expand render stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatSim</key>
<map>
<key>Comment</key>
<string>Expand simulator performance stats display</string>
<string>Expand Render performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -7529,6 +7518,39 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>OpenDebugStatMemory</key>
<map>
<key>Comment</key>
<string>Expand Memory Usage stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatNet</key>
<map>
<key>Comment</key>
<string>Expand Network performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatSim</key>
<map>
<key>Comment</key>
<string>Expand Simulator performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatPhysicsDetails</key>
<map>
<key>Comment</key>
@ -7540,6 +7562,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>OpenDebugStatPathfinding</key>
<map>
<key>Comment</key>
<string>Expand Pathfinding performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>OpenDebugStatSimTime</key>
<map>
<key>Comment</key>

View File

@ -2021,7 +2021,7 @@
value_min="-1"
value_max="1">
<param_skeleton>
<bone
name="mEyeLeft"
scale="0 0 0"
@ -2031,9 +2031,8 @@
name="mEyeRight"
scale="0 0 0"
offset="-.005 0 0" />
<bone
<bone
name="mFaceEyeAltLeft"
scale="0 0 0"
offset="-.005 0 0" />
@ -2042,7 +2041,7 @@
name="mFaceEyeAltRight"
scale="0 0 0"
offset="-.005 0 0" />
<bone
name="mFaceEyeLidLowerRight"
scale="0 0.3 0.7"
@ -2053,7 +2052,7 @@
scale="0 0.3 0.7"
offset="0 0 0" />
<bone
<bone
name="mFaceEyeLidUpperRight"
scale="0 0.3 0.7"
offset=" 0 0 0" />
@ -2062,17 +2061,17 @@
name="mFaceEyeLidUpperLeft"
scale="0 0.3 0.7"
offset=" 0 0 0" />
<bone
name="mFaceEyecornerInnerLeft"
scale="0 0 0"
offset="-0.005 -0.008 0.0" />
<bone
name="mFaceEyecornerInnerRight"
scale="0 0 0"
offset="-0.005 0.008 0.0" />
</param_skeleton>
</param>

View File

@ -1892,6 +1892,9 @@ bool LLAppViewer::cleanup()
LL_INFOS() << "ViewerWindow deleted" << LL_ENDL;
}
LLSplashScreen::show();
LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
LL_INFOS() << "Cleaning up Keyboard & Joystick" << LL_ENDL;
// viewer UI relies on keyboard so keep it aound until viewer UI isa gone
@ -2170,6 +2173,8 @@ bool LLAppViewer::cleanup()
// deleteSingleton() methods.
LLSingletonBase::deleteAll();
LLSplashScreen::hide();
LL_INFOS() << "Goodbye!" << LL_ENDL;
removeDumpDir();
@ -2954,13 +2959,14 @@ bool LLAppViewer::initConfiguration()
if (mSecondInstance)
{
// This is the second instance of SL. Turn off voice support,
// This is the second instance of SL. Mute voice,
// but make sure the setting is *not* persisted.
LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice");
if(disable_voice)
// Also see LLVivoxVoiceClient::voiceEnabled()
LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat");
if(enable_voice)
{
const BOOL DO_NOT_PERSIST = FALSE;
disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST);
enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST);
}
}
@ -5071,6 +5077,9 @@ void LLAppViewer::idleShutdown()
&& gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME
&& !logoutRequestSent())
{
gViewerWindow->setShowProgress(TRUE);
gViewerWindow->setProgressPercent(100.f);
gViewerWindow->setProgressString(LLTrans::getString("LoggingOut"));
return;
}
@ -5443,9 +5452,18 @@ void LLAppViewer::forceErrorBadMemoryAccess()
void LLAppViewer::forceErrorInfiniteLoop()
{
LL_WARNS() << "Forcing a deliberate infinite loop" << LL_ENDL;
// Loop is intentionally complicated to fool basic loop detection
LLTimer timer_total;
LLTimer timer_expiry;
const S32 report_frequency = 10;
timer_expiry.setTimerExpirySec(report_frequency);
while(true)
{
;
if (timer_expiry.hasExpired())
{
LL_INFOS() << "Infinite loop time : " << timer_total.getElapsedSeconds() << LL_ENDL;
timer_expiry.setTimerExpirySec(report_frequency);
}
}
return;
}
@ -5456,6 +5474,13 @@ void LLAppViewer::forceErrorSoftwareException()
LLTHROW(LLException("User selected Force Software Exception"));
}
void LLAppViewer::forceErrorOSSpecificException()
{
// Virtual, MacOS only
const std::string exception_text = "User selected Force OS Exception, Not implemented on this OS";
throw std::runtime_error(exception_text);
}
void LLAppViewer::forceErrorDriverCrash()
{
LL_WARNS() << "Forcing a deliberate driver crash" << LL_ENDL;

View File

@ -157,6 +157,7 @@ public:
virtual void forceErrorBadMemoryAccess();
virtual void forceErrorInfiniteLoop();
virtual void forceErrorSoftwareException();
virtual void forceErrorOSSpecificException();
virtual void forceErrorDriverCrash();
virtual void forceErrorCoroutineCrash();
virtual void forceErrorThreadCrash();

View File

@ -33,4 +33,6 @@
//Why? Because BOOL
void launchApplication(const std::string* app_name, const std::vector<std::string>* args);
void force_ns_sxeption();
#endif // LL_LLAPPVIEWERMACOSX_OBJC_H

View File

@ -71,3 +71,9 @@ void launchApplication(const std::string* app_name, const std::vector<std::strin
[pool release];
return;
}
void force_ns_sxeption()
{
NSException *exception = [NSException exceptionWithName:@"Forced NSException" reason:nullptr userInfo:nullptr];
@throw exception;
}

View File

@ -250,6 +250,11 @@ bool LLAppViewerMacOSX::init()
return LLAppViewer::init();
}
void LLAppViewerMacOSX::forceErrorOSSpecificException()
{
force_ns_sxeption();
}
// MacOSX may add and addition command line arguement for the process serial number.
// The option takes a form like '-psn_0_12345'. The following method should be able to recognize
// and either ignore or return a pair of values for the option.

View File

@ -42,6 +42,8 @@ public:
//
virtual bool init(); // Override to do application initialization
virtual void forceErrorOSSpecificException();
protected:
virtual bool restoreErrorTrap();

View File

@ -99,7 +99,6 @@ LLVOAvatar *LLControlAvatar::getAttachedAvatar()
void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_scale_fixup) const
{
F32 max_legal_offset = MAX_LEGAL_OFFSET;
if (gSavedSettings.getControl("AnimatedObjectsMaxLegalOffset"))
{
@ -362,6 +361,9 @@ LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj)
void LLControlAvatar::markForDeath()
{
mMarkedForDeath = true;
// object unlinked cav and might be dead already
// might need to clean mControlAVBridge here as well
mRootVolp = NULL;
}
void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time)
@ -379,6 +381,7 @@ void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time)
void LLControlAvatar::markDead()
{
mRootVolp = NULL;
super::markDead();
mControlAVBridge = NULL;
}
@ -439,7 +442,7 @@ void LLControlAvatar::updateDebugText()
F32 streaming_cost = 0.f;
std::string cam_dist_string = "";
S32 cam_dist_count = 0;
F32 lod_radius = mRootVolp->mLODRadius;
F32 lod_radius = mRootVolp ? mRootVolp->mLODRadius : 0.f;
for (std::vector<LLVOVolume*>::iterator it = volumes.begin();
it != volumes.end(); ++it)

View File

@ -90,6 +90,8 @@ LLConversationItem::~LLConversationItem()
{
mAvatarNameCacheConnection.disconnect();
}
clearChildren();
}
//virtual
@ -254,6 +256,11 @@ LLConversationItemSession::LLConversationItemSession(const LLUUID& uuid, LLFolde
mConvType = CONV_SESSION_UNKNOWN;
}
LLConversationItemSession::~LLConversationItemSession()
{
clearAndDeparentModels();
}
bool LLConversationItemSession::hasChildren() const
{
return getChildrenCount() > 0;

View File

@ -157,6 +157,7 @@ class LLConversationItemSession : public LLConversationItem
public:
LLConversationItemSession(std::string display_name, const LLUUID& uuid, LLFolderViewModelInterface& root_view_model);
LLConversationItemSession(const LLUUID& uuid, LLFolderViewModelInterface& root_view_model);
~LLConversationItemSession();
/*virtual*/ bool hasChildren() const;
LLPointer<LLUIImage> getIcon() const { return NULL; }

View File

@ -947,7 +947,7 @@ void LLFastTimerView::printLineStats()
{
std::string legend_stat;
bool first = true;
for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
it != LLTrace::end_block_timer_tree_df();
++it)
{
@ -969,7 +969,7 @@ void LLFastTimerView::printLineStats()
std::string timer_stat;
first = true;
for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
it != LLTrace::end_block_timer_tree_df();
++it)
{
@ -1046,7 +1046,7 @@ void LLFastTimerView::drawLineGraph()
F32Seconds cur_max(0);
U32 cur_max_calls = 0;
for(block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
for(LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
it != LLTrace::end_block_timer_tree_df();
++it)
{
@ -1195,8 +1195,8 @@ void LLFastTimerView::drawLegend()
S32 scroll_offset = 0; // element's y offset from top of the inner scroll's rect
ft_display_idx.clear();
std::map<BlockTimerStatHandle*, S32> display_line;
for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
it != block_timer_tree_df_iterator_t();
for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
it != LLTrace::end_block_timer_tree_df();
++it)
{
BlockTimerStatHandle* idp = (*it);
@ -1311,8 +1311,8 @@ void LLFastTimerView::generateUniqueColors()
F32 hue = 0.f;
for (block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
it != block_timer_tree_df_iterator_t();
for (LLTrace::block_timer_tree_df_iterator_t it = LLTrace::begin_block_timer_tree_df(FTM_FRAME);
it != LLTrace::end_block_timer_tree_df();
++it)
{
BlockTimerStatHandle* idp = (*it);

View File

@ -320,6 +320,7 @@ public:
if (item)
{
LLFavoritesBarCtrl::sWaitingForCallabck = 0.f;
LLFavoritesOrderStorage::instance().setSortIndex(item, mSortField);
item->setComplete(TRUE);
@ -365,6 +366,9 @@ struct LLFavoritesSort
}
};
F64 LLFavoritesBarCtrl::sWaitingForCallabck = 0.f;
LLFavoritesBarCtrl::Params::Params()
: image_drag_indication("image_drag_indication"),
more_button("more_button"),
@ -381,7 +385,7 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
mShowDragMarker(FALSE),
mLandingTab(NULL),
mLastTab(NULL),
mTabsHighlightEnabled(TRUE),
mItemsListDirty(false),
mUpdateDropDownItems(true),
mRestoreOverflowMenu(false),
mGetPrevItems(true),
@ -618,6 +622,9 @@ void LLFavoritesBarCtrl::handleNewFavoriteDragAndDrop(LLInventoryItem *item, con
int sortField = 0;
LLPointer<LLItemCopiedCallback> cb;
const F64 CALLBACK_WAIT_TIME = 30.f;
sWaitingForCallabck = LLTimer::getTotalSeconds() + CALLBACK_WAIT_TIME;
// current order is saved by setting incremental values (1, 2, 3, ...) for the sort field
for (LLInventoryModel::item_array_t::iterator i = mItems.begin(); i != mItems.end(); ++i)
{
@ -691,16 +698,22 @@ void LLFavoritesBarCtrl::changed(U32 mask)
LLFavoritesOrderStorage::instance().getSLURL((*i)->getAssetUUID());
}
updateButtons();
if (!mItemsChangedTimer.getStarted())
{
mItemsChangedTimer.start();
}
else
{
mItemsChangedTimer.reset();
}
if (sWaitingForCallabck < LLTimer::getTotalSeconds())
{
updateButtons();
if (!mItemsChangedTimer.getStarted())
{
mItemsChangedTimer.start();
}
else
{
mItemsChangedTimer.reset();
}
}
else
{
mItemsListDirty = true;
}
}
}
@ -754,6 +767,18 @@ void LLFavoritesBarCtrl::draw()
mItemsChangedTimer.start();
}
if (mItemsListDirty && sWaitingForCallabck < LLTimer::getTotalSeconds())
{
updateButtons();
if (!mItemsChangedTimer.getStarted())
{
mItemsChangedTimer.start();
}
else
{
mItemsChangedTimer.reset();
}
}
}
const LLButton::Params& LLFavoritesBarCtrl::getButtonParams()
@ -782,6 +807,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update)
return;
}
mItemsListDirty = false;
mItems.clear();
if (!collectFavoriteItems(mItems))

View File

@ -53,6 +53,7 @@ public:
protected:
LLFavoritesBarCtrl(const Params&);
friend class LLUICtrlFactory;
friend class LLItemCopiedCallback;
public:
virtual ~LLFavoritesBarCtrl();
@ -84,7 +85,6 @@ protected:
void onButtonRightClick(LLUUID id,LLView* button,S32 x,S32 y,MASK mask);
void onButtonMouseDown(LLUUID id, LLUICtrl* button, S32 x, S32 y, MASK mask);
void onOverflowMenuItemMouseDown(LLUUID id, LLUICtrl* item, S32 x, S32 y, MASK mask);
void onButtonMouseUp(LLUUID id, LLUICtrl* button, S32 x, S32 y, MASK mask);
void onEndDrag();
@ -164,7 +164,8 @@ private:
BOOL mStartDrag;
LLInventoryModel::item_array_t mItems;
BOOL mTabsHighlightEnabled;
static F64 sWaitingForCallabck;
bool mItemsListDirty;
S32 mMouseX;
S32 mMouseY;

View File

@ -1770,6 +1770,7 @@ void LLFloaterIMContainer::setTimeNow(const LLUUID& session_id, const LLUUID& pa
LLConversationItemSession* item = dynamic_cast<LLConversationItemSession*>(getSessionModel(session_id));
if (item)
{
item->setTimeNow(participant_id);
mConversationViewModel.requestSortAll();
mConversationsRoot->arrangeAll();
}

View File

@ -522,6 +522,8 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
// errors in separate window.
if (chat_msg.mChatType == CHAT_TYPE_DEBUG_MSG)
{
if (LLFloater::isQuitRequested()) return;
if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE)
return;

View File

@ -113,6 +113,7 @@
#include "llpresetsmanager.h"
#include "llviewercontrol.h"
#include "llpresetsmanager.h"
#include "llinventoryfunctions.h"
#include "llsearchableui.h"
#include "llperfstats.h"
@ -1628,25 +1629,6 @@ void LLFloaterPreference::onChangeMaturity()
getChild<LLIconCtrl>("rating_icon_adult")->setVisible(sim_access == SIM_ACCESS_ADULT);
}
std::string get_category_path(LLUUID cat_id)
{
LLViewerInventoryCategory* cat = gInventory.getCategory(cat_id);
std::string localized_cat_name;
if (!LLTrans::findString(localized_cat_name, "InvFolder " + cat->getName()))
{
localized_cat_name = cat->getName();
}
if (cat->getParentUUID().notNull())
{
return get_category_path(cat->getParentUUID()) + " > " + localized_cat_name;
}
else
{
return localized_cat_name;
}
}
std::string get_category_path(LLFolderType::EType cat_type)
{
LLUUID cat_id = gInventory.findUserDefinedCategoryUUIDForType(cat_type);

View File

@ -58,6 +58,8 @@ LLFloaterProfileTexture::~LLFloaterProfileTexture()
mImage->setBoostLevel(mImageOldBoostLevel);
mImage = NULL;
}
LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList);
}
// virtual

View File

@ -143,7 +143,7 @@ public:
const LLUUID& invoice,
const sparam_t& strings);
LLSD getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count );
static LLSD getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count );
};
@ -2751,11 +2751,12 @@ bool LLDispatchSetEstateAccess::operator()(
return true;
}
// static
LLSD LLDispatchSetEstateExperience::getIDs( sparam_t::const_iterator it, sparam_t::const_iterator end, S32 count )
{
LLSD idList = LLSD::emptyArray();
LLUUID id;
while(count--> 0)
while (count-- > 0 && it < end)
{
memcpy(id.mData, (*(it++)).data(), UUID_BYTES);
idList.append(id);
@ -2769,7 +2770,7 @@ LLSD LLDispatchSetEstateExperience::getIDs( sparam_t::const_iterator it, sparam_
// strings[2] = str(num blocked)
// strings[3] = str(num trusted)
// strings[4] = str(num allowed)
// strings[8] = bin(uuid) ...
// strings[5] = bin(uuid) ...
// ...
bool LLDispatchSetEstateExperience::operator()(
const LLDispatcher* dispatcher,
@ -2778,23 +2779,30 @@ bool LLDispatchSetEstateExperience::operator()(
const sparam_t& strings)
{
LLPanelRegionExperiences* panel = LLFloaterRegionInfo::getPanelExperiences();
if (!panel) return true;
if (!panel)
return true;
const sparam_t::size_type MIN_SIZE = 5;
if (strings.size() < MIN_SIZE)
return true;
// Skip 2 parameters
sparam_t::const_iterator it = strings.begin();
++it; // U32 estate_id = strtol((*it).c_str(), NULL, 10);
++it; // U32 send_to_agent_only = strtoul((*(++it)).c_str(), NULL, 10);
// Read 3 parameters
LLUUID id;
S32 num_blocked = strtol((*(it++)).c_str(), NULL, 10);
S32 num_trusted = strtol((*(it++)).c_str(), NULL, 10);
S32 num_allowed = strtol((*(it++)).c_str(), NULL, 10);
LLSD ids = LLSD::emptyMap()
.with("blocked", getIDs(it, strings.end(), num_blocked))
.with("trusted", getIDs(it + (num_blocked), strings.end(), num_trusted))
.with("allowed", getIDs(it + (num_blocked+num_trusted), strings.end(), num_allowed));
.with("blocked", getIDs(it, strings.end(), num_blocked))
.with("trusted", getIDs(it + num_blocked, strings.end(), num_trusted))
.with("allowed", getIDs(it + num_blocked + num_trusted, strings.end(), num_allowed));
panel->processResponse(ids);
panel->processResponse(ids);
return true;
}

View File

@ -67,14 +67,14 @@ void LLFloaterSidePanelContainer::closeFloater(bool app_quitting)
if (parent == this )
{
LLSidepanelAppearance* panel_appearance = dynamic_cast<LLSidepanelAppearance*>(getPanel("appearance"));
if ( panel_appearance )
if (panel_appearance)
{
LLPanelEditWearable *edit_wearable_ptr = panel_appearance->getWearable();
if (edit_wearable_ptr)
{
edit_wearable_ptr->onClose();
}
if(!app_quitting)
if (!app_quitting)
{
panel_appearance->showOutfitsInventoryPanel();
}
@ -116,11 +116,16 @@ LLFloater* LLFloaterSidePanelContainer::getTopmostInventoryFloater()
LLPanel* LLFloaterSidePanelContainer::openChildPanel(const std::string& panel_name, const LLSD& params)
{
LLView* view = findChildView(panel_name, true);
if (!view) return NULL;
if (!view)
return NULL;
if (!getVisible())
{
openFloater();
openFloater();
}
else if (!hasFocus())
{
setFocus(TRUE);
}
LLPanel* panel = NULL;

View File

@ -897,6 +897,15 @@ void LLHUDNameTag::shift(const LLVector3& offset)
mPositionAgent += offset;
}
F32 LLHUDNameTag::getWorldHeight() const
{
const LLViewerCamera* camera = LLViewerCamera::getInstance();
F32 height_meters = mLastDistance * (F32)tan(camera->getView() / 2.f);
F32 height_pixels = camera->getViewHeightInPixels() / 2.f;
F32 meters_per_pixel = height_meters / height_pixels;
return mHeight * meters_per_pixel * gViewerWindow->getDisplayScale().mV[VY];
}
//static
void LLHUDNameTag::addPickable(std::set<LLViewerObject*> &pick_list)
{

View File

@ -127,11 +127,12 @@ public:
/*virtual*/ void markDead();
friend class LLHUDObject;
/*virtual*/ F32 getDistance() const { return mLastDistance; }
S32 getLOD() { return mLOD; }
BOOL getVisible() { return mVisible; }
S32 getLOD() const { return mLOD; }
BOOL getVisible() const { return mVisible; }
BOOL getHidden() const { return mHidden; }
void setHidden( BOOL hide ) { mHidden = hide; }
void shift(const LLVector3& offset);
F32 getWorldHeight() const;
BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a& intersection, BOOL debug_render = FALSE);

View File

@ -1778,7 +1778,7 @@ void LLItemBridge::performAction(LLInventoryModel* model, std::string action)
}
else if ("show_in_main_panel" == action)
{
LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, mUUID, TRUE);
LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true);
return;
}
else if ("cut" == action)
@ -3409,7 +3409,7 @@ void LLFolderBridge::performAction(LLInventoryModel* model, std::string action)
}
else if ("show_in_main_panel" == action)
{
LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, mUUID, TRUE);
LLInventoryPanel::openInventoryPanelAndSetSelection(true, mUUID, true);
return;
}
else if ("cut" == action)

View File

@ -2151,6 +2151,24 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st
gInventory.createNewCategory(first_item->getParentUUID(), LLFolderType::FT_NONE, folder_name, func);
}
std::string get_category_path(LLUUID cat_id)
{
LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
std::string localized_cat_name;
if (!LLTrans::findString(localized_cat_name, "InvFolder " + cat->getName()))
{
localized_cat_name = cat->getName();
}
if (cat->getParentUUID().notNull())
{
return get_category_path(cat->getParentUUID()) + " > " + localized_cat_name;
}
else
{
return localized_cat_name;
}
}
// Returns true if the item can be moved to Current Outfit or any outfit folder.
bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit)
{

View File

@ -106,6 +106,7 @@ void move_items_to_new_subfolder(const uuid_vec_t& selected_uuids, const std::st
void move_items_to_folder(const LLUUID& new_cat_uuid, const uuid_vec_t& selected_uuids);
bool is_only_cats_selected(const uuid_vec_t& selected_uuids);
bool is_only_items_selected(const uuid_vec_t& selected_uuids);
std::string get_category_path(LLUUID cat_id);
bool can_move_to_outfit(LLInventoryItem* inv_item, BOOL move_is_into_current_outfit);
bool can_move_to_landmarks(LLInventoryItem* inv_item);

View File

@ -240,7 +240,7 @@ void LLInventoryItemsList::refresh()
case REFRESH_LIST_SORT:
{
// Filter, sort, rearrange and notify parent about shape changes
filterItems();
filterItems(true, true);
if (mAddedItems.size() == 0)
{

View File

@ -51,20 +51,20 @@ public:
/**
* Let list know items need to be refreshed in next doIdle()
*/
void setNeedsRefresh(bool needs_refresh){ mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; }
void setNeedsRefresh(bool needs_refresh) { mRefreshState = needs_refresh ? REFRESH_ALL : REFRESH_COMPLETE; }
U32 getNeedsRefresh(){ return mRefreshState; }
U32 getNeedsRefresh() { return mRefreshState; }
/**
* Sets the flag indicating that the list needs to be refreshed even if it is
* not currently visible.
*/
void setForceRefresh(bool force_refresh){ mForceRefresh = force_refresh; }
void setForceRefresh(bool force_refresh) { mForceRefresh = force_refresh; }
/**
* If refreshes when invisible.
*/
bool getForceRefresh(){ return mForceRefresh; }
bool getForceRefresh() { return mForceRefresh; }
virtual bool selectItemByValue(const LLSD& value, bool select = true);

View File

@ -566,8 +566,12 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask)
for (uuid_set_t::iterator it = added.begin(); it != added.end(); ++it)
{
LLInventoryItem *item = gInventory.getItem(*it);
if (!item)
{
continue;
}
const LLUUID& asset_uuid = item->getAssetUUID();
if (item && item->getUUID().notNull() && asset_uuid.notNull())
if (item->getUUID().notNull() && asset_uuid.notNull())
{
if (isAssetWatched(asset_uuid))
{

View File

@ -1887,46 +1887,52 @@ LLInventoryPanel* LLInventoryPanel::getActiveInventoryPanel(BOOL auto_open)
}
//static
void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const LLUUID& obj_id, BOOL use_main_panel, BOOL take_keyboard_focus, BOOL reset_filter)
void LLInventoryPanel::openInventoryPanelAndSetSelection(bool auto_open, const LLUUID& obj_id,
bool use_main_panel, bool take_keyboard_focus, bool reset_filter)
{
LLSidepanelInventory* sidepanel_inventory = LLFloaterSidePanelContainer::getPanel<LLSidepanelInventory>("inventory");
sidepanel_inventory->showInventoryPanel();
bool in_inbox = (gInventory.isObjectDescendentOf(obj_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX)));
if (!in_inbox && (use_main_panel || !sidepanel_inventory->getMainInventoryPanel()->isRecentItemsPanelSelected()))
LLUUID cat_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_INBOX);
bool in_inbox = gInventory.isObjectDescendentOf(obj_id, cat_id);
if (!in_inbox && use_main_panel)
{
sidepanel_inventory->selectAllItemsPanel();
}
LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater();
if(!auto_open && inventory_floater && inventory_floater->getVisible())
if (!auto_open)
{
LLSidepanelInventory *inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel();
if(main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode())
LLFloater* inventory_floater = LLFloaterSidePanelContainer::getTopmostInventoryFloater();
if (inventory_floater && inventory_floater->getVisible())
{
LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL;
main_panel->setGallerySelection(obj_id);
return;
LLSidepanelInventory *inventory_panel = inventory_floater->findChild<LLSidepanelInventory>("main_panel");
LLPanelMainInventory* main_panel = inventory_panel->getMainInventoryPanel();
if (main_panel->isSingleFolderMode() && main_panel->isGalleryViewMode())
{
LL_DEBUGS("Inventory") << "Opening gallery panel for item" << obj_id << LL_ENDL;
main_panel->setGallerySelection(obj_id);
return;
}
}
}
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory && main_inventory->isSingleFolderMode()
&& use_main_panel)
if (use_main_panel)
{
const LLInventoryObject *obj = gInventory.getObject(obj_id);
if (obj)
LLPanelMainInventory* main_inventory = sidepanel_inventory->getMainInventoryPanel();
if (main_inventory && main_inventory->isSingleFolderMode())
{
LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL;
main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false);
main_inventory->setGallerySelection(obj_id);
return;
const LLInventoryObject *obj = gInventory.getObject(obj_id);
if (obj)
{
LL_DEBUGS("Inventory") << "Opening main inventory panel for item" << obj_id << LL_ENDL;
main_inventory->setSingleFolderViewRoot(obj->getParentUUID(), false);
main_inventory->setGallerySelection(obj_id);
return;
}
}
}
LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
if (active_panel)
{
LL_DEBUGS("Messaging", "Inventory") << "Highlighting" << obj_id << LL_ENDL;
@ -1938,11 +1944,8 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
if (in_inbox)
{
LLInventoryPanel * inventory_panel = NULL;
sidepanel_inventory->openInbox();
inventory_panel = sidepanel_inventory->getInboxPanel();
LLInventoryPanel* inventory_panel = sidepanel_inventory->getInboxPanel();
if (inventory_panel)
{
inventory_panel->setSelection(obj_id, take_keyboard_focus);
@ -1967,7 +1970,6 @@ void LLInventoryPanel::openInventoryPanelAndSetSelection(BOOL auto_open, const L
void LLInventoryPanel::setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id)
{
LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory");
for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter)
{

View File

@ -244,12 +244,12 @@ public:
// "Auto_open" determines if we open an inventory panel if none are open.
static LLInventoryPanel *getActiveInventoryPanel(BOOL auto_open = TRUE);
static void openInventoryPanelAndSetSelection(BOOL auto_open,
static void openInventoryPanelAndSetSelection(bool auto_open,
const LLUUID& obj_id,
BOOL use_main_panel = FALSE,
BOOL take_keyboard_focus = TAKE_FOCUS_YES,
BOOL reset_filter = FALSE);
static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id);
bool use_main_panel = false,
bool take_keyboard_focus = true,
bool reset_filter = false);
static void setSFViewAndOpenFolder(const LLInventoryPanel* panel, const LLUUID& folder_id);
void addItemID(const LLUUID& id, LLFolderViewItem* itemp);
void removeItemID(const LLUUID& id);
LLFolderViewItem* getItemByID(const LLUUID& id);

View File

@ -1081,6 +1081,13 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename)
LLImageDimensionsInfo image_info;
if (!image_info.load(filename,codec))
{
LLSD args;
args["NAME"] = gDirUtilp->getBaseFileName(filename);
if (!image_info.getWarningName().empty())
{
args["REASON"] = LLTrans::getString(image_info.getWarningName());
}
LLNotificationsUtil::add("CannotUploadTexture", args);
return false;
}
@ -1096,6 +1103,7 @@ bool LLLocalBitmapMgr::checkTextureDimensions(std::string filename)
LLSD notif_args;
notif_args["REASON"] = mImageLoadError;
notif_args["NAME"] = gDirUtilp->getBaseFileName(filename);
LLNotificationsUtil::add("CannotUploadTexture", notif_args);
return false;

View File

@ -5503,7 +5503,7 @@ void on_new_single_inventory_upload_complete(
}
else
{
LLInventoryPanel::openInventoryPanelAndSetSelection(TRUE, server_response["new_inventory_item"].asUUID(), TRUE, TAKE_FOCUS_NO, TRUE);
LLInventoryPanel::openInventoryPanelAndSetSelection(true, server_response["new_inventory_item"].asUUID(), true, false, true);
}
// restore keyboard focus

View File

@ -249,7 +249,7 @@ void LLModelPreview::updateDimentionsAndOffsets()
{
accounted.insert(instance.mModel);
//update instance skin info for each lods pelvisZoffset
// update instance skin info for each lods pelvisZoffset
for (int j = 0; j<LLModel::NUM_LODS; ++j)
{
if (instance.mLOD[j])
@ -271,6 +271,7 @@ void LLModelPreview::rebuildUploadData()
{
assert_main_thread();
mDefaultPhysicsShapeP = NULL;
mUploadData.clear();
mTextureSet.clear();
@ -310,7 +311,7 @@ void LLModelPreview::rebuildUploadData()
mat *= scale_mat;
for (LLModelLoader::model_instance_list::iterator model_iter = iter->second.begin(); model_iter != iter->second.end();)
{ //for each instance with said transform applied
{ // for each instance with said transform applied
LLModelInstance instance = *model_iter++;
LLModel* base_model = instance.mModel;
@ -573,7 +574,7 @@ void LLModelPreview::rebuildUploadData()
else if (getLoadState() == LLModelLoader::ERROR_MATERIALS
|| getLoadState() == LLModelLoader::WARNING_BIND_SHAPE_ORIENTATION)
{
// This is only valid for these two error types because they are
// This is only valid for these two error types because they are
// only used inside rebuildUploadData() and updateStatusMessages()
// updateStatusMessages() is called after rebuildUploadData()
setLoadState(LLModelLoader::DONE);
@ -798,7 +799,7 @@ void LLModelPreview::loadModel(std::string filename, S32 lod, bool force_disable
// it tends to force the UI into strange checkbox options
// which cannot be altered.
//only try to load from slm if viewer is configured to do so and this is the
//only try to load from slm if viewer is configured to do so and this is the
//initial model load (not an LoD or physics shape)
mModelLoader->mTrySLM = gSavedSettings.getBOOL("MeshImportUseSLM") && mUploadData.empty();
}
@ -884,12 +885,13 @@ void LLModelPreview::clearIncompatible(S32 lod)
// Check if already started
bool subscribe_for_generation = mLodsQuery.empty();
// Remove previously scheduled work
mLodsQuery.clear();
LLFloaterModelPreview* fmp = LLFloaterModelPreview::sInstance;
if (!fmp) return;
if (!fmp)
return;
// Schedule new work
for (S32 i = LLModel::LOD_HIGH; i >= 0; --i)
@ -1719,7 +1721,7 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
ll_aligned_free_16(output_indices);
ll_aligned_free_16(shadow_indices);
if (size_new_indices < 3)
{
// At least one triangle is needed
@ -1912,7 +1914,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
{
precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, MESH_OPTIMIZER_NO_UVS);
}
if (precise_ratio < 0 || (precise_ratio * allowed_ratio_drift < indices_decimator))
{
// Try sloppy variant if normal one failed to simplify model enough.

Some files were not shown because too many files have changed in this diff Show More