diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 60ad7e8fe5..50b0cf02bc 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -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 }}
diff --git a/autobuild.xml b/autobuild.xml
index 95ee34439b..777d98640f 100644
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -2039,11 +2039,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
name
darwin64
@@ -2053,11 +2053,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
name
linux64
@@ -2067,11 +2067,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
archive
name
windows64
@@ -3014,14 +3014,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
build
default
@@ -3042,14 +3043,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
build
name
@@ -3072,14 +3074,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
build
name
@@ -3098,14 +3101,15 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
build
name
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 39f26ced5d..c895f42362 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -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}")
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 95d55c835f..3d66809ed6 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -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)
diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp
index 97f9ca68b6..719381b4fc 100644
--- a/indra/llappearance/llpolymesh.cpp
+++ b/indra/llappearance/llpolymesh.cpp
@@ -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)
{
diff --git a/indra/llappearance/llwearable.cpp b/indra/llappearance/llwearable.cpp
index f30c147b91..4acb0ef3d4 100644
--- a/indra/llappearance/llwearable.cpp
+++ b/indra/llappearance/llwearable.cpp
@@ -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.
diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp
index 18d682b554..755547bfaa 100644
--- a/indra/llaudio/llaudioengine_openal.cpp
+++ b/indra/llaudio/llaudioengine_openal.cpp
@@ -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;
}
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 3d18864b80..57f5a112d9 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -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:
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index 1539b48bd3..9e95d9c85f 100644
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -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
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index b38864688d..5205699b92 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -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;
diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h
index 1a69a04232..34c8692f20 100644
--- a/indra/llcommon/lldate.h
+++ b/indra/llcommon/lldate.h
@@ -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);
/**
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 6066e74fb5..c8ece616b2 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -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)
diff --git a/indra/llinventory/llsettingsbase.cpp b/indra/llinventory/llsettingsbase.cpp
index 0ee71de3a1..d483b33288 100644
--- a/indra/llinventory/llsettingsbase.cpp
+++ b/indra/llinventory/llsettingsbase.cpp
@@ -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);
diff --git a/indra/llinventory/llsettingsbase.h b/indra/llinventory/llsettingsbase.h
index 816ff3e111..7de71588ef 100644
--- a/indra/llinventory/llsettingsbase.h
+++ b/indra/llinventory/llsettingsbase.h
@@ -348,13 +348,8 @@ protected:
LLSettingsBase();
LLSettingsBase(const LLSD setting);
- static LLSD settingValidation(LLSD settings);
-
typedef std::set 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)
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index bf7cfbe071..0d1f2b3006 100644
--- a/indra/llkdu/llimagej2ckdu.cpp
+++ b/indra/llkdu/llimagej2ckdu.cpp
@@ -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() << "!")));
}
}
diff --git a/indra/llmath/llmatrix3a.cpp b/indra/llmath/llmatrix3a.cpp
index 48a72e71e1..c0b00201cf 100644
--- a/indra/llmath/llmatrix3a.cpp
+++ b/indra/llmath/llmatrix3a.cpp
@@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
+#include "linden_common.h"
+
#include "llmath.h"
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
diff --git a/indra/llmath/llmatrix4a.cpp b/indra/llmath/llmatrix4a.cpp
index 00e30a248b..bfb4c2b07a 100644
--- a/indra/llmath/llmatrix4a.cpp
+++ b/indra/llmath/llmatrix4a.cpp
@@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
+#include "linden_common.h"
+
#include "llmath.h"
#include "llmatrix4a.h"
diff --git a/indra/llmath/llrigginginfo.cpp b/indra/llmath/llrigginginfo.cpp
index 23dbddd78e..2f59f685d5 100644
--- a/indra/llmath/llrigginginfo.cpp
+++ b/indra/llmath/llrigginginfo.cpp
@@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
+#include "linden_common.h"
+
#include "llmath.h"
#include "llrigginginfo.h"
diff --git a/indra/llmath/llvector4a.cpp b/indra/llmath/llvector4a.cpp
index 0ac91366b6..b81d50f0f9 100644
--- a/indra/llmath/llvector4a.cpp
+++ b/indra/llmath/llvector4a.cpp
@@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
+#include "linden_common.h"
+
#include "llmemory.h"
#include "llmath.h"
#include "llquantize.h"
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 44b6e7923b..76e5e3aae9 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -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 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;
diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp
index 71288daa89..141317ee8d 100644
--- a/indra/llmath/llvolumeoctree.cpp
+++ b/indra/llmath/llvolumeoctree.cpp
@@ -24,6 +24,8 @@
* $/LicenseInfo$
*/
+#include "linden_common.h"
+
#include "llvolumeoctree.h"
#include "llvector4a.h"
diff --git a/indra/llmath/v3colorutil.h b/indra/llmath/v3colorutil.h
index 62005f76a0..af8799e42a 100644
--- a/indra/llmath/v3colorutil.h
+++ b/indra/llmath/v3colorutil.h
@@ -28,6 +28,7 @@
#define LL_V3COLORUTIL_H
#include "v3color.h"
+#include "v4color.h"
inline LLColor3 componentDiv(LLColor3 const &left, LLColor3 const & right)
{
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 2de59c1b6a..10fd56a68e 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -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(
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 88fa572092..6d6526757d 100644
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -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(
diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp
index 263670bdac..6a663a8e97 100644
--- a/indra/llmessage/llcoproceduremanager.cpp
+++ b/indra/llmessage/llcoproceduremanager.cpp
@@ -301,12 +301,12 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size):
mPoolSize(size),
mActiveCoprocsCount(0),
mPending(0),
- mPendingCoprocs(std::make_shared(LLCoprocedureManager::DEFAULT_QUEUE_SIZE)),
mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID),
mCoroMapping()
{
try
{
+ mPendingCoprocs = std::make_shared(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)
{
diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp
index 918a69be6f..992e145758 100644
--- a/indra/llmessage/llcorehttputil.cpp
+++ b/indra/llmessage/llcorehttputil.cpp
@@ -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);
diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp
index b5d0c93376..83a070df32 100644
--- a/indra/llmessage/llexperiencecache.cpp
+++ b/indra/llmessage/llexperiencecache.cpp
@@ -94,6 +94,8 @@ LLExperienceCache::LLExperienceCache()
LLExperienceCache::~LLExperienceCache()
{
+ // can exit without cleanup()
+ sShutdown = true;
}
void LLExperienceCache::initSingleton()
diff --git a/indra/llmessage/llpacketbuffer.cpp b/indra/llmessage/llpacketbuffer.cpp
index dc5c7a73cb..0b04a560be 100644
--- a/indra/llmessage/llpacketbuffer.cpp
+++ b/indra/llmessage/llpacketbuffer.cpp
@@ -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();
+ }
+}
+
diff --git a/indra/llmessage/llpacketbuffer.h b/indra/llmessage/llpacketbuffer.h
index a2d2973fb0..ac4012d330 100644
--- a/indra/llmessage/llpacketbuffer.h
+++ b/indra/llmessage/llpacketbuffer.h
@@ -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
diff --git a/indra/llmessage/llpacketring.cpp b/indra/llmessage/llpacketring.cpp
index be838770a8..eb6650c6c5 100644
--- a/indra/llmessage/llpacketring.cpp
+++ b/indra/llmessage/llpacketring.cpp
@@ -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(static_cast(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(static_cast(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(static_cast(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(static_cast(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 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;
+}
diff --git a/indra/llmessage/llpacketring.h b/indra/llmessage/llpacketring.h
index f0e95f8524..572dcbd271 100644
--- a/indra/llmessage/llpacketring.h
+++ b/indra/llmessage/llpacketring.h
@@ -25,16 +25,14 @@
* $/LicenseInfo$
*/
-#ifndef LL_LLPACKETRING_H
-#define LL_LLPACKETRING_H
+#pragma once
-#include
+#include
#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 mReceiveQueue;
- std::queue mSendQueue;
+protected:
+ std::vector 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
diff --git a/indra/llmessage/llproxy.cpp b/indra/llmessage/llproxy.cpp
index 864e68998c..d04ca52ad6 100644
--- a/indra/llmessage/llproxy.cpp
+++ b/indra/llmessage/llproxy.cpp
@@ -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)
diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp
index cfa5178fc6..ad1ff86807 100644
--- a/indra/llmessage/message.cpp
+++ b/indra/llmessage/message.cpp
@@ -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
diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h
index b4b0d94021..30945cac51 100644
--- a/indra/llmessage/message.h
+++ b/indra/llmessage/message.h
@@ -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
{
diff --git a/indra/llmessage/net.cpp b/indra/llmessage/net.cpp
index f153c938cf..2be5a9e5b6 100644
--- a/indra/llmessage/net.cpp
+++ b/indra/llmessage/net.cpp
@@ -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)
diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp
index 908f3c8ff5..19a0ce639a 100644
--- a/indra/llplugin/llpluginprocessparent.cpp
+++ b/indra/llplugin/llpluginprocessparent.cpp
@@ -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",
diff --git a/indra/llrender/llcubemaparray.cpp b/indra/llrender/llcubemaparray.cpp
index d0a97dc2c6..998b57217d 100644
--- a/indra/llrender/llcubemaparray.cpp
+++ b/indra/llrender/llcubemaparray.cpp
@@ -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 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 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);
diff --git a/indra/llrender/llcubemaparray.h b/indra/llrender/llcubemaparray.h
index bfc72a321d..6b4288cb23 100644
--- a/indra/llrender/llcubemaparray.h
+++ b/indra/llrender/llcubemaparray.h
@@ -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;
};
diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp
index 62b551f1e0..649dd369cb 100644
--- a/indra/llrender/llfontfreetype.cpp
+++ b/indra/llrender/llfontfreetype.cpp
@@ -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());
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 1bc5e79835..1966e48f2e 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -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];
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 1bce31edb1..d2534b3939 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -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())
diff --git a/indra/llui/llcommandmanager.cpp b/indra/llui/llcommandmanager.cpp
index 03717da80b..b10ec51f18 100644
--- a/indra/llui/llcommandmanager.cpp
+++ b/indra/llui/llcommandmanager.cpp
@@ -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;
}
diff --git a/indra/llui/llfolderviewitem.cpp b/indra/llui/llfolderviewitem.cpp
index 18bde344a0..6d0cfcba95 100644
--- a/indra/llui/llfolderviewitem.cpp
+++ b/indra/llui/llfolderviewitem.cpp
@@ -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"
diff --git a/indra/llui/llmenugl.cpp b/indra/llui/llmenugl.cpp
index 69ffa9a94f..c11b42a348 100644
--- a/indra/llui/llmenugl.cpp
+++ b/indra/llui/llmenugl.cpp
@@ -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)
diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp
index 7405413a3d..a05feab1d9 100644
--- a/indra/llui/llnotifications.cpp
+++ b/indra/llui/llnotifications.cpp
@@ -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::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);
diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h
index 46286457cf..138f1969d5 100644
--- a/indra/llui/llnotifications.h
+++ b/indra/llui/llnotifications.h
@@ -887,7 +887,7 @@ class LLNotifications :
{
LLSINGLETON(LLNotifications);
LOG_CLASS(LLNotifications);
- virtual ~LLNotifications() {}
+ virtual ~LLNotifications();
public:
diff --git a/indra/llui/llscrolllistctrl.cpp b/indra/llui/llscrolllistctrl.cpp
index 93bd3c6bed..245339b107 100644
--- a/indra/llui/llscrolllistctrl.cpp
+++ b/indra/llui/llscrolllistctrl.cpp
@@ -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);
diff --git a/indra/llui/llsearchablecontrol.h b/indra/llui/llsearchablecontrol.h
index 119852b763..bae85fe9a5 100644
--- a/indra/llui/llsearchablecontrol.h
+++ b/indra/llui/llsearchablecontrol.h
@@ -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();
}
diff --git a/indra/llui/lltextbase.cpp b/indra/llui/lltextbase.cpp
index fae22fd248..41e7094163 100644
--- a/indra/llui/lltextbase.cpp
+++ b/indra/llui/lltextbase.cpp
@@ -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 );
diff --git a/indra/llui/lltextbox.h b/indra/llui/lltextbox.h
index a3cde45cd0..500dc8669f 100644
--- a/indra/llui/lltextbox.h
+++ b/indra/llui/lltextbox.h
@@ -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
diff --git a/indra/llui/lltexteditor.cpp b/indra/llui/lltexteditor.cpp
index 3537c764b9..77a4976f6b 100644
--- a/indra/llui/lltexteditor.cpp
+++ b/indra/llui/lltexteditor.cpp
@@ -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 )
diff --git a/indra/llui/llui.h b/indra/llui/llui.h
index 375cd539b7..9890d3f7ef 100644
--- a/indra/llui/llui.h
+++ b/indra/llui/llui.h
@@ -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"
diff --git a/indra/llwindow/llwindowmacosx.cpp b/indra/llwindow/llwindowmacosx.cpp
index 6c3be3eef8..dadbc83f45 100644
--- a/indra/llwindow/llwindowmacosx.cpp
+++ b/indra/llwindow/llwindowmacosx.cpp
@@ -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;
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 832cf254d1..1cac6ffe08 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -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;
}
diff --git a/indra/llxml/llxmlnode.cpp b/indra/llxml/llxmlnode.cpp
index 92bcb1a2ae..ec616cefbc 100644
--- a/indra/llxml/llxmlnode.cpp
+++ b/indra/llxml/llxmlnode.cpp
@@ -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);
}
diff --git a/indra/llxml/llxmltree.cpp b/indra/llxml/llxmltree.cpp
index 164b3156e1..d66544d0f8 100644
--- a/indra/llxml/llxmltree.cpp
+++ b/indra/llxml/llxmltree.cpp
@@ -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();
}
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index d2736c7c12..ed29911a43 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -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
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 0f9f025fe4..991d8e5c5f 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-7.1.12
+7.1.13
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 4293fa3034..60ae8ac691 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3676,6 +3676,17 @@
Value
5000
+ InventoryExposeFolderID
+
MarketplaceListingsSortOrder
+ RenderTextureVRAMDivisor
+
RenderMinFreeMainMemoryThreshold
+ RenderReflectionProbeDynamicAllocation
+
+ RenderReflectionProbeCount
+
RenderReflectionProbeResolution
TextureScaleMaxAreaFactor