Ansariel 2024-04-10 01:49:35 +02:00
commit 096aef2a72
783 changed files with 3971 additions and 3751 deletions

11
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2
updates:
- package-ecosystem: "github-actions" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "monthly"

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
@ -224,7 +224,7 @@ jobs:
- name: Upload executable
if: matrix.configuration != 'ReleaseOS' && steps.build.outputs.viewer_app
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "${{ steps.build.outputs.artifact }}-app"
path: |
@ -234,7 +234,7 @@ jobs:
# artifact for that too.
- name: Upload symbol file
if: matrix.configuration != 'ReleaseOS'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "${{ steps.build.outputs.artifact }}-symbols"
path: |
@ -242,7 +242,7 @@ jobs:
- name: Upload metadata
if: matrix.configuration != 'ReleaseOS'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "${{ steps.build.outputs.artifact }}-metadata"
# emitted by build.sh, possibly multiple lines
@ -250,7 +250,7 @@ jobs:
${{ steps.build.outputs.metadata }}
- name: Upload physics package
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
# should only be set for viewer-private
if: matrix.configuration != 'ReleaseOS' && steps.build.outputs.physicstpv
with:

View File

@ -9,7 +9,7 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v4
- uses: actions/labeler@v5
with:
configuration-path: .github/labeler.yaml
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
- uses: actions/setup-python@v5
with:
python-version: 3.x
- uses: pre-commit/action@v3.0.0
- uses: pre-commit/action@v3.0.1

View File

@ -12,7 +12,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v6
- uses: actions/stale@v9
id: stale
with:
stale-pr-message: This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or it will be closed in 7 days

View File

@ -142,9 +142,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>81fe1e927e4fe3c5e5f15ce6219ca883</string>
<string>691fef2ddd57d7b6c26e87fc82d9ace3f54e078c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://3p.firestormviewer.org/fltk-1.3.5.202282121-linux64-202282121.tar.bz2</string>
<string>https://github.com/secondlife/3p-fltk/releases/download/v1.3.9-r1/fltk-1.3.9.8556992788-linux64-8556992788.tar.zst</string>
</map>
<key>name</key>
<string>linux</string>
@ -1177,34 +1179,6 @@
<key>description</key>
<string>a library for writing and using C++ mock classes</string>
</map>
<key>gstreamer</key>
<map>
<key>platforms</key>
<map>
<key>linux64</key>
<map>
<key>archive</key>
<map>
<key>hash</key>
<string>86a358f1b5a2c2baf68444b2bfc5bb32</string>
<key>url</key>
<string>https://3p.firestormviewer.org/gstreamer-0.10.6.180841551-linux64-180841551.tar.bz2</string>
</map>
<key>name</key>
<string>linux64</string>
</map>
</map>
<key>license</key>
<string>LGPL</string>
<key>license_file</key>
<string>LICENSES/gstreamer.txt</string>
<key>copyright</key>
<string>Copyright (C) 2007 Free Software Foundation, Inc. &lt;http://fsf.org/&gt;</string>
<key>version</key>
<string>0.10.6.314267</string>
<key>name</key>
<string>gstreamer</string>
</map>
<key>havok-source</key>
<map>
<key>platforms</key>
@ -1302,11 +1276,11 @@
<key>archive</key>
<map>
<key>hash</key>
<string>f5e5be3af96f1eb0842219a94765c04aa9c561c5</string>
<string>bdd74e2a02c7b78fded9222140d197da4af9904e</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://3p.firestormviewer.org/icu4c-4.8.1-linux64-240621048.tar.zst</string>
<string>https://github.com/secondlife/3p-icu4c/releases/download/v4.8.1-8bff176/icu4c-4.8.1-linux64-8512575562.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@ -1856,11 +1830,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>
@ -1874,7 +1848,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

@ -297,6 +297,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()
@ -793,13 +792,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

@ -197,12 +197,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;
@ -415,11 +415,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

@ -1533,9 +1533,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

@ -929,7 +929,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

@ -342,13 +342,7 @@ bool LLThreadSafeQueue<ElementT, QueueT>::pushIfOpen(T&& element)
return true;
// Storage Full. Wait for signal.
// <FS:Beq> [FIRE-32453][BUG-232971] Improve shutdown behaviour. Time bound the sleep
// mCapacityCond.wait(lock1);
// When the queue is full and the consuming thread has exited we would never wake up.
// For safety, we now wait max half a second then recheck close.
const auto timeout = std::chrono::milliseconds(500);
mCapacityCond.wait_for(lock1, timeout);
// </FS:Beq>
mCapacityCond.wait(lock1);
}
}

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

@ -211,61 +211,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>
@ -352,33 +297,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()
@ -80,6 +83,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(
@ -110,8 +121,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,10 +55,7 @@ namespace LL
* ThreadPool listens for application shutdown messages on the "LLApp"
* LLEventPump. Call close() to shut down this ThreadPool early.
*/
// <FS:Beq> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
// void close();
virtual void close();
// </FS:Beq>
std::string getName() const { return mName; }
size_t getWidth() const { return mThreads.size(); }
@ -90,14 +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);
protected: // <FS:Beq/> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
std::string mName;
size_t mThreadCount;
std::vector<std::pair<std::string, std::thread>> mThreads;
};
/**
@ -121,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;
}
@ -184,6 +187,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";
fclose(fp); // <FS:ND/> Don't leak the file handle
return false;
}

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)
{
}
@ -211,7 +216,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

@ -5630,9 +5630,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);
@ -5651,6 +5651,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);
@ -5684,6 +5691,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

@ -1056,7 +1056,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 )
{
@ -1083,11 +1088,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;
}
// <FS:ND> FIRE-9251; There is no way iter can be valid here, otherwise we had hit the if branch and not the else branch.
// F32 min_dist = (iter->first - pos).magVec();

View File

@ -101,6 +101,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[] =
{
@ -155,8 +166,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

@ -296,7 +296,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

@ -86,7 +86,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

@ -1373,26 +1373,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
{
@ -1400,34 +1402,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

@ -308,6 +308,7 @@ public:
virtual S32 notify(const LLSD& info) ;
virtual ~LLFlatListView();
protected:
/** Pairs LLpanel representing a single item LLPanel and LLSD associated with it */
@ -383,7 +384,9 @@ protected:
LLRect getLastSelectedItemRect();
void ensureSelectedVisible();
void ensureSelectedVisible();
const pairs_list_t& getItemPairs() { return mItemPairs; }
private:
@ -496,14 +499,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
@ -527,7 +530,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

@ -541,7 +541,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);
@ -2631,8 +2630,7 @@ LLFloaterView::LLFloaterView (const Params& p)
mSnapOffsetBottom(0),
mSnapOffsetChatBar(0),
mSnapOffsetLeft(0),
mSnapOffsetRight(0),
mFrontChild(NULL)
mSnapOffsetRight(0)
{
mSnapView = getHandle();
}
@ -2788,7 +2786,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))
{
@ -2797,12 +2796,12 @@ void LLFloaterView::bringToFront(LLFloater* child, BOOL give_focus, BOOL restore
return;
}
if (mFrontChild && !mFrontChild->isDead())
if (front_child && !front_child->isDead() && 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
@ -3389,7 +3388,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
@ -3427,11 +3427,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())
{
@ -3451,7 +3452,7 @@ void LLFloaterView::syncFloaterTabOrder()
{
sendChildToFront(childp);
}
mFrontChild = listTop.back();
mFrontChildHandle = listTop.back()->getHandle();
}
}
@ -3547,14 +3548,6 @@ void LLFloaterView::setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LL
}
}
void LLFloaterView::onDestroyFloater(LLFloater* floater)
{
if (mFrontChild == floater)
{
mFrontChild = nullptr;
}
}
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
void LLFloaterView::setMainChatbarRect(LLLayoutPanel* panel, const LLRect& chatbar_rect)
{

View File

@ -645,7 +645,6 @@ public:
// </FS:KC> Fix for bad edge snapping
void setToolbarRect(LLToolBarEnums::EToolBarLocation tb, const LLRect& toolbar_rect);
void onDestroyFloater(LLFloater* floater);
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
void setMainChatbarRect(LLLayoutPanel* panel, const LLRect& chatbar_rect);
@ -670,7 +669,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;
// <FS:Ansariel> Prevent floaters being dragged under main chat bar
LLRect mMainChatbarRect;

View File

@ -206,14 +206,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

@ -502,7 +502,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();
@ -515,10 +515,10 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
S32 text_len = wtext.size() + 1;
// <FS:Ansariel> Script editor ignoring font selection
//seg_list->push_back( new LLNormalTextSegment( defaultColor, 0, text_len, editor ) );
LLStyleSP style = getDefaultStyle(editor);
style->setColor(defaultColor);
seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) );
//seg_list->push_back( new LLNormalTextSegment( style, 0, text_len, editor ) );
LLStyleSP actual_style = getDefaultStyle(editor);
actual_style->setColor(style->getColor());
seg_list->push_back( new LLNormalTextSegment( actual_style, 0, text_len, editor ) );
// </FS:Ansariel>
const llwchar* base = wtext.c_str();
@ -530,11 +530,11 @@ void LLKeywords::findSegments(std::vector<LLTextSegmentPtr>* seg_list, const LLW
if( *cur == '\n' )
{
// <FS:Ansariel> Script editor ignoring font selection
//LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(cur-base);
//LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, cur-base);
LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(getDefaultStyle(editor), cur-base);
// </FS:Ansariel>
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' )
{
@ -572,7 +572,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;
}
@ -679,7 +679,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);
/*
// <FS:Ansariel> Script editor ignoring font selection
//LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_delimiter->getColor(), seg_start, seg_end, editor );
@ -723,7 +723,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;
@ -738,9 +738,12 @@ 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);
// <FS:Ansariel> Script editor ignoring font selection
//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)
{
@ -753,28 +756,28 @@ void LLKeywords::insertSegments(const LLWString& wtext, std::vector<LLTextSegmen
LLTextSegmentPtr text_segment = new LLNormalTextSegment( style, seg_start, pos, editor );
// </FS:Ansariel>
text_segment->setToken( cur_token );
insertSegment( seg_list, text_segment, text_len, defaultColor, editor);
insertSegment( seg_list, text_segment, text_len, style, editor);
}
// <FS:Ansariel> Script editor ignoring font selection
//LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(pos);
//LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(style, pos);
LLTextSegmentPtr text_segment = new LLLineBreakTextSegment(getDefaultStyle(editor), pos);
// </FS:Ansariel>
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);
}
// <FS:Ansariel> Script editor ignoring font selection
//LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, seg_end, editor );
LLStyleSP style = getDefaultStyle(editor);
style->setColor(cur_token->getColor());
LLTextSegmentPtr text_segment = new LLNormalTextSegment( style, seg_start, seg_end, editor );
//LLTextSegmentPtr text_segment = new LLNormalTextSegment(cur_token_style, seg_start, seg_end, editor);
LLStyleSP actual_style = getDefaultStyle(editor);
actual_style->setColor(cur_token->getColor());
LLTextSegmentPtr text_segment = new LLNormalTextSegment(actual_style, seg_start, seg_end, editor);
// </FS:Ansariel>
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 )
@ -803,6 +806,32 @@ 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 )
{
// <FS:Ansariel> Script editor ignoring font selection
//seg_list.push_back( new LLNormalTextSegment( style, new_seg_end, text_len, editor ) );
LLStyleSP actual_style = getDefaultStyle(editor);
actual_style->setColor(style->getColor());
seg_list.push_back(new LLNormalTextSegment(actual_style, new_seg_end, text_len, editor));
// </FS:Ansariel>
}
}
// <FS:Ansariel> Re-add support for Cinder's legacy file format
bool LLKeywords::loadFromLegacyFile(const std::string& filename)
{

View File

@ -29,6 +29,7 @@
#include "lldir.h"
#include "llstyle.h"
#include "llstring.h"
#include "v3color.h"
#include "v4color.h"
@ -121,8 +122,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();
@ -187,9 +188,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

@ -1811,7 +1811,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("_");
@ -3682,6 +3683,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

@ -563,6 +563,8 @@ public:
// add a context menu branch
BOOL appendContextSubMenu(LLMenuGL *menu);
const LLFontGL *getFont() const { return mFont; }
// <FS:Ansariel> Items-accessor
typedef std::list< LLMenuItemGL* > item_list_t;
item_list_t* getItems() { return &mItems; }
@ -599,6 +601,9 @@ protected:
BOOL mKeepFixedSize;
BOOL mNeedsArrange;
// Font for top menu items only
const LLFontGL* mFont;
private:

View File

@ -184,7 +184,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),
@ -279,9 +279,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;
}
@ -430,18 +427,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;
}
@ -560,11 +545,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;
}
@ -661,14 +641,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

@ -100,17 +100,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

@ -1657,25 +1657,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

@ -3829,7 +3829,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

@ -2048,7 +2048,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)
@ -625,5 +629,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

@ -237,14 +237,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

@ -293,16 +293,18 @@ 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();
// }
//}
if (match_entry != mUrlEntryNoLink && match_entry == mUrlEntryTrustedUrl)
{
LLUriParser up(url);
if (!up.normalize())
{
url = up.normalizedUri();
}
if (up.normalize() == 0)
{
url = up.normalizedUri();
}
}
// </FS:Ansariel>

View File

@ -37,7 +37,6 @@
#include "llwindowcallbacks.h"
// Linden library includes
#include "llapp.h" // <FS:Beq/> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
#include "llerror.h"
#include "llexception.h"
#include "llfasttimer.h"
@ -94,7 +93,6 @@ const UINT WM_DUMMY_(WM_USER + 0x0017);
const UINT WM_POST_FUNCTION_(WM_USER + 0x0018);
extern BOOL gDebugWindowProc;
extern BOOL gDisconnected; // <FS:Beq/> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
static std::thread::id sWindowThreadId;
static std::thread::id sMainThreadId;
@ -353,7 +351,10 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
LLWindowWin32Thread();
void run() override;
void close() override; // <FS:Beq/> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
void close() override;
// closes queue, wakes thread, waits until thread closes
void wakeAndDestroy();
void glReady()
{
@ -366,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();
@ -415,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
@ -992,53 +996,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))
{
// <FS:Beq> Can't use a message box here because we're about to stop servicing the events.
// OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
// mCallbacks->translateString("MBShutdownErr"),
// OSMB_OK);
LL_INFOS("Window") << "Destroying Window failed" << LL_ENDL;
// </FS:Beq>
}
}
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;
// <FS:Beq> [FIRE-32453][BUG-232971] close the related queues first to prevent spinning.
mFunctionQueue.close();
mMouseQueue.close();
// </FS:Beq>
mWindowThread->close();
mWindowThread->wakeAndDestroy();
}
BOOL LLWindowWin32::isValid()
@ -1791,8 +1752,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)
{
@ -1826,20 +1787,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
@ -3723,6 +3684,7 @@ void LLWindowWin32::swapBuffers()
}
}
//
// LLSplashScreenImp
//
@ -3745,6 +3707,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, APP_NAME.c_str());
}
@ -4708,11 +4673,25 @@ void LLWindowWin32::getWindowChrome( U32 &aChromeW, U32 &aChromeH )
#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
@ -4864,7 +4843,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);
@ -4874,7 +4853,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))
{
@ -4887,6 +4866,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;
@ -4960,45 +4961,10 @@ void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
}
}
// <FS:Beq> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
// Provide a close() override that ignores the initial close triggered by the threadpool detecting "quit"
// but waits for the viewer to be disconected and the second close call triggered by the app window destructor
void LLWindowWin32::LLWindowWin32Thread::close()
{
assert_main_thread();
if (!mQueue->isClosed() && gDisconnected)
{
LL_DEBUGS("ThreadPool") << mName << " closing queue and joining threads" << LL_ENDL;
mQueue->close();
for (auto& pair: mThreads)
{
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
// As we cannot seem to rely on the clean and timely exit of the windows thread in ALL situations we apply a timeout.
std::future<void> f = std::async(std::launch::async, [&] { pair.second.join(); });
if (f.wait_until(std::chrono::steady_clock::now() + std::chrono::seconds(5)) == std::future_status::ready) {
LL_DEBUGS("ThreadPool") << mName << " joined normally." << LL_ENDL;
} else {
LL_WARNS("ThreadPool") << mName << " join timed out." << LL_ENDL;
// the specified time point was reached before the thread finished execution and could be joined
}
}
LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL;
}
else
{
LL_DEBUGS("ThreadPool") << mName << " shutdown request ignored - not yet disconneced." << LL_ENDL;
}
}
// </FS:Beq>
void LLWindowWin32::LLWindowWin32Thread::run()
{
sWindowThreadId = std::this_thread::get_id();
LogChange logger("Window");
// <FS:Beq> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
try
{
// </FS:Beq>
//as good a place as any to up the MM timer resolution (see ms_sleep)
//attempt to set timer resolution to 1ms
TIMECAPS tc;
@ -5014,7 +4980,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
@ -5022,16 +4988,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)
@ -5040,21 +5006,7 @@ void LLWindowWin32::LLWindowWin32Thread::run()
", ", msg.wParam, ")");
TranslateMessage(&msg);
DispatchMessage(&msg);
// <FS:Beq> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
// mMessageQueue.pushFront(msg);
try
{
// <FS:Beq> Nobody is reading this queue once we are quitting. Writing to it causes a hang.
if(!LLApp::isQuitting())
mMessageQueue.pushFront(msg);
}
catch (const LLThreadSafeQueueInterrupt&)
{
// Shutdown timing is tricky. The main thread can end up trying
// to post a cursor position after having closed the WorkQueue.
logger.always("Message procesing tried to push() to closed MessageQueue - caught");
}
// </FS:Beq>
mMessageQueue.pushFront(msg);
}
}
@ -5080,38 +5032,111 @@ void LLWindowWin32::LLWindowWin32Thread::run()
}
#endif
}
// <FS:Beq> [FIRE-32453][BUG-232971] Improve shutdown behaviour.
}
catch (const std::exception& e)
{
logger.always("Windows thread exiting - Exception: ", e.what());
}
catch (...)
{
logger.always("Windows thread exiting - Exception: Unknown");
}
logger.always("done - queue closed on windows thread.");
// </FS:Beq>
//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

@ -286,7 +286,11 @@ void VolumeCatcherImpl::setVolume(F32 volume)
void VolumeCatcherImpl::pump()
{
return;
// <FS:Beq> PR#17 makidoll: Fix Linux volume catcher
if (mGotSyms && mMainloop) {
llpa_mainloop_iterate(mMainloop, 0, NULL);
}
// </FS:Beq>
}
void VolumeCatcherImpl::connected_okay()

View File

@ -21,5 +21,6 @@ LL_PA_SYM(true, pa_sw_volume_from_linear, pa_volume_t, double v);
LL_PA_SYM(true, pa_mainloop_free, void, pa_mainloop* m);
LL_PA_SYM(true, pa_mainloop_get_api, pa_mainloop_api*, pa_mainloop* m);
LL_PA_SYM(true, pa_mainloop_new, pa_mainloop*, void);
LL_PA_SYM(true, pa_mainloop_iterate, int, pa_mainloop*, int, int*);
// optional symbols to grab

View File

@ -28,6 +28,8 @@
<string>${VIEWER_VERSION_MAJOR}.${VIEWER_VERSION_MINOR}.${VIEWER_VERSION_PATCH}.${VIEWER_VERSION_REVISION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSRequiresCarbon</key>
<true/>
<key>NSAppSleepDisabled</key>

View File

@ -1 +1 @@
7.1.5
7.1.6

View File

@ -5152,171 +5152,6 @@
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemTrace</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemUI</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemFonts</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemInventory</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemObjects</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemOctreeGroupData</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemOctreeData</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemObjectCache</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemDrawable</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemFaceData</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemDrawInfo</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemTextureData</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemImageData</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemGLImageData</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMemVertexBuffer</key>
<map>
<key>Comment</key>
<string>Mode of stat in Statistics floater</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>DebugStatModeMaterials</key>
<map>
<key>Comment</key>
@ -7732,6 +7567,17 @@
<key>Backup</key>
<integer>0</integer>
</map>
<key>LSLFontSizeName</key>
<map>
<key>Comment</key>
<string>UNUSED - 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>
@ -10342,21 +10188,10 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatAdvanced</key>
<map>
<key>Comment</key>
<string>Expand advanced performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatBasic</key>
<map>
<key>Comment</key>
<string>Expand basic performance stats display</string>
<string>Expand Basic performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -10364,10 +10199,10 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatNet</key>
<key>OpenDebugStatAdvanced</key>
<map>
<key>Comment</key>
<string>Expand network stats display</string>
<string>Expand Advanced performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -10378,18 +10213,7 @@ Change of this parameter will affect the layout of buttons in notification toast
<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>
@ -10408,10 +10232,32 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>OpenDebugStatSimPathfinding</key>
<key>OpenDebugStatNet</key>
<map>
<key>Comment</key>
<string>Expand Pathfinding performance stats display</string>
<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>
<string>Expand Physics Details performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -10419,10 +10265,10 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>OpenDebugStatPhysicsDetails</key>
<key>OpenDebugStatPathfinding</key>
<map>
<key>Comment</key>
<string>Expand Physics Details performance stats display</string>
<string>Expand Pathfinding performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
@ -10452,17 +10298,6 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>1</integer>
</map>
<key>OpenDebugStatMemory</key>
<map>
<key>Comment</key>
<string>Expand Memory performance stats display</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>OutBandwidth</key>
<map>
<key>Comment</key>
@ -21989,17 +21824,6 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>FSDisplaySavedOutfitsCap</key>
<map>
<key>Comment</key>
<string>Display only so many saved outfits in edit appearance. 0 to disable.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>FSAdvancedWorldmapRegionInfo</key>
<map>
<key>Comment</key>
@ -25198,17 +25022,6 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Value</key>
<integer>0</integer>
</map>
<key>VoiceMultiInstance</key>
<map>
<key>Comment</key>
<string>Enables using voice in multiple simultaneous viewer instances</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>FSSoundCacheLocation</key>
<map>
<key>Comment</key>

View File

@ -2023,7 +2023,7 @@
value_min="-1"
value_max="1">
<param_skeleton>
<bone
name="mEyeLeft"
scale="0 0 0"
@ -2033,9 +2033,8 @@
name="mEyeRight"
scale="0 0 0"
offset="-.005 0 0" />
<bone
<bone
name="mFaceEyeAltLeft"
scale="0 0 0"
offset="-.005 0 0" />
@ -2044,7 +2043,7 @@
name="mFaceEyeAltRight"
scale="0 0 0"
offset="-.005 0 0" />
<bone
name="mFaceEyeLidLowerRight"
scale="0 0.3 0.7"
@ -2055,7 +2054,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" />
@ -2064,17 +2063,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

@ -311,7 +311,7 @@ void FSFloaterWearableFavorites::handleRemove()
void FSFloaterWearableFavorites::onFilterEdit(const std::string& search_string)
{
mItemsList->setFilterSubString(search_string);
mItemsList->setFilterSubString(search_string, true);
mItemsList->setNoItemsCommentText(getString("empty_list"));
}

View File

@ -66,14 +66,14 @@ LLSLURL::LLSLURL(const std::string& slurl)
// by default we go to agni.
mType = INVALID;
LL_DEBUGS("AppInit", "SLURL") << "SLURL: " << slurl << LL_ENDL;
if(slurl == SIM_LOCATION_HOME)
{
mType = HOME_LOCATION;
}
else if(slurl.empty() || (slurl == SIM_LOCATION_LAST))
if (slurl.empty() || (slurl == SIM_LOCATION_LAST))
{
mType = LAST_LOCATION;
}
else if (slurl == SIM_LOCATION_HOME)
{
mType = HOME_LOCATION;
}
else
{
LLURI slurl_uri;
@ -154,6 +154,15 @@ LLSLURL::LLSLURL(const std::string& slurl)
if(slurl_uri.scheme() == LLSLURL::SLURL_SECONDLIFE_SCHEME)
{
LL_DEBUGS("SLURL") << "secondlife scheme" << LL_ENDL;
if (path_array.size() == 0
&& slurl_uri.authority().empty()
&& slurl_uri.escapedQuery().empty())
{
mType = EMPTY;
// um, we need a path...
return;
}
// parse a maingrid style slurl. We know the grid is maingrid
// so grab it.
// A location slurl for maingrid (with the special schemes) can be in the form
@ -676,28 +685,24 @@ std::string LLSLURL::asString() const
// <AW: opensim>
std::string LLSLURL::getTypeHumanReadable(SLURL_TYPE type)
{
std::string ret;
switch(type)
{
case INVALID:
ret = "INVALID";
break;
return "INVALID";
case LOCATION:
ret = "LOCATION";
break;
return "LOCATION";
case HOME_LOCATION:
ret = "HOME_LOCATION";
break;
return "HOME_LOCATION";
case LAST_LOCATION:
ret = "LAST_LOCATION";
break;
return "LAST_LOCATION";
case APP:
ret = "APP";
break;
return "APP";
case HELP:
ret = "HELP";
return "HELP";
case EMPTY:
return "EMPTY";
default:
return{};
}
return ret;
}
// </AW: opensim>

View File

@ -60,7 +60,8 @@ public:
HOME_LOCATION,
LAST_LOCATION,
APP,
HELP
HELP,
EMPTY
};
LLSLURL(): mType(INVALID) { }

View File

@ -18,22 +18,23 @@ if [[ -f "$CONFIG_FILE" ]]; then
res=$(xcrun notarytool submit "$zip_file" \
--apple-id $USERNAME \
--password $PASSWORD \
--verbose \
--team-id $ASC_PROVIDER \
--wait 2>&1)
echo "Notarytool submit:"
echo $res
[[ "$res" =~ 'id: '([^[:space:]]+) ]]
match=$?
echo "Notarized with id: [$match]"
if [[ ! $match -eq 0 ]]; then
echo "Running Stapler"
xcrun stapler staple "$app_file"
exit 0
else
echo "Notarization error"
exit 1
fi
# if [[ ! $match -eq 0 ]]; then
echo "Running Stapler"
xcrun stapler staple "$app_file"
exit 0
# else
# echo "Notarization error"
# exit 1
# fi
else
echo "Notarization error: ditto failed"
exit 1

View File

@ -2214,6 +2214,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
@ -2530,6 +2533,8 @@ bool LLAppViewer::cleanup()
// deleteSingleton() methods.
LLSingletonBase::deleteAll();
LLSplashScreen::hide();
LL_INFOS() << "Goodbye!" << LL_ENDL;
removeDumpDir();
@ -3478,20 +3483,19 @@ bool LLAppViewer::initConfiguration()
return false;
}
if (mSecondInstance)
{
// This is the second instance of SL. Turn off voice support,
// but make sure the setting is *not* persisted.
LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice");
// <FS:Ansariel> Voice in multiple instances; by Latif Khalifa
//if(disable_voice)
if(disable_voice && !gSavedSettings.getBOOL("VoiceMultiInstance"))
// </FS:Ansariel>
{
const BOOL DO_NOT_PERSIST = FALSE;
disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST);
}
}
// <FS:Ansariel> Voice in multiple instances
//if (mSecondInstance)
//{
// // This is the second instance of SL. Mute voice,
// // but make sure the setting is *not* persisted.
// LLControlVariable* enable_voice = gSavedSettings.getControl("EnableVoiceChat");
// if(enable_voice)
// {
// const BOOL DO_NOT_PERSIST = FALSE;
// enable_voice->setValue(LLSD(FALSE), DO_NOT_PERSIST);
// }
//}
// </FS:Ansariel>
gLastRunVersion = gSavedSettings.getString("LastRunVersion");
@ -5932,6 +5936,9 @@ void LLAppViewer::idleShutdown()
&& gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME
&& !logoutRequestSent())
{
gViewerWindow->setShowProgress(TRUE, !gSavedSettings.getBOOL("FSDisableLogoutScreens"));
gViewerWindow->setProgressPercent(100.f);
gViewerWindow->setProgressString(LLTrans::getString("LoggingOut"));
return;
}
@ -6336,9 +6343,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;
}
@ -6349,6 +6365,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

@ -154,6 +154,7 @@ public:
virtual void forceErrorBadMemoryAccess();
virtual void forceErrorInfiniteLoop();
virtual void forceErrorSoftwareException();
virtual void forceErrorOSSpecificException();
virtual void forceErrorDriverCrash();
// <FS:Ansariel> Wrongly merged back in by LL
//virtual void forceErrorCoroutineCrash();

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

@ -101,7 +101,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"))
{
@ -364,6 +363,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;
mVolumep = nullptr;
}
@ -382,6 +384,7 @@ void LLControlAvatar::idleUpdate(LLAgent &agent, const F64 &time)
void LLControlAvatar::markDead()
{
mRootVolp = NULL;
super::markDead();
mControlAVBridge = NULL;
}
@ -442,7 +445,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

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

View File

@ -160,6 +160,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

@ -971,7 +971,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)
{
@ -993,7 +993,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)
{
@ -1070,7 +1070,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)
{
@ -1229,8 +1229,8 @@ void LLFastTimerView::drawLegend()
#pragma GCC diagnostic ignored "-Wnonnull"
#endif
// </FS:Zi>
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)
// <FS:Zi> GCC12 warning: nonnull - probably bogus
#if defined(__GNUC__) && (__GNUC__ >= 12)
@ -1355,8 +1355,8 @@ void LLFastTimerView::generateUniqueColors()
#pragma GCC diagnostic ignored "-Wnonnull"
#endif
// </FS:Zi>
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)
// <FS:Zi> GCC12 warning: nonnull - probably bogus
#if defined(__GNUC__) && (__GNUC__ >= 12)

View File

@ -446,6 +446,7 @@ public:
if (item)
{
LLFavoritesBarCtrl::sWaitingForCallabck = 0.f;
LLFavoritesOrderStorage::instance().setSortIndex(item, mSortField);
item->setComplete(TRUE);
@ -491,6 +492,9 @@ struct LLFavoritesSort
}
};
F64 LLFavoritesBarCtrl::sWaitingForCallabck = 0.f;
LLFavoritesBarCtrl::Params::Params()
: image_drag_indication("image_drag_indication"),
more_button("more_button"),
@ -510,7 +514,7 @@ LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p)
mShowDragMarker(FALSE),
mLandingTab(NULL),
mLastTab(NULL),
mTabsHighlightEnabled(TRUE),
mItemsListDirty(false),
mUpdateDropDownItems(true),
mRestoreOverflowMenu(false),
mGetPrevItems(true),
@ -765,6 +769,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)
{
@ -838,16 +845,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;
}
}
}
@ -901,6 +914,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()
@ -929,6 +954,7 @@ void LLFavoritesBarCtrl::updateButtons(bool force_update)
return;
}
mItemsListDirty = false;
mItems.clear();
if (!collectFavoriteItems(mItems))

View File

@ -56,6 +56,7 @@ public:
protected:
LLFavoritesBarCtrl(const Params&);
friend class LLUICtrlFactory;
friend class LLItemCopiedCallback;
public:
virtual ~LLFavoritesBarCtrl();
@ -87,7 +88,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();
@ -171,7 +171,8 @@ private:
BOOL mStartDrag;
LLInventoryModel::item_array_t mItems;
BOOL mTabsHighlightEnabled;
static F64 sWaitingForCallabck;
bool mItemsListDirty;
S32 mMouseX;
S32 mMouseY;

View File

@ -1782,6 +1782,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

@ -619,6 +619,8 @@ void LLFloaterIMNearbyChatHandler::processChat(const LLChat& chat_msg,
static LLCachedControl<bool> FSllOwnerSayToScriptDebugWindow(gSavedPerAccountSettings, "FSllOwnerSayToScriptDebugWindow");
if (chat_msg.mChatType == CHAT_TYPE_DEBUG_MSG || (chat_msg.mChatType == CHAT_TYPE_OWNER && FSllOwnerSayToScriptDebugWindow))
{
if (LLFloater::isQuitRequested()) return;
// <FS:Kadah> [FSllOwnerSayToScriptDebugWindow] Show llOwnerSays in the script debug window instead of local chat
// if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE)
if(gSavedSettings.getBOOL("ShowScriptErrors") == FALSE && chat_msg.mChatType == CHAT_TYPE_DEBUG_MSG)

View File

@ -126,6 +126,7 @@
#include "llpresetsmanager.h"
#include "llviewercontrol.h"
#include "llpresetsmanager.h"
#include "llinventoryfunctions.h"
#include "llsearchableui.h"
#include "llperfstats.h"
@ -2839,25 +2840,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

@ -60,6 +60,8 @@ LLFloaterProfileTexture::~LLFloaterProfileTexture()
mImage->forceActive(); // <FS:Ansariel> Make sure it can get discarded
mImage = NULL;
}
LLLoadedCallbackEntry::cleanUpCallbackList(&mCallbackTextureList);
}
// virtual

View File

@ -150,7 +150,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 );
};
@ -2987,11 +2987,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);
@ -3005,7 +3006,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,
@ -3014,23 +3015,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

@ -71,14 +71,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();
}
@ -133,11 +133,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

@ -243,8 +243,13 @@ void LLGLTFMaterialList::applyOverrideMessage(LLMessageSystem* msg, const std::s
}
}
}
region->cacheFullUpdateGLTFOverride(cache);
// <FS:Beq> FIRE-33808 - Material Override Cache causes long delays
if(cache.mSides.size() > 0)
{
region->cacheFullUpdateGLTFOverride(cache);
LL_DEBUGS("GLTF") << "GLTF Material Override: " << cache.mObjectId << " " << cache.mLocalId << " " << cache.mRegionHandle << " (sides:" << (cache.mSides.size()) << ")" << LL_ENDL;
}
// </FS:Beq>
}
}

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