Merge pull request #3706 from secondlife/release/2025.03

Release/2025.03
master
Jonathan "Geenz" Goodman 2025-04-15 09:50:42 -04:00 committed by GitHub
commit cf2b4dbfb2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
216 changed files with 4311 additions and 1748 deletions

View File

@ -42,8 +42,8 @@ jobs:
needs: setup
strategy:
matrix:
runner: [windows-large, macos-15-xlarge]
configuration: ${{ fromJSON(needs.setup.outputs.configurations) }}
runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-latest","macos-15"]') }}
configuration: ${{ fromJson(needs.setup.outputs.configurations) }}
runs-on: ${{ matrix.runner }}
outputs:
viewer_channel: ${{ steps.build.outputs.viewer_channel }}

View File

@ -2039,11 +2039,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>191e4ef07a35f7147708415465191ce7622e3012</string>
<string>a3cc405d48a48a474d05b3de3d28da2005d80037</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-8668009/openal-1.23.1-darwin64-8979520327.tar.zst</string>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-darwin64-13245988487.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -2053,11 +2053,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>3bd8c9028ef42bdb43c7422e7d324e213fdb081e</string>
<string>a2b63f0f85ca156c59ee1d34ef96c8e50b89153c</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-8668009/openal-1.23.1-linux64-8979520327.tar.zst</string>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-linux64-13245988487.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@ -2067,11 +2067,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>4b849609abec790e89be5fad8ddee3717ee301c4</string>
<string>8ad24fba1191c9cb0d2ab36e64b04b4648a99f43</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.23.1-8668009/openal-1.23.1-windows64-8979520327.tar.zst</string>
<string>https://github.com/secondlife/3p-openal-soft/releases/download/v1.24.2-r1/openal-1.24.2-r1-windows64-13245988487.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@ -3014,14 +3014,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>build</key>
<map>
<key>command</key>
<string>xcodebuild</string>
<string>cmake</string>
<key>options</key>
<array>
<string>-configuration</string>
<string>--build</string>
<string>.</string>
<string>--config</string>
<string>RelWithDebInfo</string>
<string>-project</string>
<string>SecondLife.xcodeproj</string>
<string>-parallelizeTargets</string>
<string>--parallel</string>
<string>$AUTOBUILD_CPU_COUNT</string>
</array>
</map>
<key>default</key>
@ -3042,14 +3043,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>build</key>
<map>
<key>command</key>
<string>xcodebuild</string>
<string>cmake</string>
<key>options</key>
<array>
<string>-configuration</string>
<string>--build</string>
<string>.</string>
<string>--config</string>
<string>RelWithDebInfo</string>
<string>-project</string>
<string>SecondLife.xcodeproj</string>
<string>-parallelizeTargets</string>
<string>--parallel</string>
<string>$AUTOBUILD_CPU_COUNT</string>
</array>
</map>
<key>name</key>
@ -3072,14 +3074,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>build</key>
<map>
<key>command</key>
<string>xcodebuild</string>
<string>cmake</string>
<key>options</key>
<array>
<string>-configuration</string>
<string>--build</string>
<string>.</string>
<string>--config</string>
<string>Release</string>
<string>-project</string>
<string>SecondLife.xcodeproj</string>
<string>-parallelizeTargets</string>
<string>--parallel</string>
<string>$AUTOBUILD_CPU_COUNT</string>
</array>
</map>
<key>name</key>
@ -3098,14 +3101,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>build</key>
<map>
<key>command</key>
<string>xcodebuild</string>
<string>cmake</string>
<key>options</key>
<array>
<string>-configuration</string>
<string>--build</string>
<string>.</string>
<string>--config</string>
<string>Release</string>
<string>-project</string>
<string>SecondLife.xcodeproj</string>
<string>-parallelizeTargets</string>
<string>--parallel</string>
<string>$AUTOBUILD_CPU_COUNT</string>
</array>
</map>
<key>name</key>

View File

@ -34,7 +34,7 @@ add_compile_definitions(BOOST_BIND_GLOBAL_PLACEHOLDERS)
# Force enable SSE2 instructions in GLM per the manual
# https://github.com/g-truc/glm/blob/master/manual.md#section2_10
add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_FORCE_SSE2=1)
add_compile_definitions(GLM_FORCE_DEFAULT_ALIGNED_GENTYPES=1 GLM_FORCE_SSE2=1 GLM_ENABLE_EXPERIMENTAL=1)
# Configure crash reporting
set(RELEASE_CRASH_REPORTING OFF CACHE BOOL "Enable use of crash reporting in release builds")
@ -48,6 +48,11 @@ if(NON_RELEASE_CRASH_REPORTING)
add_compile_definitions( LL_SEND_CRASH_REPORTS=1)
endif()
set(USE_LTO OFF CACHE BOOL "Enable Link Time Optimization")
if(USE_LTO)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
endif()
# Don't bother with a MinSizeRel or Debug builds.
set(CMAKE_CONFIGURATION_TYPES "RelWithDebInfo;Release" CACHE STRING "Supported build types." FORCE)
@ -101,7 +106,7 @@ if (WINDOWS)
#ND: When using something like buildcache (https://github.com/mbitsnbites/buildcache)
# to make those wrappers work /Zi must be changed to /Z7, as /Zi due to it's nature is not compatible with caching
if( ${CMAKE_CXX_COMPILER_LAUNCHER} MATCHES ".*cache.*")
if(${CMAKE_CXX_COMPILER_LAUNCHER} MATCHES ".*cache.*")
add_compile_options( /Z7 )
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")

View File

@ -799,7 +799,6 @@ void LLAvatarAppearance::buildCharacter()
bool status = loadAvatar();
stop_glerror();
// gPrintMessagesThisFrame = true;
LL_DEBUGS() << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << LL_ENDL;
if (!status)

View File

@ -981,7 +981,7 @@ void LLPolyMesh::initializeForMorph()
LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
memcpy((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices)); // allocated in LLPolyMeshSharedData::allocateVertexData
for (S32 i = 0; i < mSharedData->mNumVertices; ++i)
{

View File

@ -645,9 +645,10 @@ void LLWearable::addVisualParam(LLVisualParam *param)
void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
{
if( is_in_map(mVisualParamIndexMap, param_index ) )
visual_param_index_map_t::iterator found = mVisualParamIndexMap.find(param_index);
if(found != mVisualParamIndexMap.end())
{
LLVisualParam *wearable_param = mVisualParamIndexMap[param_index];
LLVisualParam *wearable_param = found->second;
wearable_param->setWeight(value);
}
else
@ -658,10 +659,10 @@ void LLWearable::setVisualParamWeight(S32 param_index, F32 value)
F32 LLWearable::getVisualParamWeight(S32 param_index) const
{
if( is_in_map(mVisualParamIndexMap, param_index ) )
visual_param_index_map_t::const_iterator found = mVisualParamIndexMap.find(param_index);
if(found != mVisualParamIndexMap.end())
{
const LLVisualParam *wearable_param = mVisualParamIndexMap.find(param_index)->second;
return wearable_param->getWeight();
return found->second->getWeight();
}
else
{
@ -726,7 +727,7 @@ void LLWearable::writeToAvatar(LLAvatarAppearance* avatarp)
if (!avatarp) return;
// Pull params
for( LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
for( const LLVisualParam* param = avatarp->getFirstVisualParam(); param; param = avatarp->getNextVisualParam() )
{
// cross-wearable parameters are not authoritative, as they are driven by a different wearable. So don't copy the values to the
// avatar object if cross wearable. Cross wearable params get their values from the avatar, they shouldn't write the other way.

View File

@ -79,7 +79,7 @@ bool LLAudioEngine_OpenAL::init(void* userdata, const std::string &app_title)
ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext());
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor);
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
LL_INFOS() << "ALC version: " << major << "." << minor << LL_ENDL;
LL_INFOS() << "ALC default device: "
@ -190,6 +190,8 @@ LLAudioChannelOpenAL::~LLAudioChannelOpenAL()
void LLAudioChannelOpenAL::cleanup()
{
alSourceStop(mALSource);
alSourcei(mALSource, AL_BUFFER, AL_NONE);
mCurrentBufferp = NULL;
}

View File

@ -282,7 +282,7 @@ public:
LLRunner& getRunner() { return mRunner; }
#ifdef LL_WINDOWS
virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { }
virtual bool reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { return false; }
#endif
public:

View File

@ -310,25 +310,54 @@ namespace
static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop)
U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop)
{
if (code == STATUS_MSC_EXCEPTION)
if (LLApp::instance()->reportCrashToBugsplat((void*)exception_infop))
{
// Handled
return EXCEPTION_CONTINUE_SEARCH;
}
else if (code == STATUS_MSC_EXCEPTION)
{
// C++ exception, go on
return EXCEPTION_CONTINUE_SEARCH;
}
else
{
// handle it
// handle it, convert to std::exception
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
void cpphandle(const LLCoros::callable_t& callable, const std::string& name)
{
// SE and C++ can not coexists, thus two handlers
try
{
callable();
}
catch (const LLCoros::Stop& exc)
{
LL_INFOS("LLCoros") << "coroutine " << name << " terminating because "
<< exc.what() << LL_ENDL;
}
catch (const LLContinueError&)
{
// Any uncaught exception derived from LLContinueError will be caught
// here and logged. This coroutine will terminate but the rest of the
// viewer will carry on.
LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name));
}
}
void sehandle(const LLCoros::callable_t& callable)
void sehandle(const LLCoros::callable_t& callable, const std::string& name)
{
__try
{
callable();
// handle stop and continue exceptions first
cpphandle(callable, name);
}
__except (exception_filter(GetExceptionCode(), GetExceptionInformation()))
{
@ -340,16 +369,7 @@ void sehandle(const LLCoros::callable_t& callable)
throw std::exception(integer_string);
}
}
#else // ! LL_WINDOWS
inline void sehandle(const LLCoros::callable_t& callable)
{
callable();
}
#endif // ! LL_WINDOWS
#endif // LL_WINDOWS
} // anonymous namespace
// Top-level wrapper around caller's coroutine callable.
@ -362,10 +382,14 @@ void LLCoros::toplevel(std::string name, callable_t callable)
// set it as current
mCurrent.reset(&corodata);
#ifdef LL_WINDOWS
// can not use __try directly, toplevel requires unwinding, thus use of a wrapper
sehandle(callable, name);
#else // LL_WINDOWS
// run the code the caller actually wants in the coroutine
try
{
sehandle(callable);
callable();
}
catch (const Stop& exc)
{
@ -387,6 +411,7 @@ void LLCoros::toplevel(std::string name, callable_t callable)
<< name << LL_ENDL;
LLCoros::instance().saveException(name, std::current_exception());
}
#endif // else LL_WINDOWS
}
//static

View File

@ -77,6 +77,15 @@ std::string LLDate::asRFC1123() const
return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT"));
}
std::string LLDate::toLocalDateString (std::string fmt) const
{
LL_PROFILE_ZONE_SCOPED;
time_t locSeconds = (time_t) mSecondsSinceEpoch;
struct tm * lt = localtime (&locSeconds);
return toHTTPDateString(lt, fmt);
}
std::string LLDate::toHTTPDateString (std::string fmt) const
{
LL_PROFILE_ZONE_SCOPED;

View File

@ -77,6 +77,7 @@ public:
std::string asRFC1123() const;
void toStream(std::ostream&) const;
bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const;
std::string toLocalDateString(std::string fmt) const;
std::string toHTTPDateString (std::string fmt) const;
static std::string toHTTPDateString (tm * gmt, std::string fmt);
/**

View File

@ -17,6 +17,7 @@
// std headers
// external library headers
// other Linden headers
#include "llapp.h"
#include "llcoros.h"
#include LLCOROS_MUTEX_HEADER
#include "llerror.h"
@ -102,19 +103,95 @@ std::string LL::WorkQueueBase::makeName(const std::string& name)
return STRINGIZE("WorkQueue" << num);
}
namespace
{
#if LL_WINDOWS
static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific
U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop)
{
if (LLApp::instance()->reportCrashToBugsplat((void*)exception_infop))
{
// Handled
return EXCEPTION_CONTINUE_SEARCH;
}
else if (code == STATUS_MSC_EXCEPTION)
{
// C++ exception, go on
return EXCEPTION_CONTINUE_SEARCH;
}
else
{
// handle it, convert to std::exception
return EXCEPTION_EXECUTE_HANDLER;
}
return EXCEPTION_CONTINUE_SEARCH;
}
void cpphandle(const LL::WorkQueueBase::Work& work)
{
// SE and C++ can not coexists, thus two handlers
try
{
work();
}
catch (const LLContinueError&)
{
// Any uncaught exception derived from LLContinueError will be caught
// here and logged. This coroutine will terminate but the rest of the
// viewer will carry on.
LOG_UNHANDLED_EXCEPTION(STRINGIZE("LLContinue in work queue"));
}
}
void sehandle(const LL::WorkQueueBase::Work& work)
{
__try
{
// handle stop and continue exceptions first
cpphandle(work);
}
__except (exception_filter(GetExceptionCode(), GetExceptionInformation()))
{
// convert to C++ styled exception
char integer_string[512];
sprintf(integer_string, "SEH, code: %lu\n", GetExceptionCode());
throw std::exception(integer_string);
}
}
#endif // LL_WINDOWS
} // anonymous namespace
void LL::WorkQueueBase::callWork(const Work& work)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD;
#ifdef LL_WINDOWS
// can not use __try directly, toplevel requires unwinding, thus use of a wrapper
sehandle(work);
#else // LL_WINDOWS
try
{
work();
}
catch (...)
catch (LLContinueError&)
{
// No matter what goes wrong with any individual work item, the worker
// thread must go on! Log our own instance name with the exception.
LOG_UNHANDLED_EXCEPTION(getKey());
}
catch (...)
{
// Stash any other kind of uncaught exception to be rethrown by main thread.
LL_WARNS("LLCoros") << "Capturing and rethrowing uncaught exception in WorkQueueBase "
<< getKey() << LL_ENDL;
LL::WorkQueue::ptr_t main_queue = LL::WorkQueue::getInstance("mainloop");
main_queue->post(
// Bind the current exception, rethrow it in main loop.
[exc = std::current_exception()]() { std::rethrow_exception(exc); });
}
#endif // else LL_WINDOWS
}
void LL::WorkQueueBase::error(const std::string& msg)

View File

@ -130,17 +130,6 @@ void LLSettingsBase::saveValuesIfNeeded()
}
//=========================================================================
void LLSettingsBase::lerpSettings(LLSettingsBase &other, F64 mix)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_ENVIRONMENT;
saveValuesIfNeeded();
stringset_t skip = getSkipInterpolateKeys();
stringset_t slerps = getSlerpKeys();
mSettings = interpolateSDMap(mSettings, other.getSettings(), other.getParameterMap(), mix, skip, slerps);
setDirtyFlag(true);
loadValuesFromLLSD();
}
void LLSettingsBase::lerpVector2(LLVector2& a, const LLVector2& b, F32 mix)
{
a.mV[0] = lerp(a.mV[0], b.mV[0], mix);

View File

@ -348,13 +348,8 @@ protected:
LLSettingsBase();
LLSettingsBase(const LLSD setting);
static LLSD settingValidation(LLSD settings);
typedef std::set<std::string> stringset_t;
// combining settings objects. Customize for specific setting types
virtual void lerpSettings(LLSettingsBase &other, BlendFactor mix);
// combining settings maps where it can based on mix rate
// @settings initial value (mix==0)
// @other target value (mix==1)

View File

@ -279,103 +279,118 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod
{
LLImageDataLock lock(&base);
S32 data_size = base.getDataSize();
S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
//
// Initialization
//
mCodeStreamp.reset();
// It's not clear to nat under what circumstances we would reuse a
// pre-existing LLKDUMemSource instance. As of 2016-08-05, it consists of
// two U32s and a pointer, so it's not as if it would be a huge overhead
// to allocate a new one every time.
// Also -- why is base.getData() tested specifically here? If that returns
// NULL, shouldn't we bail out of the whole method?
if (!mInputp && base.getData())
try
{
// The compressed data has been loaded
// Setup the source for the codestream
mInputp.reset(new LLKDUMemSource(base.getData(), data_size));
}
if (mInputp)
{
// This is LLKDUMemSource::reset(), not boost::scoped_ptr::reset().
mInputp->reset();
}
S32 data_size = base.getDataSize();
S32 max_bytes = (base.getMaxBytes() ? base.getMaxBytes() : data_size);
mCodeStreamp->create(mInputp.get());
//
// Initialization
//
mCodeStreamp.reset();
// Set the maximum number of bytes to use from the codestream
// *TODO: This seems to be wrong. The base class should have no idea of
// how j2c compression works so no good way of computing what's the byte
// range to be used.
mCodeStreamp->set_max_bytes(max_bytes,true);
// If you want to flip or rotate the image for some reason, change
// the resolution, or identify a restricted region of interest, this is
// the place to do it. You may use "kdu_codestream::change_appearance"
// and "kdu_codestream::apply_input_restrictions" for this purpose.
// If you wish to truncate the code-stream prior to decompression, you
// may use "kdu_codestream::set_max_bytes".
// If you wish to retain all compressed data so that the material
// can be decompressed multiple times, possibly with different appearance
// parameters, you should call "kdu_codestream::set_persistent" here.
// There are a variety of other features which must be enabled at
// this point if you want to take advantage of them. See the
// descriptions appearing with the "kdu_codestream" interface functions
// in "kdu_compressed.h" for an itemized account of these capabilities.
switch (mode)
{
case MODE_FAST:
mCodeStreamp->set_fast();
break;
case MODE_RESILIENT:
mCodeStreamp->set_resilient();
break;
case MODE_FUSSY:
mCodeStreamp->set_fussy();
break;
default:
llassert(0);
mCodeStreamp->set_fast();
}
kdu_dims dims;
mCodeStreamp->get_dims(0,dims);
S32 components = mCodeStreamp->get_num_components();
// Check that components have consistent dimensions (for PPM file)
for (int idx = 1; idx < components; ++idx)
{
kdu_dims other_dims;
mCodeStreamp->get_dims(idx, other_dims);
if (other_dims != dims)
// It's not clear to nat under what circumstances we would reuse a
// pre-existing LLKDUMemSource instance. As of 2016-08-05, it consists of
// two U32s and a pointer, so it's not as if it would be a huge overhead
// to allocate a new one every time.
// Also -- why is base.getData() tested specifically here? If that returns
// NULL, shouldn't we bail out of the whole method?
if (!mInputp && base.getData())
{
// This method is only called from methods that catch KDUError.
// We want to fail the image load, not crash the viewer.
LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions "
<< stringize(other_dims)
<< " do not match component 0 dimensions "
<< stringize(dims) << "!")));
// The compressed data has been loaded
// Setup the source for the codestream
mInputp.reset(new LLKDUMemSource(base.getData(), data_size));
}
if (mInputp)
{
// This is LLKDUMemSource::reset(), not boost::scoped_ptr::reset().
mInputp->reset();
}
mCodeStreamp->create(mInputp.get());
// Set the maximum number of bytes to use from the codestream
// *TODO: This seems to be wrong. The base class should have no idea of
// how j2c compression works so no good way of computing what's the byte
// range to be used.
mCodeStreamp->set_max_bytes(max_bytes, true);
// If you want to flip or rotate the image for some reason, change
// the resolution, or identify a restricted region of interest, this is
// the place to do it. You may use "kdu_codestream::change_appearance"
// and "kdu_codestream::apply_input_restrictions" for this purpose.
// If you wish to truncate the code-stream prior to decompression, you
// may use "kdu_codestream::set_max_bytes".
// If you wish to retain all compressed data so that the material
// can be decompressed multiple times, possibly with different appearance
// parameters, you should call "kdu_codestream::set_persistent" here.
// There are a variety of other features which must be enabled at
// this point if you want to take advantage of them. See the
// descriptions appearing with the "kdu_codestream" interface functions
// in "kdu_compressed.h" for an itemized account of these capabilities.
switch (mode)
{
case MODE_FAST:
mCodeStreamp->set_fast();
break;
case MODE_RESILIENT:
mCodeStreamp->set_resilient();
break;
case MODE_FUSSY:
mCodeStreamp->set_fussy();
break;
default:
llassert(0);
mCodeStreamp->set_fast();
}
kdu_dims dims;
mCodeStreamp->get_dims(0, dims);
S32 components = mCodeStreamp->get_num_components();
// Check that components have consistent dimensions (for PPM file)
for (int idx = 1; idx < components; ++idx)
{
kdu_dims other_dims;
mCodeStreamp->get_dims(idx, other_dims);
if (other_dims != dims)
{
// This method is only called from methods that catch KDUError.
// We want to fail the image load, not crash the viewer.
LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions "
<< stringize(other_dims)
<< " do not match component 0 dimensions "
<< stringize(dims) << "!")));
}
}
// Get the number of resolution levels in that image
mLevels = mCodeStreamp->get_min_dwt_levels();
// Set the base dimensions
base.setSize(dims.size.x, dims.size.y, components);
base.setLevels(mLevels);
if (!keep_codestream)
{
mCodeStreamp.reset();
mInputp.reset();
}
}
// Get the number of resolution levels in that image
mLevels = mCodeStreamp->get_min_dwt_levels();
// Set the base dimensions
base.setSize(dims.size.x, dims.size.y, components);
base.setLevels(mLevels);
if (!keep_codestream)
catch (std::bad_alloc&)
{
mCodeStreamp.reset();
mInputp.reset();
// we are in a thread, can't show an 'out of memory' here,
// main thread will keep going
throw;
}
catch (...)
{
LLTHROW(KDUError(STRINGIZE("Unknown J2C error : " +
boost::current_exception_diagnostic_information() << "!")));
}
}

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmath.h"
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmath.h"
#include "llmatrix4a.h"

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmath.h"
#include "llrigginginfo.h"

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llmemory.h"
#include "llmath.h"
#include "llquantize.h"

View File

@ -5586,14 +5586,22 @@ struct MikktData
{
U32 count = face->mNumIndices;
p.resize(count);
n.resize(count);
tc.resize(count);
t.resize(count);
if (face->mWeights)
try
{
w.resize(count);
p.resize(count);
n.resize(count);
tc.resize(count);
t.resize(count);
if (face->mWeights)
{
w.resize(count);
}
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Bad memory allocation in MikktData, elements count: " << count << LL_ENDL;
}
@ -5665,7 +5673,16 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
// and is executed on a background thread
MikktData data(this);
mikk::Mikktspace ctx(data);
ctx.genTangSpace();
try
{
ctx.genTangSpace();
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Bad memory allocation in MikktData::genTangSpace" << LL_ENDL;
}
//re-weld
meshopt_Stream mos[] =
@ -5678,7 +5695,15 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
};
std::vector<U32> remap;
remap.resize(data.p.size());
try
{
remap.resize(data.p.size());
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Failed to allocate memory for remap: " << (S32)data.p.size() << LL_ENDL;
}
U32 stream_count = data.w.empty() ? 4 : 5;

View File

@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
#include "linden_common.h"
#include "llvolumeoctree.h"
#include "llvector4a.h"

View File

@ -28,6 +28,7 @@
#define LL_V3COLORUTIL_H
#include "v3color.h"
#include "v4color.h"
inline LLColor3 componentDiv(LLColor3 const &left, LLColor3 const & right)
{

View File

@ -585,7 +585,8 @@ void LLAssetStorage::getAssetData(const LLUUID uuid,
// static
void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type,
const LLUUID& callback_id, LLAssetType::EType callback_type,
S32 result_code, LLExtStat ext_status)
S32 result_code, LLExtStat ext_status,
S32 bytes_fetched)
{
// find and callback ALL pending requests for this UUID
// SJB: We process the callbacks in reverse order, I do not know if this is important,
@ -598,6 +599,10 @@ void LLAssetStorage::removeAndCallbackPendingDownloads(const LLUUID& file_id, LL
LLAssetRequest* tmp = *curiter;
if ((tmp->getUUID() == file_id) && (tmp->getType()== file_type))
{
if (bytes_fetched > 0)
{
tmp->mBytesFetched = bytes_fetched;
}
requests.push_front(tmp);
iter = gAssetStorage->mPendingDownloads.erase(curiter);
}
@ -664,6 +669,7 @@ void LLAssetStorage::downloadCompleteCallback(
callback_type = req->getType();
}
S32 bytes_fetched = 0;
if (LL_ERR_NOERR == result)
{
// we might have gotten a zero-size file
@ -677,21 +683,11 @@ void LLAssetStorage::downloadCompleteCallback(
}
else
{
#if 1
for (request_list_t::iterator iter = gAssetStorage->mPendingDownloads.begin();
iter != gAssetStorage->mPendingDownloads.end(); ++iter )
{
LLAssetRequest* dlreq = *iter;
if ((dlreq->getUUID() == file_id) && (dlreq->getType()== file_type))
{
dlreq->mBytesFetched = vfile.getSize();
}
}
#endif
bytes_fetched = vfile.getSize();
}
}
removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, result, ext_status);
removeAndCallbackPendingDownloads(file_id, file_type, callback_id, callback_type, result, ext_status, bytes_fetched);
}
void LLAssetStorage::getEstateAsset(

View File

@ -324,7 +324,8 @@ public:
static void removeAndCallbackPendingDownloads(const LLUUID& file_id, LLAssetType::EType file_type,
const LLUUID& callback_id, LLAssetType::EType callback_type,
S32 result_code, LLExtStat ext_status);
S32 result_code, LLExtStat ext_status,
S32 bytes_fetched);
// download process callbacks
static void downloadCompleteCallback(

View File

@ -301,12 +301,12 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
mPoolSize(size),
mActiveCoprocsCount(0),
mPending(0),
mPendingCoprocs(std::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE)),
mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mCoroMapping()
{
try
{
mPendingCoprocs = std::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE);
// store in our LLTempBoundListener so that when the LLCoprocedurePool is
// destroyed, we implicitly disconnect from this LLEventPump
// Monitores application status
@ -339,6 +339,11 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
llassert(0); // Fix Me! Ignoring missing listener!
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("CoProcMgr") << "Bad memory allocation in LLCoprocedurePool::LLCoprocedurePool!" << LL_ENDL;
}
for (size_t count = 0; count < mPoolSize; ++count)
{

View File

@ -295,7 +295,15 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons
}
else
{
result = this->handleSuccess(response, status);
try
{
result = this->handleSuccess(response, status);
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("CoreHTTP") << "Failed to allocate memory for response handling." << LL_ENDL;
}
}
buildStatusEntry(response, status, result);

View File

@ -94,6 +94,8 @@ LLExperienceCache::LLExperienceCache()
LLExperienceCache::~LLExperienceCache()
{
// can exit without cleanup()
sShutdown = true;
}
void LLExperienceCache::initSingleton()

View File

@ -32,8 +32,6 @@
#include "lltimer.h"
#include "llhost.h"
///////////////////////////////////////////////////////////
LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32 size) : mHost(host)
{
mSize = 0;
@ -41,7 +39,7 @@ LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32
if (size > NET_BUFFER_SIZE)
{
LL_ERRS() << "Sending packet > " << NET_BUFFER_SIZE << " of size " << size << LL_ENDL;
LL_ERRS() << "Constructing packet with size=" << size << " > " << NET_BUFFER_SIZE << LL_ENDL;
}
else
{
@ -51,7 +49,6 @@ LLPacketBuffer::LLPacketBuffer(const LLHost &host, const char *datap, const S32
mSize = size;
}
}
}
LLPacketBuffer::LLPacketBuffer (S32 hSocket)
@ -59,18 +56,29 @@ LLPacketBuffer::LLPacketBuffer (S32 hSocket)
init(hSocket);
}
///////////////////////////////////////////////////////////
LLPacketBuffer::~LLPacketBuffer ()
{
}
///////////////////////////////////////////////////////////
void LLPacketBuffer::init (S32 hSocket)
void LLPacketBuffer::init(S32 hSocket)
{
mSize = receive_packet(hSocket, mData);
mHost = ::get_sender();
mReceivingIF = ::get_receiving_interface();
}
void LLPacketBuffer::init(const char* buffer, S32 data_size, const LLHost& host)
{
if (data_size > NET_BUFFER_SIZE)
{
LL_ERRS() << "Initializing packet with size=" << data_size << " > " << NET_BUFFER_SIZE << LL_ENDL;
}
else
{
memcpy(mData, buffer, data_size);
mSize = data_size;
mHost = host;
mReceivingIF = ::get_receiving_interface();
}
}

View File

@ -35,20 +35,22 @@ class LLPacketBuffer
{
public:
LLPacketBuffer(const LLHost &host, const char *datap, const S32 size);
LLPacketBuffer(S32 hSocket); // receive a packet
LLPacketBuffer(S32 hSocket); // receive a packet
~LLPacketBuffer();
S32 getSize() const { return mSize; }
const char *getData() const { return mData; }
LLHost getHost() const { return mHost; }
LLHost getReceivingInterface() const { return mReceivingIF; }
void init(S32 hSocket);
void init(const char* buffer, S32 data_size, const LLHost& host);
protected:
char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */
S32 mSize; // size of buffer in bytes
LLHost mHost; // source/dest IP and port
LLHost mReceivingIF; // source/dest IP and port
char mData[NET_BUFFER_SIZE]; // packet data /* Flawfinder : ignore */
S32 mSize; // size of buffer in bytes
LLHost mHost; // source/dest IP and port
LLHost mReceivingIF; // source/dest IP and port
};
#endif

View File

@ -1,6 +1,6 @@
/**
* @file llpacketring.cpp
* @brief implementation of LLPacketRing class for a packet.
* @brief implementation of LLPacketRing class.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
@ -43,313 +43,44 @@
#include "message.h"
#include "u64.h"
///////////////////////////////////////////////////////////
LLPacketRing::LLPacketRing () :
mUseInThrottle(false),
mUseOutThrottle(false),
mInThrottle(256000.f),
mOutThrottle(64000.f),
mActualBitsIn(0),
mActualBitsOut(0),
mMaxBufferLength(64000),
mInBufferLength(0),
mOutBufferLength(0),
mDropPercentage(0.0f),
mPacketsToDrop(0x0)
constexpr S16 MAX_BUFFER_RING_SIZE = 1024;
constexpr S16 DEFAULT_BUFFER_RING_SIZE = 256;
LLPacketRing::LLPacketRing ()
: mPacketRing(DEFAULT_BUFFER_RING_SIZE, nullptr)
{
LLHost invalid_host;
for (size_t i = 0; i < mPacketRing.size(); ++i)
{
mPacketRing[i] = new LLPacketBuffer(invalid_host, nullptr, 0);
}
}
///////////////////////////////////////////////////////////
LLPacketRing::~LLPacketRing ()
{
cleanup();
}
///////////////////////////////////////////////////////////
void LLPacketRing::cleanup ()
{
LLPacketBuffer *packetp;
while (!mReceiveQueue.empty())
for (auto packet : mPacketRing)
{
packetp = mReceiveQueue.front();
delete packetp;
mReceiveQueue.pop();
}
while (!mSendQueue.empty())
{
packetp = mSendQueue.front();
delete packetp;
mSendQueue.pop();
delete packet;
}
mPacketRing.clear();
mNumBufferedPackets = 0;
mNumBufferedBytes = 0;
mHeadIndex = 0;
}
///////////////////////////////////////////////////////////
void LLPacketRing::dropPackets (U32 num_to_drop)
{
mPacketsToDrop += num_to_drop;
}
///////////////////////////////////////////////////////////
void LLPacketRing::setDropPercentage (F32 percent_to_drop)
{
mDropPercentage = percent_to_drop;
}
void LLPacketRing::setUseInThrottle(const bool use_throttle)
{
mUseInThrottle = use_throttle;
}
void LLPacketRing::setUseOutThrottle(const bool use_throttle)
{
mUseOutThrottle = use_throttle;
}
void LLPacketRing::setInBandwidth(const F32 bps)
{
mInThrottle.setRate(bps);
}
void LLPacketRing::setOutBandwidth(const F32 bps)
{
mOutThrottle.setRate(bps);
}
///////////////////////////////////////////////////////////
S32 LLPacketRing::receiveFromRing (S32 socket, char *datap)
{
if (mInThrottle.checkOverflow(0))
{
// We don't have enough bandwidth, don't give them a packet.
return 0;
}
LLPacketBuffer *packetp = NULL;
if (mReceiveQueue.empty())
{
// No packets on the queue, don't give them any.
return 0;
}
S32 packet_size = 0;
packetp = mReceiveQueue.front();
mReceiveQueue.pop();
packet_size = packetp->getSize();
if (packetp->getData() != NULL)
{
memcpy(datap, packetp->getData(), packet_size); /*Flawfinder: ignore*/
}
// need to set sender IP/port!!
mLastSender = packetp->getHost();
mLastReceivingIF = packetp->getReceivingInterface();
delete packetp;
this->mInBufferLength -= packet_size;
// Adjust the throttle
mInThrottle.throttleOverflow(packet_size * 8.f);
return packet_size;
}
///////////////////////////////////////////////////////////
S32 LLPacketRing::receivePacket (S32 socket, char *datap)
{
S32 packet_size = 0;
// If using the throttle, simulate a limited size input buffer.
if (mUseInThrottle)
{
bool done = false;
// push any current net packet (if any) onto delay ring
while (!done)
{
LLPacketBuffer *packetp;
packetp = new LLPacketBuffer(socket);
if (packetp->getSize())
{
mActualBitsIn += packetp->getSize() * 8;
// Fake packet loss
if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
{
mPacketsToDrop++;
}
if (mPacketsToDrop)
{
delete packetp;
packetp = NULL;
packet_size = 0;
mPacketsToDrop--;
}
}
// If we faked packet loss, then we don't have a packet
// to use for buffer overflow testing
if (packetp)
{
if (mInBufferLength + packetp->getSize() > mMaxBufferLength)
{
// Toss it.
LL_WARNS() << "Throwing away packet, overflowing buffer" << LL_ENDL;
delete packetp;
packetp = NULL;
}
else if (packetp->getSize())
{
mReceiveQueue.push(packetp);
mInBufferLength += packetp->getSize();
}
else
{
delete packetp;
packetp = NULL;
done = true;
}
}
else
{
// No packetp, keep going? - no packetp == faked packet loss
}
}
// Now, grab data off of the receive queue according to our
// throttled bandwidth settings.
packet_size = receiveFromRing(socket, datap);
}
else
{
// no delay, pull straight from net
if (LLProxy::isSOCKSProxyEnabled())
{
U8 buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
packet_size = receive_packet(socket, static_cast<char*>(static_cast<void*>(buffer)));
if (packet_size > SOCKS_HEADER_SIZE)
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size - SOCKS_HEADER_SIZE);
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
mLastSender.setAddress(header->addr);
mLastSender.setPort(ntohs(header->port));
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
}
else
{
packet_size = 0;
}
}
else
{
packet_size = receive_packet(socket, datap);
mLastSender = ::get_sender();
}
mLastReceivingIF = ::get_receiving_interface();
if (packet_size) // did we actually get a packet?
{
if (mDropPercentage && (ll_frand(100.f) < mDropPercentage))
{
mPacketsToDrop++;
}
if (mPacketsToDrop)
{
packet_size = 0;
mPacketsToDrop--;
}
}
}
return packet_size;
bool drop = computeDrop();
return (mNumBufferedPackets > 0) ?
receiveOrDropBufferedPacket(datap, drop) :
receiveOrDropPacket(socket, datap, drop);
}
bool LLPacketRing::sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host)
bool send_packet_helper(int socket, const char * datap, S32 data_size, LLHost host)
{
bool status = true;
if (!mUseOutThrottle)
{
return sendPacketImpl(h_socket, send_buffer, buf_size, host );
}
else
{
mActualBitsOut += buf_size * 8;
LLPacketBuffer *packetp = NULL;
// See if we've got enough throttle to send a packet.
while (!mOutThrottle.checkOverflow(0.f))
{
// While we have enough bandwidth, send a packet from the queue or the current packet
S32 packet_size = 0;
if (!mSendQueue.empty())
{
// Send a packet off of the queue
LLPacketBuffer *packetp = mSendQueue.front();
mSendQueue.pop();
mOutBufferLength -= packetp->getSize();
packet_size = packetp->getSize();
status = sendPacketImpl(h_socket, packetp->getData(), packet_size, packetp->getHost());
delete packetp;
// Update the throttle
mOutThrottle.throttleOverflow(packet_size * 8.f);
}
else
{
// If the queue's empty, we can just send this packet right away.
status = sendPacketImpl(h_socket, send_buffer, buf_size, host );
packet_size = buf_size;
// Update the throttle
mOutThrottle.throttleOverflow(packet_size * 8.f);
// This was the packet we're sending now, there are no other packets
// that we need to send
return status;
}
}
// We haven't sent the incoming packet, add it to the queue
if (mOutBufferLength + buf_size > mMaxBufferLength)
{
// Nuke this packet, we overflowed the buffer.
// Toss it.
LL_WARNS() << "Throwing away outbound packet, overflowing buffer" << LL_ENDL;
}
else
{
static LLTimer queue_timer;
if ((mOutBufferLength > 4192) && queue_timer.getElapsedTimeF32() > 1.f)
{
// Add it to the queue
LL_INFOS() << "Outbound packet queue " << mOutBufferLength << " bytes" << LL_ENDL;
queue_timer.reset();
}
packetp = new LLPacketBuffer(host, send_buffer, buf_size);
mOutBufferLength += packetp->getSize();
mSendQueue.push(packetp);
}
}
return status;
}
bool LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host)
{
if (!LLProxy::isSOCKSProxyEnabled())
{
return send_packet(h_socket, send_buffer, buf_size, host.getAddress(), host.getPort());
return send_packet(socket, datap, data_size, host.getAddress(), host.getPort());
}
char headered_send_buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE];
@ -361,11 +92,274 @@ bool LLPacketRing::sendPacketImpl(int h_socket, const char * send_buffer, S32 bu
socks_header->atype = ADDRESS_IPV4;
socks_header->frag = 0;
memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, send_buffer, buf_size);
memcpy(headered_send_buffer + SOCKS_HEADER_SIZE, datap, data_size);
return send_packet( h_socket,
return send_packet( socket,
headered_send_buffer,
buf_size + SOCKS_HEADER_SIZE,
data_size + SOCKS_HEADER_SIZE,
LLProxy::getInstance()->getUDPProxy().getAddress(),
LLProxy::getInstance()->getUDPProxy().getPort());
}
bool LLPacketRing::sendPacket(int socket, const char * datap, S32 data_size, LLHost host)
{
mActualBytesOut += data_size;
return send_packet_helper(socket, datap, data_size, host);
}
void LLPacketRing::dropPackets (U32 num_to_drop)
{
mPacketsToDrop += num_to_drop;
}
void LLPacketRing::setDropPercentage (F32 percent_to_drop)
{
mDropPercentage = percent_to_drop;
}
bool LLPacketRing::computeDrop()
{
bool drop= (mDropPercentage > 0.0f && (ll_frand(100.f) < mDropPercentage));
if (drop)
{
++mPacketsToDrop;
}
if (mPacketsToDrop > 0)
{
--mPacketsToDrop;
drop = true;
}
return drop;
}
S32 LLPacketRing::receiveOrDropPacket(S32 socket, char *datap, bool drop)
{
S32 packet_size = 0;
// pull straight from socket
if (LLProxy::isSOCKSProxyEnabled())
{
char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */
packet_size = receive_packet(socket, buffer);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
}
if (packet_size > SOCKS_HEADER_SIZE)
{
if (drop)
{
packet_size = 0;
}
else
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
memcpy(datap, buffer + SOCKS_HEADER_SIZE, packet_size);
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
mLastSender.setAddress(header->addr);
mLastSender.setPort(ntohs(header->port));
mLastReceivingIF = ::get_receiving_interface();
}
}
else
{
packet_size = 0;
}
}
else
{
packet_size = receive_packet(socket, datap);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
if (drop)
{
packet_size = 0;
}
else
{
mLastSender = ::get_sender();
mLastReceivingIF = ::get_receiving_interface();
}
}
}
return packet_size;
}
S32 LLPacketRing::receiveOrDropBufferedPacket(char *datap, bool drop)
{
assert(mNumBufferedPackets > 0);
S32 packet_size = 0;
S16 ring_size = (S16)(mPacketRing.size());
S16 packet_index = (mHeadIndex + ring_size - mNumBufferedPackets) % ring_size;
LLPacketBuffer* packet = mPacketRing[packet_index];
packet_size = packet->getSize();
mLastSender = packet->getHost();
mLastReceivingIF = packet->getReceivingInterface();
--mNumBufferedPackets;
mNumBufferedBytes -= packet_size;
if (mNumBufferedPackets == 0)
{
assert(mNumBufferedBytes == 0);
}
if (!drop)
{
assert(packet_size > 0);
memcpy(datap, packet->getData(), packet_size);
}
else
{
packet_size = 0;
}
return packet_size;
}
S32 LLPacketRing::bufferInboundPacket(S32 socket)
{
if (mNumBufferedPackets == mPacketRing.size() && mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
expandRing();
}
LLPacketBuffer* packet = mPacketRing[mHeadIndex];
S32 old_packet_size = packet->getSize();
S32 packet_size = 0;
if (LLProxy::isSOCKSProxyEnabled())
{
char buffer[NET_BUFFER_SIZE + SOCKS_HEADER_SIZE]; /* Flawfinder ignore */
packet_size = receive_packet(socket, buffer);
if (packet_size > 0)
{
mActualBytesIn += packet_size;
if (packet_size > SOCKS_HEADER_SIZE)
{
// *FIX We are assuming ATYP is 0x01 (IPv4), not 0x03 (hostname) or 0x04 (IPv6)
proxywrap_t * header = static_cast<proxywrap_t*>(static_cast<void*>(buffer));
LLHost sender;
sender.setAddress(header->addr);
sender.setPort(ntohs(header->port));
packet_size -= SOCKS_HEADER_SIZE; // The unwrapped packet size
packet->init(buffer + SOCKS_HEADER_SIZE, packet_size, sender);
mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size());
if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
++mNumBufferedPackets;
mNumBufferedBytes += packet_size;
}
else
{
// we overwrote an older packet
mNumBufferedBytes += packet_size - old_packet_size;
}
}
else
{
packet_size = 0;
}
}
}
else
{
packet->init(socket);
packet_size = packet->getSize();
if (packet_size > 0)
{
mActualBytesIn += packet_size;
mHeadIndex = (mHeadIndex + 1) % (S16)(mPacketRing.size());
if (mNumBufferedPackets < MAX_BUFFER_RING_SIZE)
{
++mNumBufferedPackets;
mNumBufferedBytes += packet_size;
}
else
{
// we overwrote an older packet
mNumBufferedBytes += packet_size - old_packet_size;
}
}
}
return packet_size;
}
S32 LLPacketRing::drainSocket(S32 socket)
{
// drain into buffer
S32 packet_size = 1;
S32 num_loops = 0;
S32 old_num_packets = mNumBufferedPackets;
while (packet_size > 0)
{
packet_size = bufferInboundPacket(socket);
++num_loops;
}
S32 num_dropped_packets = (num_loops - 1 + old_num_packets) - mNumBufferedPackets;
if (num_dropped_packets > 0)
{
// It will eventually be accounted by mDroppedPackets
// and mPacketsLost, but track it here for logging purposes.
mNumDroppedPackets += num_dropped_packets;
}
return (S32)(mNumBufferedPackets);
}
bool LLPacketRing::expandRing()
{
// compute larger size
constexpr S16 BUFFER_RING_EXPANSION = 256;
S16 old_size = (S16)(mPacketRing.size());
S16 new_size = llmin(old_size + BUFFER_RING_EXPANSION, MAX_BUFFER_RING_SIZE);
if (new_size == old_size)
{
// mPacketRing is already maxed out
return false;
}
// make a larger ring and copy packet pointers
std::vector<LLPacketBuffer*> new_ring(new_size, nullptr);
for (S16 i = 0; i < old_size; ++i)
{
S16 j = (mHeadIndex + i) % old_size;
new_ring[i] = mPacketRing[j];
}
// allocate new packets for the remainder of new_ring
LLHost invalid_host;
for (S16 i = old_size; i < new_size; ++i)
{
new_ring[i] = new LLPacketBuffer(invalid_host, nullptr, 0);
}
// swap the rings and reset mHeadIndex
mPacketRing.swap(new_ring);
mHeadIndex = mNumBufferedPackets;
return true;
}
F32 LLPacketRing::getBufferLoadRate() const
{
// goes up to MAX_BUFFER_RING_SIZE
return (F32)mNumBufferedPackets / (F32)DEFAULT_BUFFER_RING_SIZE;
}
void LLPacketRing::dumpPacketRingStats()
{
mNumDroppedPacketsTotal += mNumDroppedPackets;
LL_INFOS("Messaging") << "Packet ring stats: " << std::endl
<< "Buffered packets: " << mNumBufferedPackets << std::endl
<< "Buffered bytes: " << mNumBufferedBytes << std::endl
<< "Dropped packets current: " << mNumDroppedPackets << std::endl
<< "Dropped packets total: " << mNumDroppedPacketsTotal << std::endl
<< "Dropped packets percentage: " << mDropPercentage << "%" << std::endl
<< "Actual in bytes: " << mActualBytesIn << std::endl
<< "Actual out bytes: " << mActualBytesOut << LL_ENDL;
mNumDroppedPackets = 0;
}

View File

@ -25,16 +25,14 @@
* $/LicenseInfo$
*/
#ifndef LL_LLPACKETRING_H
#define LL_LLPACKETRING_H
#pragma once
#include <queue>
#include <vector>
#include "llhost.h"
#include "llpacketbuffer.h"
#include "llproxy.h"
#include "llthrottle.h"
#include "net.h"
class LLPacketRing
{
@ -42,60 +40,71 @@ public:
LLPacketRing();
~LLPacketRing();
void cleanup();
// receive one packet: either buffered or from the socket
S32 receivePacket (S32 socket, char *datap);
// send one packet
bool sendPacket(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
// drains packets from socket and returns final mNumBufferedPackets
S32 drainSocket(S32 socket);
void dropPackets(U32);
void setDropPercentage (F32 percent_to_drop);
void setUseInThrottle(const bool use_throttle);
void setUseOutThrottle(const bool use_throttle);
void setInBandwidth(const F32 bps);
void setOutBandwidth(const F32 bps);
S32 receivePacket (S32 socket, char *datap);
S32 receiveFromRing (S32 socket, char *datap);
bool sendPacket(int h_socket, char * send_buffer, S32 buf_size, LLHost host);
inline LLHost getLastSender() const;
inline LLHost getLastReceivingInterface() const;
inline LLHost getLastSender();
inline LLHost getLastReceivingInterface();
S32 getActualInBytes() const { return mActualBytesIn; }
S32 getActualOutBytes() const { return mActualBytesOut; }
S32 getAndResetActualInBits() { S32 bits = mActualBytesIn * 8; mActualBytesIn = 0; return bits;}
S32 getAndResetActualOutBits() { S32 bits = mActualBytesOut * 8; mActualBytesOut = 0; return bits;}
S32 getAndResetActualInBits() { S32 bits = mActualBitsIn; mActualBitsIn = 0; return bits;}
S32 getAndResetActualOutBits() { S32 bits = mActualBitsOut; mActualBitsOut = 0; return bits;}
S32 getNumBufferedPackets() const { return (S32)(mNumBufferedPackets); }
S32 getNumBufferedBytes() const { return mNumBufferedBytes; }
S32 getNumDroppedPackets() const { return mNumDroppedPacketsTotal + mNumDroppedPackets; }
F32 getBufferLoadRate() const; // from 0 to 4 (0 - empty, 1 - default size is full)
void dumpPacketRingStats();
protected:
bool mUseInThrottle;
bool mUseOutThrottle;
// returns 'true' if we should intentionally drop a packet
bool computeDrop();
// For simulating a lower-bandwidth connection - BPS
LLThrottle mInThrottle;
LLThrottle mOutThrottle;
// returns packet_size of received packet, zero or less if no packet found
S32 receiveOrDropPacket(S32 socket, char *datap, bool drop);
S32 receiveOrDropBufferedPacket(char *datap, bool drop);
S32 mActualBitsIn;
S32 mActualBitsOut;
S32 mMaxBufferLength; // How much data can we queue up before dropping data.
S32 mInBufferLength; // Current incoming buffer length
S32 mOutBufferLength; // Current outgoing buffer length
// returns packet_size of packet buffered
S32 bufferInboundPacket(S32 socket);
F32 mDropPercentage; // % of packets to drop
U32 mPacketsToDrop; // drop next n packets
// returns 'true' if ring was expanded
bool expandRing();
std::queue<LLPacketBuffer *> mReceiveQueue;
std::queue<LLPacketBuffer *> mSendQueue;
protected:
std::vector<LLPacketBuffer*> mPacketRing;
S16 mHeadIndex { 0 };
S16 mNumBufferedPackets { 0 };
S32 mNumDroppedPackets { 0 };
S32 mNumDroppedPacketsTotal { 0 };
S32 mNumBufferedBytes { 0 };
S32 mActualBytesIn { 0 };
S32 mActualBytesOut { 0 };
F32 mDropPercentage { 0.0f }; // % of inbound packets to drop
U32 mPacketsToDrop { 0 }; // drop next inbound n packets
// These are the sender and receiving_interface for the last packet delivered by receivePacket()
LLHost mLastSender;
LLHost mLastReceivingIF;
private:
bool sendPacketImpl(int h_socket, const char * send_buffer, S32 buf_size, LLHost host);
};
inline LLHost LLPacketRing::getLastSender()
inline LLHost LLPacketRing::getLastSender() const
{
return mLastSender;
}
inline LLHost LLPacketRing::getLastReceivingInterface()
inline LLHost LLPacketRing::getLastReceivingInterface() const
{
return mLastReceivingIF;
}
#endif

View File

@ -465,7 +465,7 @@ void LLProxy::applyProxySettings(CURL* handle)
/**
* @brief Send one TCP packet and receive one in return.
*
* This operation is done synchronously with a 1000ms timeout. Therefore, it should not be used when a blocking
* This operation is done synchronously with a 100ms timeout. Therefore, it should not be used when a blocking
* operation would impact the operation of the viewer.
*
* @param handle_ptr Pointer to a connected LLSocket of type STREAM_TCP.
@ -482,7 +482,7 @@ static apr_status_t tcp_blocking_handshake(LLSocket::ptr_t handle, char * dataou
apr_size_t expected_len = outlen;
handle->setBlocking(1000);
handle->setBlocking(100000); // 100ms, 100000us. Should be sufficient for localhost, nearby network
rv = apr_socket_send(apr_socket, dataout, &outlen);
if (APR_SUCCESS != rv)

View File

@ -656,8 +656,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
// UseCircuitCode is allowed in even from an invalid circuit, so that
// we can toss circuits around.
if(
valid_packet &&
else if (
!cdp &&
(mTemplateMessageReader->getMessageName() !=
_PREHASH_UseCircuitCode))
@ -667,8 +666,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
valid_packet = false;
}
if(
valid_packet &&
if ( valid_packet &&
cdp &&
!cdp->getTrusted() &&
mTemplateMessageReader->isTrusted())
@ -680,7 +678,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
valid_packet = false;
}
if( valid_packet )
if ( valid_packet )
{
logValidMsg(cdp, host, recv_reliable, recv_resent, acks>0 );
valid_packet = mTemplateMessageReader->readMessage(buffer, host);
@ -726,6 +724,7 @@ bool LLMessageSystem::checkMessages(LockMessageChecker&, S64 frame_count )
// Check to see if we need to print debug info
if ((mt_sec - mCircuitPrintTime) > mCircuitPrintFreq)
{
mPacketRing.dumpPacketRingStats();
dumpCircuitInfo();
mCircuitPrintTime = mt_sec;
}
@ -821,6 +820,11 @@ void LLMessageSystem::processAcks(LockMessageChecker&, F32 collect_time)
}
}
S32 LLMessageSystem::drainUdpSocket()
{
return mPacketRing.drainSocket(mSocket);
}
void LLMessageSystem::copyMessageReceivedToSend()
{
// NOTE: babbage: switch builder to match reader to avoid

View File

@ -417,6 +417,9 @@ public:
bool checkMessages(LockMessageChecker&, S64 frame_count = 0 );
void processAcks(LockMessageChecker&, F32 collect_time = 0.f);
// returns total number of buffered packets after the drain
S32 drainUdpSocket();
bool isMessageFast(const char *msg);
bool isMessage(const char *msg)
{
@ -535,7 +538,6 @@ public:
//void buildMessage();
S32 zeroCode(U8 **data, S32 *data_size);
S32 zeroCodeExpand(U8 **data, S32 *data_size);
S32 zeroCodeAdjustCurrentSendTotal();
@ -752,6 +754,7 @@ public:
S32 getReceiveBytes() const;
S32 getUnackedListSize() const { return mUnackedListSize; }
F32 getBufferLoadRate() const { return mPacketRing.getBufferLoadRate(); }
//const char* getCurrentSMessageName() const { return mCurrentSMessageName; }
//const char* getCurrentSBlockName() const { return mCurrentSBlockName; }
@ -839,12 +842,10 @@ private:
LLUUID mSessionID;
void addTemplate(LLMessageTemplate *templatep);
bool decodeTemplate( const U8* buffer, S32 buffer_size, LLMessageTemplate** msg_template );
void logMsgFromInvalidCircuit( const LLHost& sender, bool recv_reliable );
void logTrustedMsgFromUntrustedCircuit( const LLHost& sender );
void logValidMsg(LLCircuitData *cdp, const LLHost& sender, bool recv_reliable, bool recv_resent, bool recv_acks );
void logRanOffEndOfPacket( const LLHost& sender );
class LLMessageCountInfo
{

View File

@ -76,14 +76,8 @@ static U32 gsnReceivingIFAddr = INVALID_HOST_IP_ADDRESS; // Address to which dat
const char* LOOPBACK_ADDRESS_STRING = "127.0.0.1";
const char* BROADCAST_ADDRESS_STRING = "255.255.255.255";
#if LL_DARWIN
// macOS returns an error when trying to set these to 400000. Smaller values succeed.
const int SEND_BUFFER_SIZE = 200000;
const int RECEIVE_BUFFER_SIZE = 200000;
#else // LL_DARWIN
const int SEND_BUFFER_SIZE = 400000;
const int RECEIVE_BUFFER_SIZE = 400000;
#endif // LL_DARWIN
const int SEND_BUFFER_SIZE = 200000;
const int RECEIVE_BUFFER_SIZE = 800000;
// universal functions (cross-platform)

View File

@ -400,9 +400,14 @@ void LLPluginProcessParent::idle(void)
apr_sockaddr_t* addr = NULL;
mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP);
mBoundPort = 0;
if (!mListenSocket)
{
killSockets();
errorState();
break;
}
// This code is based on parts of LLSocket::create() in lliosocket.cpp.
status = apr_sockaddr_info_get(
&addr,
"127.0.0.1",

View File

@ -105,6 +105,36 @@ LLCubeMapArray::LLCubeMapArray()
}
LLCubeMapArray::LLCubeMapArray(LLCubeMapArray& lhs, U32 width, U32 count) : mTextureStage(0)
{
mWidth = width;
mCount = count;
// Allocate a new cubemap array with the same criteria as the incoming cubemap array
allocate(mWidth, lhs.mImage->getComponents(), count, lhs.mImage->getUseMipMaps(), lhs.mHDR);
// Copy each cubemap from the incoming array to the new array
U32 min_count = std::min(count, lhs.mCount);
for (U32 i = 0; i < min_count * 6; ++i)
{
U32 src_resolution = lhs.mWidth;
U32 dst_resolution = mWidth;
{
GLint components = GL_RGB;
if (mImage->getComponents() == 4)
components = GL_RGBA;
GLint format = GL_RGB;
// Handle different resolutions by scaling the image
LLPointer<LLImageRaw> src_image = new LLImageRaw(lhs.mWidth, lhs.mWidth, lhs.mImage->getComponents());
glGetTexImage(GL_TEXTURE_CUBE_MAP_ARRAY, 0, components, GL_UNSIGNED_BYTE, src_image->getData());
LLPointer<LLImageRaw> scaled_image = src_image->scaled(mWidth, mWidth);
glTexSubImage3D(GL_TEXTURE_CUBE_MAP_ARRAY, 0, 0, 0, i, mWidth, mWidth, 1, components, GL_UNSIGNED_BYTE, scaled_image->getData());
}
}
}
LLCubeMapArray::~LLCubeMapArray()
{
}
@ -115,6 +145,8 @@ void LLCubeMapArray::allocate(U32 resolution, U32 components, U32 count, bool us
mWidth = resolution;
mCount = count;
mHDR = hdr;
LLImageGL::generateTextures(1, &texname);
mImage = new LLImageGL(resolution, resolution, components, use_mips);

View File

@ -36,6 +36,7 @@ class LLCubeMapArray : public LLRefCount
{
public:
LLCubeMapArray();
LLCubeMapArray(LLCubeMapArray& lhs, U32 width, U32 count);
static GLenum sTargets[6];
@ -73,4 +74,5 @@ protected:
U32 mWidth = 0;
U32 mCount = 0;
S32 mTextureStage;
bool mHDR;
};

View File

@ -725,11 +725,11 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, ll
|| FT_Err_Invalid_Composite == error
|| (FT_Err_Ok != error && LLStringOps::isEmoji(wch)))
{
glyph_index = FT_Get_Char_Index(mFTFace, '?');
// if '?' is not present, potentially can use last index, that's supposed to be null glyph
if (glyph_index > 0)
// value~0 always corresponds to the 'missing glyph'
error = FT_Load_Glyph(mFTFace, 0, FT_LOAD_FORCE_AUTOHINT);
if (FT_Err_Ok != error)
{
error = FT_Load_Glyph(mFTFace, glyph_index, load_flags ^ FT_LOAD_COLOR);
LL_ERRS() << "Loading fallback for char '" << (U32)wch << "', glyph " << glyph_index << " failed with error : " << (S32)error << LL_ENDL;
}
}
llassert_always_msg(FT_Err_Ok == error, message.c_str());

View File

@ -2458,12 +2458,15 @@ void LLGLState::checkStates(GLboolean writeAlpha)
return;
}
GLint src;
GLint dst;
glGetIntegerv(GL_BLEND_SRC, &src);
glGetIntegerv(GL_BLEND_DST, &dst);
llassert_always(src == GL_SRC_ALPHA);
llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA);
GLint srcRGB, dstRGB, srcAlpha, dstAlpha;
glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB);
glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB);
glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcAlpha);
glGetIntegerv(GL_BLEND_DST_ALPHA, &dstAlpha);
llassert_always(srcRGB == GL_SRC_ALPHA);
llassert_always(srcAlpha == GL_SRC_ALPHA);
llassert_always(dstRGB == GL_ONE_MINUS_SRC_ALPHA);
llassert_always(dstAlpha == GL_ONE_MINUS_SRC_ALPHA);
// disable for now until usage is consistent
//GLboolean colorMask[4];

View File

@ -837,7 +837,7 @@ void LLButton::draw()
// Highlight if needed
if( ll::ui::SearchableControl::getHighlighted() )
label_color = ll::ui::SearchableControl::getHighlightColor();
label_color = ll::ui::SearchableControl::getHighlightFontColor();
// overlay with keyboard focus border
if (hasFocus())

View File

@ -170,12 +170,14 @@ bool LLCommandManager::load()
if (!parser.readXUI(commands_file, commandsParams))
{
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Unable to load xml file: " << commands_file << LL_ENDL;
return false;
}
if (!commandsParams.validateBlock())
{
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Invalid commands file: " << commands_file << LL_ENDL;
return false;
}

View File

@ -23,7 +23,7 @@
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "../newview/llviewerprecompiledheaders.h"
#include "linden_common.h"
#include "llflashtimer.h"

View File

@ -508,7 +508,7 @@ void LLMenuItemGL::draw( void )
// Highlight if needed
if( ll::ui::SearchableControl::getHighlighted() )
color = ll::ui::SearchableControl::getHighlightColor();
color = ll::ui::SearchableControl::getHighlightFontColor();
// Draw the text on top.
if (mBriefItem)

View File

@ -614,6 +614,13 @@ void LLNotification::cancel()
LLSD LLNotification::getResponseTemplate(EResponseTemplateType type)
{
LLSD response = LLSD::emptyMap();
if (!mForm)
{
LL_WARNS("Notifications") << "Null form when getting response template for notification " << getName() << LL_ENDL;
return response;
}
for (S32 element_idx = 0;
element_idx < mForm->getNumElements();
++element_idx)
@ -1249,9 +1256,26 @@ LLNotifications::LLNotifications()
LLInstanceTracker<LLNotificationChannel, std::string>::instanceCount();
}
LLNotifications::~LLNotifications()
{
// Clear explicitly, something in ~LLNotifications() crashes so narrowing down suspects
pHistoryChannel = nullptr;
pExpirationChannel = nullptr;
mGlobalStrings.clear();
mTemplates.clear();
mVisibilityRules.clear();
mUniqueNotifications.clear();
mListener = nullptr;
}
void LLNotifications::clear()
{
mDefaultChannels.clear();
mDefaultChannels.clear();
// At this point mTemplates still gets used by lingering notifications
// to do responses (ex: group notice will call forceResponse()), but
// since network should be down and everything save, it's questionable
// whether it should stay that way
}
// The expiration channel gets all notifications that are cancelled
@ -1464,6 +1488,13 @@ bool LLNotifications::templateExists(std::string_view name)
void LLNotifications::forceResponse(const LLNotification::Params& params, S32 option)
{
LLNotificationPtr temp_notify(new LLNotification(params));
if (!temp_notify->getForm())
{
LL_WARNS("Notifications") << "Cannot force response for notification with null form: " << (std::string)params.name << LL_ENDL;
return;
}
LLSD response = temp_notify->getResponseTemplate();
LLSD selected_item = temp_notify->getForm()->getElement(option);

View File

@ -887,7 +887,7 @@ class LLNotifications :
{
LLSINGLETON(LLNotifications);
LOG_CLASS(LLNotifications);
virtual ~LLNotifications() {}
virtual ~LLNotifications();
public:

View File

@ -3394,7 +3394,7 @@ bool LLScrollListCtrl::highlightMatchingItems(const std::string& filter_str)
bool res = false;
setHighlightedColor(LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red));
setHighlightedColor(LLUIColorTable::instance().getColor("SearchableControlHighlightBgColor", LLColor4::red4));
std::string filter_str_lc(filter_str);
LLStringUtil::toLower(filter_str_lc);

View File

@ -43,9 +43,15 @@ namespace ll
virtual ~SearchableControl()
{ }
const LLColor4& getHighlightColor( ) const
const LLColor4& getHighlightBgColor( ) const
{
static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightColor", LLColor4::red);
static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightBgColor", LLColor4::red4);
return highlight_color.get();
}
const LLColor4& getHighlightFontColor() const
{
static LLUIColor highlight_color = LLUIColorTable::instance().getColor("SearchableControlHighlightFontColor", LLColor4::red4);
return highlight_color.get();
}

View File

@ -1378,7 +1378,7 @@ void LLTextBase::draw()
// Draw highlighted if needed
if( ll::ui::SearchableControl::getHighlighted() )
{
const LLColor4& bg_color = ll::ui::SearchableControl::getHighlightColor();
const LLColor4& bg_color = ll::ui::SearchableControl::getHighlightBgColor();
LLRect bg_rect = mVisibleTextRect;
if( mScroller )
bg_rect.intersectWith( text_rect );

View File

@ -76,6 +76,12 @@ protected:
LLUIString mText;
callback_t mClickedCallback;
bool mShowCursorHand;
protected:
virtual std::string _getSearchText() const
{
return LLTextBase::_getSearchText() + mText.getString();
}
};
// Build time optimization, generate once in .cpp file

View File

@ -209,8 +209,15 @@ public:
}
virtual bool execute( LLTextBase* editor, S32* delta )
{
mWString = editor->getWText().substr(getPosition(), mLen);
*delta = remove(editor, getPosition(), mLen );
try
{
mWString = editor->getWText().substr(getPosition(), mLen);
*delta = remove(editor, getPosition(), mLen);
}
catch (std::out_of_range&)
{
return false;
}
return (*delta != 0);
}
virtual S32 undo( LLTextBase* editor )

View File

@ -31,8 +31,6 @@
#include "llrect.h"
#include "llcoord.h"
#include "llcontrol.h"
#include "llcoord.h"
#include "llcontrol.h"
#include "llinitparam.h"
#include "llregistry.h"
#include "llrender2dutils.h"

View File

@ -279,6 +279,10 @@ void callResetKeys()
bool callUnicodeCallback(wchar_t character, unsigned int mask)
{
if (!gWindowImplementation)
{
return false;
}
NativeKeyEventData eventData;
memset(&eventData, 0, sizeof(NativeKeyEventData));
@ -300,7 +304,7 @@ bool callUnicodeCallback(wchar_t character, unsigned int mask)
void callFocus()
{
if (gWindowImplementation)
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
gWindowImplementation->getCallbacks()->handleFocus(gWindowImplementation);
}
@ -308,7 +312,7 @@ void callFocus()
void callFocusLost()
{
if (gWindowImplementation)
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
gWindowImplementation->getCallbacks()->handleFocusLost(gWindowImplementation);
}
@ -316,6 +320,10 @@ void callFocusLost()
void callRightMouseDown(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -329,6 +337,10 @@ void callRightMouseDown(float *pos, MASK mask)
void callRightMouseUp(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -342,6 +354,10 @@ void callRightMouseUp(float *pos, MASK mask)
void callLeftMouseDown(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -355,6 +371,10 @@ void callLeftMouseDown(float *pos, MASK mask)
void callLeftMouseUp(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -369,6 +389,10 @@ void callLeftMouseUp(float *pos, MASK mask)
void callDoubleClick(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
if (gWindowImplementation->allowsLanguageInput())
{
gWindowImplementation->interruptLanguageTextInput();
@ -382,7 +406,7 @@ void callDoubleClick(float *pos, MASK mask)
void callResize(unsigned int width, unsigned int height)
{
if (gWindowImplementation != NULL)
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
gWindowImplementation->getCallbacks()->handleResize(gWindowImplementation, width, height);
}
@ -390,6 +414,10 @@ void callResize(unsigned int width, unsigned int height)
void callMouseMoved(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
LLCoordGL outCoords;
outCoords.mX = ll_round(pos[0]);
outCoords.mY = ll_round(pos[1]);
@ -403,6 +431,10 @@ void callMouseMoved(float *pos, MASK mask)
void callMouseDragged(float *pos, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
LLCoordGL outCoords;
outCoords.mX = ll_round(pos[0]);
outCoords.mY = ll_round(pos[1]);
@ -424,6 +456,10 @@ void callScrollMoved(float deltaX, float deltaY)
void callMouseExit()
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->getCallbacks()->handleMouseLeave(gWindowImplementation);
}
@ -475,11 +511,19 @@ void callWindowDidChangeScreen()
void callDeltaUpdate(float *delta, MASK mask)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->updateMouseDeltas(delta);
}
void callOtherMouseDown(float *pos, MASK mask, int button)
{
if (!gWindowImplementation)
{
return;
}
LLCoordGL outCoords;
outCoords.mX = ll_round(pos[0]);
outCoords.mY = ll_round(pos[1]);
@ -500,6 +544,10 @@ void callOtherMouseDown(float *pos, MASK mask, int button)
void callOtherMouseUp(float *pos, MASK mask, int button)
{
if (!gWindowImplementation)
{
return;
}
LLCoordGL outCoords;
outCoords.mX = ll_round(pos[0]);
outCoords.mY = ll_round(pos[1]);
@ -524,27 +572,43 @@ void callModifier(MASK mask)
void callHandleDragEntered(std::string url)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_START_TRACKING);
}
void callHandleDragExited(std::string url)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_STOP_TRACKING);
}
void callHandleDragUpdated(std::string url)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_TRACK);
}
void callHandleDragDropped(std::string url)
{
if (!gWindowImplementation)
{
return;
}
gWindowImplementation->handleDragNDrop(url, LLWindowCallbacks::DNDA_DROPPED);
}
void callQuitHandler()
{
if (gWindowImplementation)
if (gWindowImplementation && gWindowImplementation->getCallbacks())
{
if(gWindowImplementation->getCallbacks()->handleCloseRequest(gWindowImplementation))
{
@ -555,7 +619,7 @@ void callQuitHandler()
void getPreeditSelectionRange(int *position, int *length)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->getSelectionRange(position, length);
}
@ -563,7 +627,7 @@ void getPreeditSelectionRange(int *position, int *length)
void getPreeditMarkedRange(int *position, int *length)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->getPreeditRange(position, length);
}
@ -571,7 +635,7 @@ void getPreeditMarkedRange(int *position, int *length)
void setPreeditMarkedRange(int position, int length)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->markAsPreedit(position, length);
}
@ -580,7 +644,7 @@ void setPreeditMarkedRange(int position, int length)
bool handleUnicodeCharacter(wchar_t c)
{
bool success = false;
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
success = gWindowImplementation->getPreeditor()->handleUnicodeCharHere(c);
}
@ -590,7 +654,7 @@ bool handleUnicodeCharacter(wchar_t c)
void resetPreedit()
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
gWindowImplementation->getPreeditor()->resetPreedit();
}
@ -600,7 +664,7 @@ void resetPreedit()
// This largely mirrors the old implementation, only sans the carbon parameters.
void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigned int *replacementRange, long text_len, attributedStringInfo segments)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
LLPreeditor *preeditor = gWindowImplementation->getPreeditor();
preeditor->resetPreedit();
@ -623,7 +687,7 @@ void setMarkedText(unsigned short *unitext, unsigned int *selectedRange, unsigne
void getPreeditLocation(float *location, unsigned int length)
{
if (gWindowImplementation->getPreeditor())
if (gWindowImplementation && gWindowImplementation->getPreeditor())
{
LLPreeditor *preeditor = gWindowImplementation->getPreeditor();
LLCoordGL coord;

View File

@ -4040,7 +4040,15 @@ void LLWindowWin32::fillCompositionLogfont(LOGFONT *logfont)
break;
}
logfont->lfHeight = mPreeditor->getPreeditFontSize();
if (mPreeditor)
{
logfont->lfHeight = mPreeditor->getPreeditFontSize();
}
else
{
// todo: extract from some font * LLUI::getScaleFactor() intead
logfont->lfHeight = 10;
}
logfont->lfWeight = FW_NORMAL;
}

View File

@ -306,6 +306,7 @@ void LLXMLNode::addChild(LLXMLNodePtr& new_child)
// virtual
LLXMLNodePtr LLXMLNode::createChild(const char* name, bool is_attribute)
{
// Todo: validate to make sure node name is valid? (no spaces, etc)
return createChild(gStringTable.addStringEntry(name), is_attribute);
}

View File

@ -108,12 +108,15 @@ LLXmlTreeNode::LLXmlTreeNode( const std::string& name, LLXmlTreeNode* parent, LL
LLXmlTreeNode::~LLXmlTreeNode()
{
attribute_map_t::iterator iter;
for (iter=mAttributes.begin(); iter != mAttributes.end(); iter++)
delete iter->second;
for(LLXmlTreeNode* node : mChildren)
for (auto& attr : mAttributes)
{
delete node;
delete attr.second;
}
mAttributes.clear();
for (auto& child : mChildren)
{
delete child;
}
mChildren.clear();
}

View File

@ -291,6 +291,7 @@ set(viewer_SOURCE_FILES
llfloatersettingscolor.cpp
llfloatersettingsdebug.cpp
llfloatersidepanelcontainer.cpp
llfloaterslapptest.cpp
llfloatersnapshot.cpp
llfloatersounddevices.cpp
llfloaterspellchecksettings.cpp
@ -962,6 +963,7 @@ set(viewer_HEADER_FILES
llfloatersettingscolor.h
llfloatersettingsdebug.h
llfloatersidepanelcontainer.h
llfloaterslapptest.h
llfloatersnapshot.h
llfloatersounddevices.h
llfloaterspellchecksettings.h
@ -1417,11 +1419,24 @@ if (DARWIN)
LIST(APPEND viewer_SOURCE_FILES llfilepicker_mac.mm)
LIST(APPEND viewer_HEADER_FILES llfilepicker_mac.h)
set_source_files_properties(
llappviewermacosx-objc.mm
PROPERTIES
SKIP_PRECOMPILE_HEADERS TRUE
)
set_source_files_properties(
llfilepicker_mac.mm
PROPERTIES
SKIP_PRECOMPILE_HEADERS TRUE
)
# This should be compiled with the viewer.
LIST(APPEND viewer_SOURCE_FILES llappdelegate-objc.mm)
set_source_files_properties(
llappdelegate-objc.mm
PROPERTIES
SKIP_PRECOMPILE_HEADERS TRUE
COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}"
# BugsplatMac is a module, imported with @import. That language feature
# demands these -f switches.
@ -1705,6 +1720,10 @@ list(APPEND EVENT_HOST_SCRIPTS ${EVENT_HOST_SCRIPT_GLOB_LIST})
set(PACKAGE ON CACHE BOOL
"Add a package target that builds an installer package.")
if(USE_PRECOMPILED_HEADERS)
target_precompile_headers( ${VIEWER_BINARY_NAME} PRIVATE llviewerprecompiledheaders.h )
endif(USE_PRECOMPILED_HEADERS)
if (WINDOWS)
set_target_properties(${VIEWER_BINARY_NAME}
PROPERTIES
@ -1715,10 +1734,6 @@ if (WINDOWS)
)
target_compile_options(${VIEWER_BINARY_NAME} PRIVATE /bigobj)
if(USE_PRECOMPILED_HEADERS)
target_precompile_headers( ${VIEWER_BINARY_NAME} PRIVATE llviewerprecompiledheaders.h )
endif(USE_PRECOMPILED_HEADERS)
# If adding a file to viewer_manifest.py in the WindowsManifest.construct() method, be sure to add the dependency
# here.
# *NOTE:Mani - This is a crappy hack to have important dependencies for the viewer_manifest copy action

View File

@ -1 +1 @@
7.1.12
7.1.13

View File

@ -3676,6 +3676,17 @@
<key>Value</key>
<integer>5000</integer>
</map>
<key>InventoryExposeFolderID</key>
<map>
<key>Comment</key>
<string>Allows copying folder id from context menu</string>
<key>Persist</key>
<integer>0</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>0</integer>
</map>
<key>MarketplaceListingsSortOrder</key>
<map>
<key>Comment</key>
@ -7794,6 +7805,17 @@
<key>Value</key>
<integer>0</integer>
</map>
<key>RenderTextureVRAMDivisor</key>
<map>
<key>Comment</key>
<string>Divisor for maximum amount of VRAM the viewer will use for textures. 1 = all the VRAM. Used in conjunction with RenderMaxVRAMBudget.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>RenderMinFreeMainMemoryThreshold</key>
<map>
<key>Comment</key>
@ -9065,6 +9087,28 @@
<key>Value</key>
<integer>1</integer>
</map>
<key>RenderReflectionProbeDynamicAllocation</key>
<map>
<key>Comment</key>
<string>Enable dynamic allocation of reflection probes. -1 means no dynamic allocation. Sets a buffer to allocate when a dynamic allocation occurs otherwise.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>S32</string>
<key>Value</key>
<integer>-1</integer>
</map>
<key>RenderReflectionProbeCount</key>
<map>
<key>Comment</key>
<string>Number of probes to render. Maximum of 256. Clamps to the nearest power of 2.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>256</integer>
</map>
<key>RenderReflectionProbeResolution</key>
<map>
<key>Comment</key>
@ -11618,7 +11662,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
<real>0.04</real>
<real>0.0095</real>
</map>
<key>TextureScaleMaxAreaFactor</key>
<map>

View File

@ -80,6 +80,18 @@ vec3 atmosFragLightingLinear(vec3 light, vec3 additive, vec3 atten);
vec4 decodeNormal(vec4 norm);
vec3 clampHDRRange(vec3 color)
{
// Why do this?
// There are situations where the color range will go to something insane - potentially producing infs and NaNs even.
// This is a safety measure to prevent that.
// As to the specific number there - allegedly some HDR displays expect values to be in the 0-11.2 range. Citation needed.
// -Geenz 2025-03-05
color = mix(color, vec3(1), isinf(color));
color = mix(color, vec3(0.0), isnan(color));
return clamp(color, vec3(0.0), vec3(11.2));
}
float calcLegacyDistanceAttenuation(float distance, float falloff)
{
float dist_atten = 1.0 - clamp((distance + falloff)/(1.0 + falloff), 0.0, 1.0);

View File

@ -69,6 +69,8 @@ void dofSampleNear(inout vec4 diff, inout float w, float min_sc, vec2 tc)
w += wg;
}
vec3 clampHDRRange(vec3 color);
void main()
{
vec2 tc = vary_fragcoord.xy;
@ -120,5 +122,6 @@ void main()
diff /= w;
}
diff.rgb = clampHDRRange(diff.rgb);
frag_color = diff;
}

View File

@ -43,6 +43,8 @@ vec3 legacyGamma(vec3 color)
return c;
}
vec3 clampHDRRange(vec3 color);
void main()
{
//this is the one of the rare spots where diffuseRect contains linear color values (not sRGB)
@ -53,6 +55,7 @@ void main()
diff.rgb = legacyGamma(diff.rgb);
#endif
frag_color = max(diff, vec4(0));
diff.rgb = clampHDRRange(diff.rgb);
frag_color = diff;
}

View File

@ -71,6 +71,7 @@ float noise(vec2 x) {
//=============================
vec3 clampHDRRange(vec3 color);
void main()
@ -84,6 +85,7 @@ void main()
diff.rgb += nz*0.003;
#endif
diff.rgb = clampHDRRange(diff.rgb);
frag_color = diff;
gl_FragDepth = texture(depthMap, vary_fragcoord.xy).r;

View File

@ -34,6 +34,8 @@ in vec2 vary_fragcoord;
vec3 linear_to_srgb(vec3 cl);
vec3 toneMap(vec3 color);
vec3 clampHDRRange(vec3 color);
void main()
{
//this is the one of the rare spots where diffuseRect contains linear color values (not sRGB)
@ -45,6 +47,7 @@ void main()
diff.rgb = clamp(diff.rgb, vec3(0.0), vec3(1.0));
#endif
diff.rgb = clampHDRRange(diff.rgb);
//debugExposure(diff.rgb);
frag_color = max(diff, vec4(0));
}

View File

@ -154,6 +154,7 @@ void calcAtmosphericVarsLinear(vec3 inPositionEye, vec3 norm, vec3 light_dir, ou
if (classic_mode < 1)
{
amblit = srgb_to_linear(amblit);
amblit = vec3(dot(amblit, vec3(0.2126, 0.7152, 0.0722)));
sunlit = srgb_to_linear(sunlit);
}

View File

@ -104,6 +104,7 @@ vec3 pbrBaseLight(vec3 diffuseColor,
vec3 atten);
GBufferInfo getGBuffer(vec2 screenpos);
vec3 clampHDRRange(vec3 color);
void adjustIrradiance(inout vec3 irradiance, float ambocc)
{
@ -278,6 +279,7 @@ void main()
float final_scale = 1;
if (classic_mode > 0)
final_scale = 1.1;
frag_color.rgb = max(color.rgb * final_scale, vec3(0)); //output linear since local lights will be added to this shader's results
frag_color.rgb = clampHDRRange(color.rgb * final_scale); //output linear since local lights will be added to this shader's results
frag_color.a = 0.0;
}

View File

@ -263,7 +263,12 @@ void main()
vec3 refPos = getPositionWithNDC(vec3(distort*2.0-vec2(1.0), depth*2.0-1.0));
// Calculate some distance fade in the water to better assist with refraction blending and reducing the refraction texture's "disconnect".
fade = max(0,min(1, (pos.z - refPos.z) / 10)) * water_mask;
#ifdef SHORELINE_FADE
fade = max(0,min(1, (pos.z - refPos.z) / 10));
#else
fade = 1;
#endif
fade *= water_mask;
distort2 = mix(distort, distort2, min(1, fade * 10));
depth = texture(depthMap, distort2).r;

View File

@ -1,4 +1,4 @@
version 73
version 74
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@ -86,6 +86,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Low Graphics Settings
@ -128,6 +129,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 512
RenderReflectionProbeCount 1 1
//
// Medium Low Graphics Settings
@ -170,6 +172,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 1024
RenderReflectionProbeCount 1 32
//
// Medium Graphics Settings (standard)
@ -211,6 +214,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// Medium High Graphics Settings
@ -241,7 +245,7 @@ RenderFSAASamples 1 1
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 2
RenderReflectionProbeLevel 1 1
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 6
@ -252,6 +256,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// High Graphics Settings (SSAO + sun shadows)
@ -282,7 +287,7 @@ RenderFSAASamples 1 2
RenderReflectionsEnabled 1 1
RenderReflectionProbeDetail 1 1
RenderScreenSpaceReflections 1 0
RenderReflectionProbeLevel 1 3
RenderReflectionProbeLevel 1 2
RenderMirrors 1 0
RenderHeroProbeResolution 1 512
RenderHeroProbeDistance 1 8
@ -293,6 +298,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 128
//
// High Ultra Graphics Settings (deferred + SSAO + all shadows)
@ -334,6 +340,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Ultra graphics (REALLY PURTY!)
@ -375,6 +382,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Class Unknown Hardware (unknown)
@ -408,6 +416,7 @@ RenderReflectionProbeDetail 0 -1
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 0 0
list Intel
RenderAnisotropic 1 0
@ -429,6 +438,7 @@ RenderMirrors 0 0
RenderGLMultiThreadedTextures 0 0
RenderGLMultiThreadedMedia 0 0
RenderDisableVintageMode 1 0
RenderReflectionProbeCount 0 0
list TexUnit16orLess
RenderTerrainPBRDetail 1 -1

View File

@ -1,4 +1,4 @@
version 72
version 73
// The version number above should be incremented IF AND ONLY IF some
// change has been made that is sufficiently important to justify
// resetting the graphics preferences of all users to the recommended
@ -86,6 +86,7 @@ RenderTonemapMix 1 1
RenderDisableVintageMode 1 1
RenderDownScaleMethod 1 0
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Low Graphics Settings
@ -128,6 +129,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 512
RenderReflectionProbeCount 1 1
//
// Medium Low Graphics Settings
@ -170,6 +172,7 @@ RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 1024
RenderReflectionProbeCount 1 32
//
// Medium Graphics Settings (standard)
@ -211,6 +214,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// Medium High Graphics Settings
@ -252,6 +256,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 64
//
// High Graphics Settings (SSAO + sun shadows)
@ -293,6 +298,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 128
//
// High Ultra Graphics Settings (SSAO + all shadows)
@ -334,6 +340,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Ultra graphics (REALLY PURTY!)
@ -375,6 +382,7 @@ RenderExposure 1 1
RenderTonemapType 1 1
RenderTonemapMix 1 0.7
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 1 256
//
// Class Unknown Hardware (unknown)
@ -407,6 +415,7 @@ RenderShadowDetail 0 0
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderMaxTextureResolution 1 2048
RenderReflectionProbeCount 0 0
list TexUnit8orLess
RenderDeferredSSAO 0 0
@ -447,6 +456,7 @@ RenderReflectionProbeDetail 0 0
RenderReflectionsEnabled 0 0
RenderMirrors 0 0
RenderDisableVintageMode 1 0
RenderReflectionProbeCount 0 0
list VaryingVectors16orLess
RenderTerrainPBRPlanarSampleCount 1 1

View File

@ -26,8 +26,6 @@
* $/LicenseInfo$
*/
#define GLM_ENABLE_EXPERIMENTAL 1
#include "glm/vec2.hpp"
#include "glm/vec3.hpp"
#include "glm/vec4.hpp"

View File

@ -69,9 +69,16 @@ void GLTFSceneManager::load()
{
return;
}
if (filenames.size() > 0)
try
{
GLTFSceneManager::instance().load(filenames[0]);
if (filenames.size() > 0)
{
GLTFSceneManager::instance().load(filenames[0]);
}
}
catch (std::bad_alloc&)
{
LLNotificationsUtil::add("CannotOpenFileTooBig");
}
},
LLFilePicker::FFLOAD_GLTF,

View File

@ -2502,7 +2502,10 @@ void LLAgent::endAnimationUpdateUI()
gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
}
gFloaterTools->dirty();
if (gFloaterTools)
{
gFloaterTools->dirty();
}
// Don't let this be called more than once if the camera
// mode hasn't changed. --JC
@ -4318,9 +4321,14 @@ void LLAgent::teleportViaLandmark(const LLUUID& landmark_asset_id)
void LLAgent::doTeleportViaLandmark(const LLUUID& landmark_asset_id)
{
bool is_local(false);
LLViewerRegion* regionp = getRegion();
LLViewerRegion* regionp = getRegion();
if (!regionp)
{
LL_WARNS("Teleport") << "called when agent region is null" << LL_ENDL;
return;
}
bool is_local(false);
if (LLLandmark* landmark = gLandmarkList.getAsset(landmark_asset_id, NULL))
{
LLVector3d pos_global;

View File

@ -1385,8 +1385,6 @@ void AISUpdate::parseCategory(const LLSD& category_map, S32 depth)
&& curr_cat->getVersion() > LLViewerInventoryCategory::VERSION_UNKNOWN
&& version > curr_cat->getVersion())
{
// Potentially should new_cat->setVersion(unknown) here,
// but might be waiting for a callback that would increment
LL_DEBUGS("Inventory") << "Category " << category_id
<< " is stale. Known version: " << curr_cat->getVersion()
<< " server version: " << version << LL_ENDL;

View File

@ -301,7 +301,8 @@ struct AttachmentInfo
AttachmentInfo(metadata.logFilePathname, "text/plain"),
AttachmentInfo(metadata.userSettingsPathname, "text/xml"),
AttachmentInfo(metadata.accountSettingsPathname, "text/xml"),
AttachmentInfo(metadata.staticDebugPathname, "text/xml")
AttachmentInfo(metadata.staticDebugPathname, "text/xml"),
AttachmentInfo(metadata.attributesPathname, "text/xml")
};
secondLogPath = metadata.secondLogFilePathname;

View File

@ -4722,48 +4722,64 @@ void wear_multiple(const uuid_vec_t& ids, bool replace)
LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, replace, cb);
}
// SLapp for easy-wearing of a stock (library) avatar
//
bool wear_category(const LLSD& query_map, bool append)
{
LLUUID folder_uuid;
if (query_map.has("folder_name"))
{
std::string outfit_folder_name = query_map["folder_name"];
folder_uuid = findDescendentCategoryIDByName(gInventory.getLibraryRootFolderID(), outfit_folder_name);
if (folder_uuid.isNull())
LL_WARNS() << "Couldn't find " << std::quoted(outfit_folder_name) << " in the Library" << LL_ENDL;
}
if (folder_uuid.isNull() && query_map.has("folder_id"))
{
folder_uuid = query_map["folder_id"].asUUID();
}
if (folder_uuid.notNull())
{
if (LLViewerInventoryCategory* cat = gInventory.getCategory(folder_uuid))
{
if (bool is_library = gInventory.isObjectDescendentOf(folder_uuid, gInventory.getRootFolderID()))
{
LLPointer<LLInventoryCategory> new_category = new LLInventoryCategory(folder_uuid, LLUUID::null, LLFolderType::FT_CLOTHING, "Quick Appearance");
LLAppearanceMgr::getInstance()->wearInventoryCategory(new_category, true, append);
}
else
{
LLAppearanceMgr::getInstance()->wearInventoryCategory(cat, true, append);
}
return true;
}
else
{
LL_WARNS() << "Couldn't find folder id" << folder_uuid << " in Inventory" << LL_ENDL;
}
}
return false;
}
class LLWearFolderHandler : public LLCommandHandler
{
public:
// not allowed from outside the app
LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) { }
LLWearFolderHandler() : LLCommandHandler("wear_folder", UNTRUSTED_BLOCK) {}
bool handle(const LLSD& tokens,
const LLSD& query_map,
const std::string& grid,
LLMediaCtrl* web)
{
LLSD::UUID folder_uuid;
if (folder_uuid.isNull() && query_map.has("folder_name"))
if (wear_category(query_map, false))
{
std::string outfit_folder_name = query_map["folder_name"];
folder_uuid = findDescendentCategoryIDByName(
gInventory.getLibraryRootFolderID(),
outfit_folder_name);
}
if (folder_uuid.isNull() && query_map.has("folder_id"))
{
folder_uuid = query_map["folder_id"].asUUID();
}
// Assume this is coming from the predefined avatars web floater
LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance");
if (folder_uuid.notNull())
{
LLPointer<LLInventoryCategory> category = new LLInventoryCategory(folder_uuid,
LLUUID::null,
LLFolderType::FT_CLOTHING,
"Quick Appearance");
if ( gInventory.getCategory( folder_uuid ) != NULL )
{
// Assume this is coming from the predefined avatars web floater
LLUIUsage::instance().logCommand("Avatar.WearPredefinedAppearance");
LLAppearanceMgr::getInstance()->wearInventoryCategory(category, true, false);
// *TODOw: This may not be necessary if initial outfit is chosen already -- josh
gAgent.setOutfitChosen(true);
}
// *TODOw: This may not be necessary if initial outfit is chosen already -- josh
gAgent.setOutfitChosen(true);
}
// release avatar picker keyboard focus
@ -4773,4 +4789,46 @@ public:
}
};
class LLAddFolderHandler : public LLCommandHandler
{
public:
// not allowed from outside the app
LLAddFolderHandler() : LLCommandHandler("add_folder", UNTRUSTED_BLOCK) {}
bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web)
{
wear_category(query_map, true);
return true;
}
};
class LLRemoveFolderHandler : public LLCommandHandler
{
public:
LLRemoveFolderHandler() : LLCommandHandler("remove_folder", UNTRUSTED_BLOCK) {}
bool handle(const LLSD& tokens, const LLSD& query_map, const std::string& grid, LLMediaCtrl* web)
{
if (query_map.has("folder_id"))
{
LLUUID folder_id = query_map["folder_id"].asUUID();
if (folder_id.notNull())
{
if (LLViewerInventoryCategory* cat = gInventory.getCategory(folder_id))
{
LLAppearanceMgr::instance().takeOffOutfit(cat->getLinkedUUID());
}
else
{
LL_WARNS() << "Couldn't find folder id" << folder_id << " in Inventory" << LL_ENDL;
}
}
}
return true;
}
};
LLWearFolderHandler gWearFolderHandler;
LLAddFolderHandler gAddFolderHandler;
LLRemoveFolderHandler gRemoveFolderHandler;

View File

@ -349,10 +349,6 @@ std::string gLastVersionChannel;
LLVector3 gWindVec(3.0, 3.0, 0.0);
LLVector3 gRelativeWindVec(0.0, 0.0, 0.0);
U32 gPacketsIn = 0;
bool gPrintMessagesThisFrame = false;
bool gRandomizeFramerate = false;
bool gPeriodicSlowFrame = false;
@ -361,6 +357,7 @@ bool gLLErrorActivated = false;
bool gLogoutInProgress = false;
bool gSimulateMemLeak = false;
bool gDoDisconnect = false;
// We don't want anyone, especially threads working on the graphics pipeline,
// to have to block due to this WorkQueue being full.
@ -374,7 +371,6 @@ const std::string MARKER_FILE_NAME("SecondLife.exec_marker");
const std::string START_MARKER_FILE_NAME("SecondLife.start_marker");
const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker");
const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker");
static bool gDoDisconnect = false;
static std::string gLaunchFileOnQuit;
// Used on Win32 for other apps to identify our window (eg, win_setup)
@ -449,8 +445,8 @@ void idle_afk_check()
{
// check idle timers
F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32();
F32 afk_timeout = (F32)gSavedSettings.getS32("AFKTimeout");
if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK())
static LLCachedControl<S32> afk_timeout(gSavedSettings, "AFKTimeout", 300);
if (afk_timeout() && (current_idle > (F32)afk_timeout()) && !gAgent.getAFK())
{
LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL;
gAgent.setAFK();
@ -1495,9 +1491,9 @@ bool LLAppViewer::doFrame()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df pauseMainloopTimeout");
pingMainloopTimeout("Main:Sleep");
pingMainloopTimeout("Main:Sleep");
pauseMainloopTimeout();
pauseMainloopTimeout();
}
// Sleep and run background threads
@ -2354,6 +2350,14 @@ void LLAppViewer::initLoggingAndGetLastDuration()
{
LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL;
}
std::string user_data_path_cef_log = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.log");
if (gDirUtilp->fileExists(user_data_path_cef_log))
{
std::string user_data_path_cef_old = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "cef.old");
LLFile::remove(user_data_path_cef_old, ENOENT);
LLFile::rename(user_data_path_cef_log, user_data_path_cef_old);
}
}
}
@ -2981,9 +2985,10 @@ void LLAppViewer::initStrings()
std::string strings_path_full = gDirUtilp->findSkinnedFilenameBaseLang(LLDir::XUI, strings_file);
if (strings_path_full.empty() || !LLFile::isfile(strings_path_full))
{
std::string crash_reason;
if (strings_path_full.empty())
{
LL_WARNS() << "The file '" << strings_file << "' is not found" << LL_ENDL;
crash_reason = "The file '" + strings_file + "' is not found";
}
else
{
@ -2991,24 +2996,23 @@ void LLAppViewer::initStrings()
int rc = LLFile::stat(strings_path_full, &st);
if (rc != 0)
{
LL_WARNS() << "The file '" << strings_path_full << "' failed to get status. Error code: " << rc << LL_ENDL;
crash_reason = "The file '" + strings_path_full + "' failed to get status. Error code: " + std::to_string(rc);
}
else if (S_ISDIR(st.st_mode))
{
LL_WARNS() << "The filename '" << strings_path_full << "' is a directory name" << LL_ENDL;
crash_reason = "The filename '" + strings_path_full + "' is a directory name";
}
else
{
LL_WARNS() << "The filename '" << strings_path_full << "' doesn't seem to be a regular file name" << LL_ENDL;
crash_reason = "The filename '" + strings_path_full + "' doesn't seem to be a regular file name";
}
}
// initial check to make sure files are there failed
gDirUtilp->dumpCurrentDirectories(LLError::LEVEL_WARN);
LLError::LLUserWarningMsg::showMissingFiles();
LL_ERRS() << "Viewer failed to find localization and UI files."
<< " Please reinstall viewer from https://secondlife.com/support/downloads"
<< " and contact https://support.secondlife.com if issue persists after reinstall." << LL_ENDL;
LL_ERRS() << "Viewer failed to open some of localization and UI files."
<< " " << crash_reason << "." << LL_ENDL;
}
LLTransUtil::parseStrings(strings_file, default_trans_args);
LLTransUtil::parseLanguageStrings("language_settings.xml");
@ -4244,7 +4248,7 @@ U32 LLAppViewer::getTextureCacheVersion()
U32 LLAppViewer::getDiskCacheVersion()
{
// Viewer disk cache version intorduced in Simple Cache Viewer, change if the cache format changes.
const U32 DISK_CACHE_VERSION = 1;
const U32 DISK_CACHE_VERSION = 2;
return DISK_CACHE_VERSION ;
}
@ -4563,11 +4567,32 @@ void LLAppViewer::saveFinalSnapshot()
}
}
static const char PRODUCTION_CACHE_FORMAT_STRING[] = "%s.%s";
static const char GRID_CACHE_FORMAT_STRING[] = "%s.%s.%s";
std::string get_name_cache_filename(const std::string &base_file, const std::string& extention)
{
std::string filename;
std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, base_file));
if (LLGridManager::getInstance()->isInProductionGrid())
{
filename = llformat(PRODUCTION_CACHE_FORMAT_STRING, path.c_str(), extention.c_str());
}
else
{
// NOTE: The inventory cache filenames now include the grid name.
// Add controls against directory traversal or problematic pathname lengths
// if your viewer uses grid names from an untrusted source.
const std::string& grid_id_str = LLGridManager::getInstance()->getGridId();
const std::string& grid_id_lower = utf8str_tolower(grid_id_str);
filename = llformat(GRID_CACHE_FORMAT_STRING, path.c_str(), grid_id_lower.c_str(), extention.c_str());
}
return filename;
}
void LLAppViewer::loadNameCache()
{
// display names cache
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
std::string filename = get_name_cache_filename("avatar_name_cache", "xml");
LL_INFOS("AvNameCache") << filename << LL_ENDL;
llifstream name_cache_stream(filename.c_str());
if(name_cache_stream.is_open())
@ -4582,8 +4607,8 @@ void LLAppViewer::loadNameCache()
if (!gCacheName) return;
std::string name_cache;
name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
// is there a reason for the "cache" extention?
std::string name_cache = get_name_cache_filename("name", "cache");
llifstream cache_file(name_cache.c_str());
if(cache_file.is_open())
{
@ -4594,8 +4619,7 @@ void LLAppViewer::loadNameCache()
void LLAppViewer::saveNameCache()
{
// display names cache
std::string filename =
gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
std::string filename = get_name_cache_filename("avatar_name_cache", "xml");
llofstream name_cache_stream(filename.c_str());
if(name_cache_stream.is_open())
{
@ -4605,8 +4629,7 @@ void LLAppViewer::saveNameCache()
// real names cache
if (gCacheName)
{
std::string name_cache;
name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
std::string name_cache = get_name_cache_filename("name", "cache");
llofstream cache_file(name_cache.c_str());
if(cache_file.is_open())
{
@ -4884,6 +4907,20 @@ void LLAppViewer::idle()
if (gTeleportDisplay)
{
if (gAgent.getTeleportState() == LLAgent::TELEPORT_ARRIVING)
{
// Teleported, but waiting for things to load, start processing surface data
{
LL_RECORD_BLOCK_TIME(FTM_NETWORK);
gVLManager.unpackData();
}
{
LL_RECORD_BLOCK_TIME(FTM_REGION_UPDATE);
const F32 max_region_update_time = .001f; // 1ms
LLWorld::getInstance()->updateRegions(max_region_update_time);
}
}
return;
}
@ -5179,15 +5216,28 @@ void LLAppViewer::sendLogoutRequest()
gLogoutInProgress = true;
if (!mSecondInstance)
{
mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB);
if (mLogoutMarkerFile.getFileHandle())
mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
try
{
LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL;
recordMarkerVersion(mLogoutMarkerFile);
if (!mLogoutMarkerFile.getFileHandle())
{
mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB);
if (mLogoutMarkerFile.getFileHandle())
{
LL_INFOS("MarkerFile") << "Created logout marker file '" << mLogoutMarkerFileName << "' " << LL_ENDL;
recordMarkerVersion(mLogoutMarkerFile);
}
else
{
LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL;
}
}
else
{
LL_WARNS("MarkerFile") << "Atempted to reopen file '" << mLogoutMarkerFileName << "' " << LL_ENDL;
}
}
else
catch (...)
{
LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL;
}
@ -5320,12 +5370,9 @@ void LLAppViewer::idleNameCache()
// Handle messages, and all message related stuff
//
#define TIME_THROTTLE_MESSAGES
#ifdef TIME_THROTTLE_MESSAGES
#define CHECK_MESSAGES_DEFAULT_MAX_TIME .020f // 50 ms = 50 fps (just for messages!)
constexpr F32 CHECK_MESSAGES_DEFAULT_MAX_TIME = 0.020f; // 50 ms = 50 fps (just for messages!)
static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
#endif
static LLTrace::BlockTimerStatHandle FTM_IDLE_NETWORK("Idle Network");
static LLTrace::BlockTimerStatHandle FTM_MESSAGE_ACKS("Message Acks");
@ -5342,7 +5389,8 @@ void LLAppViewer::idleNetwork()
gObjectList.mNumNewObjects = 0;
S32 total_decoded = 0;
if (!gSavedSettings.getBOOL("SpeedTest"))
static LLCachedControl<bool> speed_test(gSavedSettings, "SpeedTest", false);
if (!speed_test())
{
LL_PROFILE_ZONE_NAMED_CATEGORY_NETWORK("idle network"); //LL_RECORD_BLOCK_TIME(FTM_IDLE_NETWORK); // decode
@ -5352,6 +5400,7 @@ void LLAppViewer::idleNetwork()
F32 total_time = 0.0f;
{
bool needs_drain = false;
LockMessageChecker lmc(gMessageSystem);
while (lmc.checkAllMessages(frame_count, gServicePump))
{
@ -5364,53 +5413,45 @@ void LLAppViewer::idleNetwork()
}
total_decoded++;
gPacketsIn++;
if (total_decoded > MESSAGE_MAX_PER_FRAME)
{
needs_drain = true;
break;
}
#ifdef TIME_THROTTLE_MESSAGES
// Prevent slow packets from completely destroying the frame rate.
// This usually happens due to clumps of avatars taking huge amount
// of network processing time (which needs to be fixed, but this is
// a good limit anyway).
total_time = check_message_timer.getElapsedTimeF32();
if (total_time >= CheckMessagesMaxTime)
{
needs_drain = true;
break;
#endif
}
}
if (needs_drain || gMessageSystem->mPacketRing.getNumBufferedPackets() > 0)
{
// Rather than allow packets to silently backup on the socket
// we drain them into our own buffer so we know how many exist.
S32 num_buffered_packets = gMessageSystem->drainUdpSocket();
if (num_buffered_packets > 0)
{
// Increase CheckMessagesMaxTime so that we will eventually catch up
CheckMessagesMaxTime *= 1.035f; // 3.5% ~= 2x in 20 frames, ~8x in 60 frames
}
}
else
{
// Reset CheckMessagesMaxTime to default value
CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
}
// Handle per-frame message system processing.
lmc.processAcks(gSavedSettings.getF32("AckCollectTime"));
}
#ifdef TIME_THROTTLE_MESSAGES
if (total_time >= CheckMessagesMaxTime)
{
// Increase CheckMessagesMaxTime so that we will eventually catch up
CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
}
else
{
// Reset CheckMessagesMaxTime to default value
CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
}
#endif
// Decode enqueued messages...
S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
if( remaining_possible_decodes <= 0 )
{
LL_INFOS() << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << LL_ENDL;
}
if (gPrintMessagesThisFrame)
{
LL_INFOS() << "Decoded " << total_decoded << " msgs this frame!" << LL_ENDL;
gPrintMessagesThisFrame = false;
static LLCachedControl<F32> ack_collection_time(gSavedSettings, "AckCollectTime", 0.1f);
lmc.processAcks(ack_collection_time());
}
}
add(LLStatViewer::NUM_NEW_OBJECTS, gObjectList.mNumNewObjects);
@ -5418,6 +5459,7 @@ void LLAppViewer::idleNetwork()
// Retransmit unacknowledged packets.
gXferManager->retransmitUnackedPackets();
gAssetStorage->checkForTimeouts();
gViewerThrottle.setBufferLoadRate(gMessageSystem->getBufferLoadRate());
gViewerThrottle.updateDynamicThrottle();
// Check that the circuit between the viewer and the agent's current
@ -5592,6 +5634,27 @@ void LLAppViewer::forceErrorCoroutineCrash()
LLCoros::instance().launch("LLAppViewer::crashyCoro", [] {throw LLException("A deliberate crash from LLCoros"); });
}
void LLAppViewer::forceErrorCoroprocedureCrash()
{
LL_WARNS() << "Forcing a crash in LLCoprocedureManager" << LL_ENDL;
LLCoprocedureManager::instance().enqueueCoprocedure("Upload", "DeliberateCrash",
[](LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t&, const LLUUID&)
{
LL_WARNS() << "Forcing a deliberate bad memory access from LLCoprocedureManager" << LL_ENDL;
S32* crash = NULL;
*crash = 0xDEADBEEF;
});
}
void LLAppViewer::forceErrorWorkQueueCrash()
{
LL::WorkQueue::ptr_t workqueue = LL::WorkQueue::getInstance("General");
if (workqueue)
{
workqueue->post([]() { throw LLException("This is a deliberate crash from General Queue"); });
}
}
void LLAppViewer::forceErrorThreadCrash()
{
class LLCrashTestThread : public LLThread

View File

@ -157,9 +157,6 @@ public:
void loadNameCache();
void saveNameCache();
void loadExperienceCache();
void saveExperienceCache();
void removeMarkerFiles();
void recordSessionToMarker();
@ -175,6 +172,8 @@ public:
virtual void forceErrorOSSpecificException();
virtual void forceErrorDriverCrash();
virtual void forceErrorCoroutineCrash();
virtual void forceErrorCoroprocedureCrash();
virtual void forceErrorWorkQueueCrash();
virtual void forceErrorThreadCrash();
// The list is found in app_settings/settings_files.xml
@ -411,11 +410,10 @@ extern std::string gLastVersionChannel;
extern LLVector3 gWindVec;
extern LLVector3 gRelativeWindVec;
extern U32 gPacketsIn;
extern bool gPrintMessagesThisFrame;
extern bool gRandomizeFramerate;
extern bool gPeriodicSlowFrame;
extern bool gDoDisconnect;
extern bool gSimulateMemLeak;

View File

@ -41,6 +41,7 @@ void clearDumpLogsDir();
struct CrashMetadata
{
std::string logFilePathname;
std::string attributesPathname;
std::string userSettingsPathname;
std::string accountSettingsPathname;
std::string staticDebugPathname;

View File

@ -172,6 +172,8 @@ CrashMetadataSingleton::CrashMetadataSingleton()
// Note: we depend on being able to read the static_debug_info.log file
// from the *previous* run before we overwrite it with the new one for
// *this* run. LLAppViewer initialization must happen in the Right Order.
// Todo: consider converting static file into bugspalt attributes file
staticDebugPathname = *gViewerAppPtr->getStaticDebugFile();
std::ifstream static_file(staticDebugPathname);
LLSD info;
@ -215,7 +217,32 @@ CrashMetadataSingleton::CrashMetadataSingleton()
}
}
}
// Populate bugsplat attributes
LLXMLNodePtr out_node = new LLXMLNode("XmlCrashContext", false);
out_node->createChild("OS", false)->setValue(OSInfo);
out_node->createChild("AppState", false)->setValue(info["StartupState"].asString());
out_node->createChild("GraphicsCard", false)->setValue(info["GraphicsCard"].asString());
out_node->createChild("GLVersion", false)->setValue(info["GLInfo"]["GLVersion"].asString());
out_node->createChild("GLRenderer", false)->setValue(info["GLInfo"]["GLRenderer"].asString());
out_node->createChild("RAM", false)->setValue(info["RAMInfo"]["Physical"].asString());
if (!out_node->isNull())
{
attributesPathname = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "CrashContext.xml");
LLFILE* fp = LLFile::fopen(attributesPathname, "w");
if (fp != NULL)
{
LLXMLNode::writeHeaderToFile(fp);
out_node->writeToFile(fp);
fclose(fp);
}
}
}
// else Todo: consider fillig at least some values, like OS
}
// Avoid having to compile all of our LLSingleton machinery in Objective-C++.

View File

@ -155,10 +155,10 @@ namespace
sBugSplatSender->setAttribute(WCSTR(L"OS"), WCSTR(LLOSInfo::instance().getOSStringSimple())); // In case we ever stop using email for this
sBugSplatSender->setAttribute(WCSTR(L"AppState"), WCSTR(LLStartUp::getStartupStateString()));
sBugSplatSender->setAttribute(WCSTR(L"GL Vendor"), WCSTR(gGLManager.mGLVendor));
sBugSplatSender->setAttribute(WCSTR(L"GL Version"), WCSTR(gGLManager.mGLVersionString));
sBugSplatSender->setAttribute(WCSTR(L"GPU Version"), WCSTR(gGLManager.mDriverVersionVendorString));
sBugSplatSender->setAttribute(WCSTR(L"GL Renderer"), WCSTR(gGLManager.mGLRenderer));
sBugSplatSender->setAttribute(WCSTR(L"GLVendor"), WCSTR(gGLManager.mGLVendor));
sBugSplatSender->setAttribute(WCSTR(L"GLVersion"), WCSTR(gGLManager.mGLVersionString));
sBugSplatSender->setAttribute(WCSTR(L"GPUVersion"), WCSTR(gGLManager.mDriverVersionVendorString));
sBugSplatSender->setAttribute(WCSTR(L"GLRenderer"), WCSTR(gGLManager.mGLRenderer));
sBugSplatSender->setAttribute(WCSTR(L"VRAM"), WCSTR(STRINGIZE(gGLManager.mVRAM)));
sBugSplatSender->setAttribute(WCSTR(L"RAM"), WCSTR(STRINGIZE(gSysMemory.getPhysicalMemoryKB().value())));
@ -804,14 +804,16 @@ bool LLAppViewerWin32::cleanup()
return result;
}
void LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo)
bool LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo)
{
#if defined(LL_BUGSPLAT)
if (sBugSplatSender)
{
sBugSplatSender->createReport((EXCEPTION_POINTERS*)pExcepInfo);
return true;
}
#endif // LL_BUGSPLAT
return false;
}
void LLAppViewerWin32::initLoggingAndGetLastDuration()

View File

@ -43,7 +43,7 @@ public:
bool init() override; // Override to do application initialization
bool cleanup() override;
void reportCrashToBugsplat(void* pExcepInfo) override;
bool reportCrashToBugsplat(void* pExcepInfo) override;
protected:
void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info.

View File

@ -669,6 +669,7 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassif
void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id)
{
LL_DEBUGS("PickInfo") << " Requiesting pick info for " << pick_id << LL_ENDL;
// Must ask for a pick based on the creator id because
// the pick database is distributed to the inventory cluster. JC
std::vector<std::string> request_params{ creator_id.asString(), pick_id.asString() };

View File

@ -42,6 +42,7 @@
#include "llinventorymodel.h"
#include "llnotifications.h"
#include "llslurl.h"
#include "llstartup.h"
#include "llimview.h"
#include "lltrans.h"
#include "llviewercontrol.h"
@ -271,6 +272,22 @@ S32 LLAvatarTracker::addBuddyList(const LLAvatarTracker::buddy_map_t& buds)
<< "]" << LL_ENDL;
}
}
// It's possible that the buddy list getting propagated from the inventory may have happened after we actually got the buddy list.
// Any buddies that we got prior will reside in a special queue that we must process and update statuses accordingly with.
// Do that here.
// -Geenz 2025-03-12
while (!mBuddyStatusQueue.empty())
{
auto buddyStatus = mBuddyStatusQueue.front();
mBuddyStatusQueue.pop();
if (mBuddyInfo.find(buddyStatus.first) != mBuddyInfo.end())
{
setBuddyOnline(buddyStatus.first, buddyStatus.second);
}
}
// do not notify observers here - list can be large so let it be done on idle.
return new_buddy_count;
@ -335,6 +352,8 @@ void LLAvatarTracker::setBuddyOnline(const LLUUID& id, bool is_online)
{
LL_WARNS() << "!! No buddy info found for " << id
<< ", setting to " << (is_online ? "Online" : "Offline") << LL_ENDL;
LL_WARNS() << "Did we receive a buddy status update before the buddy info?" << LL_ENDL;
mBuddyStatusQueue.push(std::make_pair(id, is_online));
}
}
@ -485,7 +504,7 @@ void LLAvatarTracker::idleNotifyObservers()
void LLAvatarTracker::notifyObservers()
{
if (mIsNotifyObservers)
if (mIsNotifyObservers || (LLStartUp::getStartupState() <= STATE_INVENTORY_CALLBACKS))
{
// Don't allow multiple calls.
// new masks and ids will be processed later from idle.
@ -706,6 +725,8 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
{
LL_WARNS() << "Received online notification for unknown buddy: "
<< agent_id << " is " << (online ? "ONLINE" : "OFFLINE") << LL_ENDL;
LL_WARNS() << "Adding buddy to buddy queue." << LL_ENDL;
mBuddyStatusQueue.push(std::make_pair(agent_id, true));
}
if(tracking_id == agent_id)
@ -723,7 +744,11 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online)
mModifyMask |= LLFriendObserver::ONLINE;
instance().notifyObservers();
gInventory.notifyObservers();
// Skip if we had received the friends list before the inventory callbacks were properly initialized
if (LLStartUp::getStartupState() > STATE_INVENTORY_CALLBACKS)
{
gInventory.notifyObservers();
}
}
}

View File

@ -109,6 +109,7 @@ public:
// add or remove agents from buddy list. Each method takes a set
// of buddies and returns how many were actually added or removed.
typedef std::map<LLUUID, LLRelationship*> buddy_map_t;
typedef std::queue<std::pair<LLUUID, bool>> buddy_status_queue_t;
S32 addBuddyList(const buddy_map_t& buddies);
//S32 removeBuddyList(const buddy_list_t& exes);
@ -194,6 +195,7 @@ protected:
//LLInventoryObserver* mInventoryObserver;
buddy_map_t mBuddyInfo;
buddy_status_queue_t mBuddyStatusQueue;
typedef std::set<LLUUID> changed_buddy_t;
changed_buddy_t mChangedBuddyIDs;

View File

@ -240,10 +240,11 @@ void LLNotificationChiclet::setCounter(S32 counter)
bool LLNotificationChiclet::ChicletNotificationChannel::filterNotification( LLNotificationPtr notification )
{
bool displayNotification;
LLFloaterNotificationsTabbed* floater = LLFloaterNotificationsTabbed::getInstance();
if ( (notification->getName() == "ScriptDialog") // special case for scripts
// if there is no toast window for the notification, filter it
//|| (!LLNotificationWellWindow::getInstance()->findItemByID(notification->getID()))
|| (!LLFloaterNotificationsTabbed::getInstance()->findItemByID(notification->getID(), notification->getName()))
|| (floater && !floater->findItemByID(notification->getID(), notification->getName()))
)
{
displayNotification = false;

View File

@ -33,6 +33,7 @@
// viewer includes
#include "llagent.h"
#include "llagentcamera.h"
#include "llcriticaldamp.h"
#include "llface.h"
#include "lllightconstants.h"
@ -252,7 +253,15 @@ void LLDrawable::cleanupReferences()
std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
mFaces.clear();
gPipeline.unlinkDrawable(this);
if (gPipeline.mInitialized)
{
gPipeline.unlinkDrawable(this);
}
else if (getSpatialGroup())
{
// Not supposed to happen?
getSpatialGroup()->getSpatialPartition()->remove(this, getSpatialGroup());
}
removeFromOctree();
@ -778,6 +787,14 @@ bool LLDrawable::updateMove()
makeActive();
// #3256 force undampened movement for attached objects in mouselook
// to prevent animation bork for linkset with animated parts
if (!isRoot() && gAgentCamera.cameraMouselook() &&
!mVObjp->isRiggedMesh() && mVObjp->getAvatar() && mVObjp->getAvatar()->isSelf())
{
return updateMoveUndamped();
}
return isState(MOVE_UNDAMPED) ? updateMoveUndamped() : updateMoveDamped();
}

View File

@ -108,8 +108,9 @@ void LLDrawPoolTree::beginShadowPass(S32 pass)
{
LL_PROFILE_ZONE_SCOPED;
glPolygonOffset(gSavedSettings.getF32("RenderDeferredTreeShadowOffset"),
gSavedSettings.getF32("RenderDeferredTreeShadowBias"));
static LLCachedControl<F32> shadow_offset(gSavedSettings, "RenderDeferredTreeShadowOffset");
static LLCachedControl<F32> shadow_bias(gSavedSettings, "RenderDeferredTreeShadowBias");
glPolygonOffset(shadow_offset(), shadow_bias());
LLEnvironment& environment = LLEnvironment::instance();

View File

@ -101,10 +101,18 @@ namespace Details
void LLEventPollImpl::handleMessage(const LLSD& content)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_APP;
std::string msg_name = content["message"];
std::string msg_name = content["message"].asString();
LLSD message;
message["sender"] = mSenderIp;
message["body"] = content["body"];
try
{
message["sender"] = mSenderIp;
message["body"] = content["body"];
}
catch (std::bad_alloc&)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS("LLCoros") << "Bad memory allocation on message: " << msg_name << LL_ENDL;
}
LLMessageSystem::dispatch(msg_name, message);
}

View File

@ -2218,7 +2218,7 @@ bool LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_FACE("calcPixelArea - rigged");
//override with joint volume face joint bounding boxes
LLVOAvatar* avatar = mVObjp->getAvatar();
LLVOAvatar* avatar = mVObjp.notNull() ? mVObjp->getAvatar() : nullptr;
bool hasRiggedExtents = false;
if (avatar && avatar->mDrawable)

View File

@ -199,6 +199,7 @@ bool LLFetchedGLTFMaterial::replaceLocalTexture(const LLUUID& tracking_id, const
{
mTrackingIdToLocalTexture.erase(tracking_id);
}
updateLocalTexDataDigest();
return res;
}

View File

@ -670,6 +670,7 @@ std::unique_ptr<std::vector<std::string>> LLFilePicker::navOpenFilterProc(ELoadF
break;
case FFLOAD_HDRI:
allowedv->push_back("exr");
case FFLOAD_MODEL:
case FFLOAD_COLLADA:
allowedv->push_back("dae");
break;

View File

@ -33,6 +33,7 @@
#include "llagentui.h"
#include "llbase64.h"
#include "llcallbacklist.h"
#include "lldate.h"
#include "llenvironment.h"
#include "llimagejpeg.h"
#include "llmediactrl.h"
@ -692,7 +693,15 @@ void LLFloater360Capture::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent
);
// execute the command on the page
mWebBrowser->getMediaPlugin()->executeJavaScript(cmd);
LLPluginClassMedia* plugin = mWebBrowser->getMediaPlugin();
if (plugin)
{
plugin->executeJavaScript(cmd);
}
else
{
LL_WARNS("360Capture") << "No media plugin found" << LL_ENDL;
}
}
}
break;
@ -773,7 +782,15 @@ void LLFloater360Capture::onSaveLocalBtn()
// send it to the browser instance, triggering the equirectangular capture
// process and complimentary offer to save the image
mWebBrowser->getMediaPlugin()->executeJavaScript(cmd);
LLPluginClassMedia* plugin = mWebBrowser->getMediaPlugin();
if (plugin)
{
plugin->executeJavaScript(cmd);
}
else
{
LL_WARNS("360Capture") << "No media plugin found" << LL_ENDL;
}
}
// We capture all 6 images sequentially and if parts of the world are moving
@ -863,15 +880,7 @@ const std::string LLFloater360Capture::generate_proposed_filename()
filename << "_";
// add in the current HH-MM-SS (with leading 0's) so users can easily save many shots in same folder
std::time_t cur_epoch = std::time(nullptr);
std::tm* tm_time = std::localtime(&cur_epoch);
filename << std::setfill('0') << std::setw(4) << (tm_time->tm_year + 1900);
filename << std::setfill('0') << std::setw(2) << (tm_time->tm_mon + 1);
filename << std::setfill('0') << std::setw(2) << tm_time->tm_mday;
filename << "_";
filename << std::setfill('0') << std::setw(2) << tm_time->tm_hour;
filename << std::setfill('0') << std::setw(2) << tm_time->tm_min;
filename << std::setfill('0') << std::setw(2) << tm_time->tm_sec;
filename << LLDate::now().toLocalDateString("%Y%m%d_%H%M%S");
// the unusual way we save the output image (originates in the
// embedded browser and not the C++ code) means that the system

View File

@ -31,6 +31,7 @@
#include "llagent.h"
#include "llagentui.h"
#include "llcombobox.h"
#include "llfloaterreg.h"
#include "llinventoryfunctions.h"
#include "llinventoryobserver.h"
#include "lllandmarkactions.h"
@ -389,6 +390,7 @@ void LLFloaterCreateLandmark::setItem(const uuid_set_t& items)
{
mItem = item;
mAssetID = mItem->getAssetUUID();
mParentID = mItem->getParentUUID();
setVisibleAndFrontmost(true);
break;
}
@ -418,8 +420,7 @@ void LLFloaterCreateLandmark::updateItem(const uuid_set_t& items, U32 mask)
closeFloater();
}
LLUUID folder_id = mFolderCombo->getValue().asUUID();
if (folder_id != mItem->getParentUUID())
if (mParentID != mItem->getParentUUID())
{
// user moved landmark in inventory,
// assume that we are done all other changes should already be commited

View File

@ -69,6 +69,7 @@ private:
LLTextEditor* mNotesEditor;
LLUUID mLandmarksID;
LLUUID mAssetID;
LLUUID mParentID;
LLLandmarksInventoryObserver* mInventoryObserver;
LLPointer<LLInventoryItem> mItem;

View File

@ -57,8 +57,7 @@ static const S32 USED_EMOJIS_IMAGE_INDEX = 0x23F2;
// https://www.compart.com/en/unicode/U+1F6D1
static const S32 EMPTY_LIST_IMAGE_INDEX = 0x1F6D1;
// The following categories should follow the required alphabetic order
static const std::string RECENTLY_USED_CATEGORY = "1 recently used";
static const std::string FREQUENTLY_USED_CATEGORY = "2 frequently used";
static const std::string FREQUENTLY_USED_CATEGORY = "frequently used";
// Floater state related variables
static std::list<llwchar> sRecentlyUsed;
@ -445,11 +444,10 @@ void LLFloaterEmojiPicker::fillGroups()
params.name = "all_categories";
createGroupButton(params, rect, ALL_EMOJIS_IMAGE_INDEX);
// Create group and button for "Recently used" and/or "Frequently used"
if (!sRecentlyUsed.empty() || !sFrequentlyUsed.empty())
// Create group and button for "Frequently used"
if (!sFrequentlyUsed.empty())
{
std::map<std::string, std::vector<LLEmojiSearchResult>> cats;
fillCategoryRecentlyUsed(cats);
fillCategoryFrequentlyUsed(cats);
if (!cats.empty())
@ -482,40 +480,6 @@ void LLFloaterEmojiPicker::fillGroups()
resizeGroupButtons();
}
void LLFloaterEmojiPicker::fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats)
{
if (sRecentlyUsed.empty())
return;
std::vector<LLEmojiSearchResult> emojis;
// In case of empty mFilterPattern we'd use sRecentlyUsed directly
if (!mFilterPattern.empty())
{
// List all emojis in "Recently used"
const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr();
std::size_t begin, end;
for (llwchar emoji : sRecentlyUsed)
{
auto e2d = emoji2descr.find(emoji);
if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty())
{
for (const std::string& shortcode : e2d->second->ShortCodes)
{
if (LLEmojiDictionary::searchInShortCode(begin, end, shortcode, mFilterPattern))
{
emojis.emplace_back(emoji, shortcode, begin, end);
}
}
}
}
if (emojis.empty())
return;
}
cats.emplace(std::make_pair(RECENTLY_USED_CATEGORY, emojis));
}
void LLFloaterEmojiPicker::fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats)
{
if (sFrequentlyUsed.empty())
@ -756,7 +720,6 @@ void LLFloaterEmojiPicker::fillEmojisCategory(const std::vector<LLEmojiSearchRes
{
// Place the category title
std::string title =
category == RECENTLY_USED_CATEGORY ? getString("title_for_recently_used") :
category == FREQUENTLY_USED_CATEGORY ? getString("title_for_frequently_used") :
isupper(category.front()) ? category : LLStringUtil::capitalize(category);
LLEmojiGridDivider* div = new LLEmojiGridDivider(row_panel_params, title);
@ -769,21 +732,7 @@ void LLFloaterEmojiPicker::fillEmojisCategory(const std::vector<LLEmojiSearchRes
{
const LLEmojiDictionary::emoji2descr_map_t& emoji2descr = LLEmojiDictionary::instance().getEmoji2Descr();
LLEmojiSearchResult emoji { 0, "", 0, 0 };
if (category == RECENTLY_USED_CATEGORY)
{
for (llwchar code : sRecentlyUsed)
{
const LLEmojiDictionary::emoji2descr_map_t::const_iterator& e2d = emoji2descr.find(code);
if (e2d != emoji2descr.end() && !e2d->second->ShortCodes.empty())
{
emoji.Character = code;
emoji.String = e2d->second->ShortCodes.front();
createEmojiIcon(emoji, category, row_panel_params, row_list_params, icon_params,
icon_rect, max_icons, bg, row, icon_index);
}
}
}
else if (category == FREQUENTLY_USED_CATEGORY)
if (category == FREQUENTLY_USED_CATEGORY)
{
for (const auto& code : sFrequentlyUsed)
{

View File

@ -60,7 +60,6 @@ public:
private:
void initialize();
void fillGroups();
void fillCategoryRecentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats);
void fillCategoryFrequentlyUsed(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats);
void fillGroupEmojis(std::map<std::string, std::vector<LLEmojiSearchResult>>& cats, U32 index);
void createGroupButton(LLButton::Params& params, const LLRect& rect, llwchar emoji);

View File

@ -1939,7 +1939,7 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c
mConversationEventQueue.erase(uuid);
// Don't let the focus fall IW, select and refocus on the first conversation in the list
if (change_focus)
if (change_focus && isInVisibleChain())
{
setFocus(true);
if (new_selection)
@ -1959,6 +1959,10 @@ bool LLFloaterIMContainer::removeConversationListItem(const LLUUID& uuid, bool c
}
}
}
else
{
LL_INFOS() << "Conversation widgets: " << (S32)mConversationsWidgets.size() << LL_ENDL;
}
return is_widget_selected;
}

View File

@ -200,6 +200,7 @@ void LLFloaterLagMeter::determineNetwork()
// the network handlers are de-synched from the rendering.
F32Milliseconds client_frame_time = frame_recording.getPeriodMean(LLStatViewer::FRAME_STACKTIME);
// Todo: account for LLPacketRing dropped packets? viewer drops those when it can't keep up
if(packet_loss >= mNetworkPacketLossCritical)
{
mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME));

View File

@ -115,12 +115,12 @@ bool LLFloaterPerformance::postBuild()
mHUDList = mHUDsPanel->getChild<LLNameListCtrl>("hud_list");
mHUDList->setNameListType(LLNameListCtrl::SPECIAL);
mHUDList->setHoverIconName("StopReload_Off");
mHUDList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1));
mHUDList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachObject, this, _1));
mObjectList = mComplexityPanel->getChild<LLNameListCtrl>("obj_list");
mObjectList->setNameListType(LLNameListCtrl::SPECIAL);
mObjectList->setHoverIconName("StopReload_Off");
mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1));
mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachObject, this, _1));
mSettingsPanel->getChild<LLButton>("advanced_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickAdvanced, this));
mSettingsPanel->getChild<LLButton>("defaults_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickDefaults, this));
@ -527,9 +527,13 @@ void LLFloaterPerformance::setFPSText()
mTextFPSLabel->setValue(fps_text);
}
void LLFloaterPerformance::detachItem(const LLUUID& item_id)
void LLFloaterPerformance::detachObject(const LLUUID& obj_id)
{
LLAppearanceMgr::instance().removeItemFromAvatar(item_id);
LLViewerObject* obj = gObjectList.findObject(obj_id);
if (obj)
{
LLAppearanceMgr::instance().removeItemFromAvatar(obj->getAttachmentItemID());
}
}
void LLFloaterPerformance::onClickAdvanced()

View File

@ -48,7 +48,7 @@ public:
void hidePanels();
void showAutoadjustmentsPanel();
void detachItem(const LLUUID& item_id);
void detachObject(const LLUUID& obj_id);
void onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y);

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