diff --git a/.gitattributes b/.gitattributes
index 3a4c44aedc..30cc9de8f1 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -33,3 +33,6 @@ FILES_ARE_UNICODE_UTF-16LE.txt text eol=crlf
# Windows Manifest files
*.manifest text eol=crlf
+
+# Windows Installer Script files (normalization disabled)
+*.nsi -text
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 0fedf579b1..3a3546a8ef 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -124,7 +124,6 @@ if(WINDOWS)
MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake")
endif (MSVC80)
- # Try using the VC runtime redistributables that came with the VS installation first
if (MSVC_TOOLSET_VER AND DEFINED ENV{VCTOOLSREDISTDIR})
if(ADDRESS_SIZE EQUAL 32)
set(redist_find_path "$ENV{VCTOOLSREDISTDIR}x86\\Microsoft.VC${MSVC_TOOLSET_VER}.CRT")
@@ -134,7 +133,6 @@ if(WINDOWS)
get_filename_component(redist_path "${redist_find_path}" ABSOLUTE)
MESSAGE(STATUS "VC Runtime redist path: ${redist_path}")
endif (MSVC_TOOLSET_VER AND DEFINED ENV{VCTOOLSREDISTDIR})
- #
if(ADDRESS_SIZE EQUAL 32)
# this folder contains the 32bit DLLs.. (yes really!)
@@ -158,14 +156,12 @@ if(WINDOWS)
vcruntime${MSVC_VER}.dll
vcruntime${MSVC_VER}_1.dll
)
- # Try using the VC runtime redistributables that came with the VS installation first
if(redist_path AND EXISTS "${redist_path}/${release_msvc_file}")
MESSAGE(STATUS "Copying redist file from ${redist_path}/${release_msvc_file}")
to_staging_dirs(
${redist_path}
third_party_targets
${release_msvc_file})
- #
elseif(EXISTS "${registry_path}/${release_msvc_file}")
MESSAGE(STATUS "Copying redist file from ${registry_path}/${release_msvc_file}")
to_staging_dirs(
diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp
index d0fb586459..e93ba83434 100644
--- a/indra/llcommon/llleap.cpp
+++ b/indra/llcommon/llleap.cpp
@@ -18,9 +18,6 @@
#include
// std headers
// external library headers
-#include
-#include
-#include
// other Linden headers
#include "llerror.h"
#include "llstring.h"
@@ -64,7 +61,9 @@ public:
// Pass it a callback to our connect() method, so it can send events
// from a particular LLEventPump to the plugin without having to know
// this class or method name.
- mListener(new LLLeapListener(boost::bind(&LLLeapImpl::connect, this, _1, _2)))
+ mListener(new LLLeapListener(
+ [this](LLEventPump& pump, const std::string& listener)
+ { return connect(pump, listener); }))
{
// Rule out unpopulated Params block
if (! cparams.executable.isProvided())
@@ -93,7 +92,7 @@ public:
}
// Listen for child "termination" right away to catch launch errors.
- mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::bad_launch, this, _1));
+ mDonePump.listen("LLLeap", [this](const LLSD& data){ return bad_launch(data); });
// Okay, launch child.
// Get a modifiable copy of params block to set files and postend.
@@ -113,7 +112,7 @@ public:
// Okay, launch apparently worked. Change our mDonePump listener.
mDonePump.stopListening("LLLeap");
- mDonePump.listen("LLLeap", boost::bind(&LLLeapImpl::done, this, _1));
+ mDonePump.listen("LLLeap", [this](const LLSD& data){ return done(data); });
// Child might pump large volumes of data through either stdout or
// stderr. Don't bother copying all that data into notification event.
@@ -128,13 +127,9 @@ public:
// Listening on stdout is stateful. In general, we're either waiting
// for the length prefix or waiting for the specified length of data.
- // We address that with two different listener methods -- one of which
- // is blocked at any given time.
+ mReadPrefix = true;
mStdoutConnection = childout.getPump()
- .listen("prefix", boost::bind(&LLLeapImpl::rstdout, this, _1));
- mStdoutDataConnection = childout.getPump()
- .listen("data", boost::bind(&LLLeapImpl::rstdoutData, this, _1));
- mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection));
+ .listen("LLLeap", [this](const LLSD& data){ return rstdout(data); });
// Log anything sent up through stderr. When a typical program
// encounters an error, it writes its error message to stderr and
@@ -142,7 +137,7 @@ public:
// interpreter behaves that way. More generally, though, a plugin
// author can log whatever s/he wants to the viewer log using stderr.
mStderrConnection = childerr.getPump()
- .listen("LLLeap", boost::bind(&LLLeapImpl::rstderr, this, _1));
+ .listen("LLLeap", [this](const LLSD& data){ return rstderr(data); });
// For our lifespan, intercept any LL_ERRS so we can notify plugin
mRecorder = LLError::addGenericRecorder(
@@ -255,120 +250,120 @@ public:
return false;
}
- // Initial state of stateful listening on child stdout: wait for a length
- // prefix, followed by ':'.
- bool rstdout(const LLSD& data)
+ // Stateful listening on child stdout:
+ // wait for a length prefix, followed by ':'.
+ bool rstdout(const LLSD&)
{
LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT));
- // It's possible we got notified of a couple digit characters without
- // seeing the ':' -- unlikely, but still. Until we see ':', keep
- // waiting.
- if (childout.contains(':'))
+ while (childout.size())
{
- std::istream& childstream(childout.get_istream());
- // Saw ':', read length prefix and store in mExpect.
- size_t expect;
- childstream >> expect;
- int colon(childstream.get());
- if (colon != ':')
+ /*----------------- waiting for length prefix ------------------*/
+ if (mReadPrefix)
{
- // Protocol failure. Clear out the rest of the pending data in
- // childout (well, up to a max length) to log what was wrong.
- LLProcess::ReadPipe::size_type
- readlen((std::min)(childout.size(), LLProcess::ReadPipe::size_type(80)));
- bad_protocol(STRINGIZE(expect << char(colon) << childout.read(readlen)));
- }
- else
- {
- // Saw length prefix, saw colon, life is good. Now wait for
- // that length of data to arrive.
- mExpect = expect;
- LL_DEBUGS("LLLeap") << "got length, waiting for "
- << mExpect << " bytes of data" << LL_ENDL;
- // Block calls to this method; resetting mBlocker unblocks
- // calls to the other method.
- mBlocker.reset(new LLEventPump::Blocker(mStdoutConnection));
- // Go check if we've already received all the advertised data.
- if (childout.size())
+ // It's possible we got notified of a couple digit characters without
+ // seeing the ':' -- unlikely, but still. Until we see ':', keep
+ // waiting.
+ if (! childout.contains(':'))
{
- LLSD updata(data);
- updata["len"] = LLSD::Integer(childout.size());
- rstdoutData(updata);
+ if (childout.contains('\n'))
+ {
+ // Since this is the initial listening state, this is where we'd
+ // arrive if the child isn't following protocol at all -- say
+ // because the user specified 'ls' or some darn thing.
+ bad_protocol(childout.getline());
+ }
+ // Either way, stop looping.
+ break;
}
- }
- }
- else if (childout.contains('\n'))
- {
- // Since this is the initial listening state, this is where we'd
- // arrive if the child isn't following protocol at all -- say
- // because the user specified 'ls' or some darn thing.
- bad_protocol(childout.getline());
- }
- return false;
- }
- // State in which we listen on stdout for the specified length of data to
- // arrive.
- bool rstdoutData(const LLSD& data)
- {
- LLProcess::ReadPipe& childout(mChild->getReadPipe(LLProcess::STDOUT));
- // Until we've accumulated the promised length of data, keep waiting.
- if (childout.size() >= mExpect)
- {
- // Ready to rock and roll.
- LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got "
- << childout.size() << ", parsing LLSD" << LL_ENDL;
- LLSD data;
-#if 1
- // specifically require notation LLSD from child
- LLPointer parser(new LLSDNotationParser());
- S32 parse_status(parser->parse(childout.get_istream(), data, mExpect));
- if (parse_status == LLSDParser::PARSE_FAILURE)
-#else
- // SL-18330: accept any valid LLSD serialization format from child
- // Unfortunately this runs into trouble we have not yet debugged.
- bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect));
- if (! parse_status)
-#endif
- {
- bad_protocol("unparseable LLSD data");
- }
- else if (! (data.isMap() && data["pump"].isString() && data.has("data")))
- {
- // we got an LLSD object, but it lacks required keys
- bad_protocol("missing 'pump' or 'data'");
+ // Saw ':', read length prefix and store in mExpect.
+ std::istream& childstream(childout.get_istream());
+ size_t expect;
+ childstream >> expect;
+ int colon(childstream.get());
+ if (colon != ':')
+ {
+ // Protocol failure. Clear out the rest of the pending data in
+ // childout (well, up to a max length) to log what was wrong.
+ LLProcess::ReadPipe::size_type
+ readlen((std::min)(childout.size(),
+ LLProcess::ReadPipe::size_type(80)));
+ bad_protocol(stringize(expect, char(colon), childout.read(readlen)));
+ break;
+ }
+ else
+ {
+ // Saw length prefix, saw colon, life is good. Now wait for
+ // that length of data to arrive.
+ mExpect = expect;
+ LL_DEBUGS("LLLeap") << "got length, waiting for "
+ << mExpect << " bytes of data" << LL_ENDL;
+ // Transition to "read data" mode and loop back to check
+ // if we've already received all the advertised data.
+ mReadPrefix = false;
+ continue;
+ }
}
+ /*----------------- saw prefix, wait for data ------------------*/
else
{
- try
+ // Until we've accumulated the promised length of data, keep waiting.
+ if (childout.size() < mExpect)
{
- // The LLSD object we got from our stream contains the
- // keys we need.
- LLEventPumps::instance().obtain(data["pump"]).post(data["data"]);
+ break;
}
- catch (const std::exception& err)
+
+ // We have the data we were told to expect! Ready to rock and roll.
+ LL_DEBUGS("LLLeap") << "needed " << mExpect << " bytes, got "
+ << childout.size() << ", parsing LLSD" << LL_ENDL;
+ LLSD data;
+#if 1
+ // specifically require notation LLSD from child
+ LLPointer parser(new LLSDNotationParser());
+ S32 parse_status(parser->parse(childout.get_istream(), data, mExpect));
+ if (parse_status == LLSDParser::PARSE_FAILURE)
+#else
+ // SL-18330: accept any valid LLSD serialization format from child
+ // Unfortunately this runs into trouble we have not yet debugged.
+ bool parse_status(LLSDSerialize::deserialize(data, childout.get_istream(), mExpect));
+ if (! parse_status)
+#endif
{
- // No plugin should be allowed to crash the viewer by
- // driving an exception -- intentionally or not.
- LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data));
- // Whether or not the plugin added a "reply" key to the
- // request, send a reply. We happen to know who originated
- // this request, and the reply LLEventPump of interest.
- // Not our problem if the plugin ignores the reply event.
- data["reply"] = mReplyPump.getName();
- sendReply(llsd::map("error",
- stringize(LLError::Log::classname(err), ": ", err.what())),
- data);
+ bad_protocol("unparseable LLSD data");
+ break;
}
- // Block calls to this method; resetting mBlocker unblocks
- // calls to the other method.
- mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection));
- // Go check for any more pending events in the buffer.
- if (childout.size())
+ else if (! (data.isMap() && data["pump"].isString() && data.has("data")))
{
- LLSD updata(data);
- data["len"] = LLSD::Integer(childout.size());
- rstdout(updata);
+ // we got an LLSD object, but it lacks required keys
+ bad_protocol("missing 'pump' or 'data'");
+ break;
+ }
+ else
+ {
+ try
+ {
+ // The LLSD object we got from our stream contains the
+ // keys we need.
+ LLEventPumps::instance().obtain(data["pump"]).post(data["data"]);
+ }
+ catch (const std::exception& err)
+ {
+ // No plugin should be allowed to crash the viewer by
+ // driving an exception -- intentionally or not.
+ LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data));
+ // Whether or not the plugin added a "reply" key to the
+ // request, send a reply. We happen to know who originated
+ // this request, and the reply LLEventPump of interest.
+ // Not our problem if the plugin ignores the reply event.
+ data["reply"] = mReplyPump.getName();
+ sendReply(llsd::map("error",
+ stringize(LLError::Log::classname(err), ": ", err.what())),
+ data);
+ }
+ // Transition to "read prefix" mode and go check for any
+ // more pending events in the buffer.
+ mReadPrefix = true;
+ continue;
}
}
}
@@ -453,7 +448,8 @@ private:
// child's stdin, suitably enriched with the pump name on which it was
// received.
return pump.listen(listener,
- boost::bind(&LLLeapImpl::wstdin, this, pump.getName(), _1));
+ [this, name=pump.getName()](const LLSD& data)
+ { return wstdin(name, data); });
}
std::string mDesc;
@@ -461,11 +457,11 @@ private:
LLEventStream mReplyPump;
LLProcessPtr mChild;
LLTempBoundListener
- mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection;
- std::unique_ptr mBlocker;
+ mStdinConnection, mStdoutConnection, mStderrConnection;
LLProcess::ReadPipe::size_type mExpect;
LLError::RecorderPtr mRecorder;
std::unique_ptr mListener;
+ bool mReadPrefix;
};
// These must follow the declaration of LLLeapImpl, so they may as well be last.
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 6bb5947dcd..4841174b10 100644
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -830,7 +830,7 @@ std::string utf8str_showBytesUTF8(const std::string& utf8str)
}
// Search for any emoji symbol, return true if found
-bool wstring_has_emoji(const LLWString& wstr)
+bool wstring_has_emoji(LLWStringView wstr)
{
for (const llwchar& wch : wstr)
{
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index 4c3433087d..0e70bf94d5 100644
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -763,7 +763,7 @@ LL_COMMON_API llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset
LL_COMMON_API std::string utf8str_showBytesUTF8(const std::string& utf8str);
-LL_COMMON_API bool wstring_has_emoji(const LLWString& wstr);
+LL_COMMON_API bool wstring_has_emoji(LLWStringView wstr);
LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr);
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 868f22d4c1..73f09bca25 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -361,14 +361,8 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
mGLReady = true;
}
- // initialzie DXGI adapter (for querying available VRAM)
- void initDX();
-
- // initialize D3D (if DXGI cannot be used)
- void initD3D();
-
- //clean up DXGI/D3D resources
- void cleanupDX();
+ // Use DXGI to check memory (because WMI doesn't report more than 4Gb)
+ void checkDXMem();
/// called by main thread to post work to this window thread
template
@@ -417,12 +411,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
// *HACK: Attempt to prevent startup crashes by deferring memory accounting
// until after some graphics setup. See SL-20177. -Cosmic,2023-09-18
bool mGLReady = false;
+ bool mGotGLBuffer = false;
U32 mMaxVRAM = 0; // maximum amount of vram to allow in the "budget", or 0 for no maximum (see updateVRAMUsage)
-
- IDXGIAdapter3* mDXGIAdapter = nullptr;
- LPDIRECT3D9 mD3D = nullptr;
- LPDIRECT3DDEVICE9 mD3DDevice = nullptr;
};
@@ -4742,39 +4733,55 @@ private:
std::string mPrev;
};
-// Print hardware debug info about available graphics adapters in ordinal order
-void debugEnumerateGraphicsAdapters()
+void LLWindowWin32::LLWindowWin32Thread::checkDXMem()
{
- LL_INFOS("Window") << "Enumerating graphics adapters..." << LL_ENDL;
+ if (!mGLReady || mGotGLBuffer) { return; }
- IDXGIFactory1* factory;
- HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory1), (void**)&factory);
- if (FAILED(res) || !factory)
+ IDXGIFactory4* p_factory = nullptr;
+
+ HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&p_factory);
+
+ if (FAILED(res))
{
LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL;
}
else
{
+ IDXGIAdapter3* p_dxgi_adapter = nullptr;
UINT graphics_adapter_index = 0;
- IDXGIAdapter3* dxgi_adapter;
while (true)
{
- res = factory->EnumAdapters(graphics_adapter_index, reinterpret_cast(&dxgi_adapter));
+ res = p_factory->EnumAdapters(graphics_adapter_index, reinterpret_cast(&p_dxgi_adapter));
if (FAILED(res))
{
if (graphics_adapter_index == 0)
{
LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL;
}
- else
- {
- LL_INFOS("Window") << "Done enumerating graphics adapters" << LL_ENDL;
- }
}
else
{
+ if (graphics_adapter_index == 0) // Should it check largest one isntead of first?
+ {
+ DXGI_QUERY_VIDEO_MEMORY_INFO info;
+ p_dxgi_adapter->QueryVideoMemoryInfo(0, DXGI_MEMORY_SEGMENT_GROUP_LOCAL, &info);
+
+ // Alternatively use GetDesc from below to get adapter's memory
+ UINT64 budget_mb = info.Budget / (1024 * 1024);
+ if (gGLManager.mVRAM < (S32)budget_mb)
+ {
+ gGLManager.mVRAM = (S32)budget_mb;
+ LL_INFOS("RenderInit") << "New VRAM Budget (DX9): " << gGLManager.mVRAM << " MB" << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("RenderInit") << "VRAM Budget (DX9): " << budget_mb
+ << " MB, current (WMI): " << gGLManager.mVRAM << " MB" << LL_ENDL;
+ }
+ }
+
DXGI_ADAPTER_DESC desc;
- dxgi_adapter->GetDesc(&desc);
+ p_dxgi_adapter->GetDesc(&desc);
std::wstring description_w((wchar_t*)desc.Description);
std::string description(description_w.begin(), description_w.end());
LL_INFOS("Window") << "Graphics adapter index: " << graphics_adapter_index << ", "
@@ -4787,10 +4794,10 @@ void debugEnumerateGraphicsAdapters()
<< "SharedSystemMemory: " << desc.SharedSystemMemory / 1024 / 1024 << LL_ENDL;
}
- if (dxgi_adapter)
+ if (p_dxgi_adapter)
{
- dxgi_adapter->Release();
- dxgi_adapter = NULL;
+ p_dxgi_adapter->Release();
+ p_dxgi_adapter = NULL;
}
else
{
@@ -4801,95 +4808,12 @@ void debugEnumerateGraphicsAdapters()
}
}
- if (factory)
+ if (p_factory)
{
- factory->Release();
- }
-}
-
-void LLWindowWin32::LLWindowWin32Thread::initDX()
-{
- if (!mGLReady) { return; }
-
- if (mDXGIAdapter == NULL)
- {
- debugEnumerateGraphicsAdapters();
-
- IDXGIFactory4* pFactory = nullptr;
-
- HRESULT res = CreateDXGIFactory1(__uuidof(IDXGIFactory4), (void**)&pFactory);
-
- if (FAILED(res))
- {
- LL_WARNS() << "CreateDXGIFactory1 failed: 0x" << std::hex << res << LL_ENDL;
- }
- else
- {
- res = pFactory->EnumAdapters(0, reinterpret_cast(&mDXGIAdapter));
- if (FAILED(res))
- {
- LL_WARNS() << "EnumAdapters failed: 0x" << std::hex << res << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "EnumAdapters success" << LL_ENDL;
- }
- }
-
- if (pFactory)
- {
- pFactory->Release();
- }
- }
-}
-
-void LLWindowWin32::LLWindowWin32Thread::initD3D()
-{
- if (!mGLReady) { return; }
-
- if (mDXGIAdapter == NULL && mD3DDevice == NULL && mWindowHandleThrd != 0)
- {
- mD3D = Direct3DCreate9(D3D_SDK_VERSION);
-
- D3DPRESENT_PARAMETERS d3dpp;
-
- ZeroMemory(&d3dpp, sizeof(d3dpp));
- d3dpp.Windowed = TRUE;
- d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
-
- HRESULT res = mD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, mWindowHandleThrd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &mD3DDevice);
-
- if (FAILED(res))
- {
- LL_WARNS() << "(fallback) CreateDevice failed: 0x" << std::hex << res << LL_ENDL;
- }
- else
- {
- LL_INFOS() << "(fallback) CreateDevice success" << LL_ENDL;
- }
- }
-}
-
-void LLWindowWin32::LLWindowWin32Thread::cleanupDX()
-{
- //clean up DXGI/D3D resources
- if (mDXGIAdapter)
- {
- mDXGIAdapter->Release();
- mDXGIAdapter = nullptr;
+ p_factory->Release();
}
- if (mD3DDevice)
- {
- mD3DDevice->Release();
- mD3DDevice = nullptr;
- }
-
- if (mD3D)
- {
- mD3D->Release();
- mD3D = nullptr;
- }
+ mGotGLBuffer = true;
}
void LLWindowWin32::LLWindowWin32Thread::run()
@@ -4908,15 +4832,11 @@ void LLWindowWin32::LLWindowWin32Thread::run()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
- // lazily call initD3D inside this loop to catch when mGLReady has been set to true
- initDX();
+ // Check memory budget using DirectX
+ checkDXMem();
if (mWindowHandleThrd != 0)
{
- // lazily call initD3D inside this loop to catch when mWindowHandle has been set, and mGLReady has been set to true
- // *TODO: Shutdown if this fails when mWindowHandle exists
- initD3D();
-
MSG msg;
BOOL status;
if (mhDCThrd == 0)
@@ -4956,8 +4876,6 @@ void LLWindowWin32::LLWindowWin32Thread::run()
}
#endif
}
-
- cleanupDX();
}
void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
@@ -5057,7 +4975,6 @@ void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
// very unsafe
TerminateThread(pair.second.native_handle(), 0);
pair.second.detach();
- cleanupDX();
}
}
LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index e30001d169..4c4fcc6eb9 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -12750,7 +12750,7 @@ Change of this parameter will affect the layout of buttons in notification toast
Comment
0 - complexity limit applies to everyone, 1 - always show friends, 2 - only show friends
Persist
- 0
+ 1
Type
S32
Value
diff --git a/indra/newview/fsfloaterwhitelisthelper.cpp b/indra/newview/fsfloaterwhitelisthelper.cpp
index 09b82b068c..e26df39b05 100644
--- a/indra/newview/fsfloaterwhitelisthelper.cpp
+++ b/indra/newview/fsfloaterwhitelisthelper.cpp
@@ -37,10 +37,10 @@ FSFloaterWhiteListHelper::FSFloaterWhiteListHelper(const LLSD& key) : LLFloater(
{
}
-BOOL FSFloaterWhiteListHelper::postBuild()
+bool FSFloaterWhiteListHelper::postBuild()
{
populateWhitelistInfo();
- return TRUE;
+ return true;
}
void FSFloaterWhiteListHelper::populateWhitelistInfo()
diff --git a/indra/newview/fsfloaterwhitelisthelper.h b/indra/newview/fsfloaterwhitelisthelper.h
index 6fe4f976e7..184e7d6462 100644
--- a/indra/newview/fsfloaterwhitelisthelper.h
+++ b/indra/newview/fsfloaterwhitelisthelper.h
@@ -36,7 +36,7 @@ public:
explicit FSFloaterWhiteListHelper(const LLSD& key);
~FSFloaterWhiteListHelper() final = default;
- BOOL postBuild() override final;
+ bool postBuild() override final;
private:
void populateWhitelistInfo();
diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp
index 573b6a20e0..e4238ac583 100644
--- a/indra/newview/llfloaterimsessiontab.cpp
+++ b/indra/newview/llfloaterimsessiontab.cpp
@@ -589,13 +589,13 @@ void LLFloaterIMSessionTab::appendMessage(const LLChat& chat, const LLSD& args)
mChatHistory->appendMessage(chat, chat_args);
}
-void LLFloaterIMSessionTab::updateUsedEmojis(LLWString text)
+void LLFloaterIMSessionTab::updateUsedEmojis(LLWStringView text)
{
LLEmojiDictionary* dictionary = LLEmojiDictionary::getInstance();
llassert_always(dictionary);
bool emojiSent = false;
- for (llwchar& c : text)
+ for (const llwchar& c : text)
{
if (dictionary->isEmoji(c))
{
diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h
index d64e5409ad..d0fddeb845 100644
--- a/indra/newview/llfloaterimsessiontab.h
+++ b/indra/newview/llfloaterimsessiontab.h
@@ -149,7 +149,7 @@ protected:
std::string appendTime();
void assignResizeLimits();
- void updateUsedEmojis(LLWString text);
+ void updateUsedEmojis(LLWStringView text);
S32 mFloaterExtraWidth;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index dcefb6ac50..978294860f 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -1362,27 +1362,35 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
// Texture
{
- mIsAlpha = false;
LLGLenum image_format = GL_RGB;
bool identical_image_format = false;
- LLSelectedTE::getImageFormat(image_format, identical_image_format);
+ bool missing_asset = false;
+ LLSelectedTE::getImageFormat(image_format, identical_image_format, missing_asset);
- mIsAlpha = false;
- switch (image_format)
+ if (!missing_asset)
{
+ mIsAlpha = false;
+ switch (image_format)
+ {
case GL_RGBA:
case GL_ALPHA:
- {
- mIsAlpha = true;
- }
- break;
+ {
+ mIsAlpha = true;
+ }
+ break;
case GL_RGB: break;
default:
- {
- LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
+ {
+ LL_WARNS() << "Unexpected tex format in LLPanelFace...resorting to no alpha" << LL_ENDL;
+ }
+ break;
}
- break;
+ }
+ else
+ {
+ // Don't know image's properties, use material's mode value
+ mIsAlpha = true;
}
if (LLViewerMedia::getInstance()->textureHasMedia(id))
@@ -1428,10 +1436,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
mTextureCtrl->setTentative(false);
mTextureCtrl->setEnabled(editable && !has_pbr_material);
mTextureCtrl->setImageAssetID(id);
- getChildView("combobox alphamode")->setEnabled(editable && mIsAlpha && transparency <= 0.f && !has_pbr_material);
- getChildView("label alphamode")->setEnabled(editable && mIsAlpha && !has_pbr_material);
- getChildView("maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
- getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
+
+ bool can_change_alpha = editable && mIsAlpha && !missing_asset && !has_pbr_material;
+ getChildView("combobox alphamode")->setEnabled(can_change_alpha && transparency <= 0.f);
+ getChildView("label alphamode")->setEnabled(can_change_alpha);
+ getChildView("maskcutoff")->setEnabled(can_change_alpha);
+ getChildView("label maskcutoff")->setEnabled(can_change_alpha);
mTextureCtrl->setBakeTextureEnabled(true);
}
@@ -1454,10 +1464,12 @@ void LLPanelFace::updateUI(bool force_set_values /*false*/)
mTextureCtrl->setTentative(true);
mTextureCtrl->setEnabled(editable && !has_pbr_material);
mTextureCtrl->setImageAssetID(id);
- getChildView("combobox alphamode")->setEnabled(editable && mIsAlpha && transparency <= 0.f && !has_pbr_material);
- getChildView("label alphamode")->setEnabled(editable && mIsAlpha && !has_pbr_material);
- getChildView("maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
- getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha && !has_pbr_material);
+
+ bool can_change_alpha = editable && mIsAlpha && !missing_asset && !has_pbr_material;
+ getChildView("combobox alphamode")->setEnabled(can_change_alpha && transparency <= 0.f);
+ getChildView("label alphamode")->setEnabled(can_change_alpha);
+ getChildView("maskcutoff")->setEnabled(can_change_alpha);
+ getChildView("label maskcutoff")->setEnabled(can_change_alpha);
mTextureCtrl->setBakeTextureEnabled(true);
}
@@ -3507,13 +3519,14 @@ void LLPanelFace::onSelectTexture(const LLSD& data)
LLGLenum image_format;
bool identical_image_format = false;
- LLSelectedTE::getImageFormat(image_format, identical_image_format);
+ bool missing_asset = false;
+ LLSelectedTE::getImageFormat(image_format, identical_image_format, missing_asset);
LLCtrlSelectionInterface* combobox_alphamode =
childGetSelectionInterface("combobox alphamode");
U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
- if (combobox_alphamode)
+ if (combobox_alphamode && !missing_asset)
{
switch (image_format)
{
@@ -5438,19 +5451,51 @@ void LLPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical
identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return, false, (LLFace*)nullptr);
}
-void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face)
+void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face, bool& missing_asset)
{
- LLGLenum image_format{ GL_RGB };
- struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor
+ struct LLSelectedTEGetmatId : public LLSelectedTEFunctor
{
- LLGLenum get(LLViewerObject* object, S32 te_index)
+ LLSelectedTEGetmatId()
+ : mImageFormat(GL_RGB)
+ , mIdentical(true)
+ , mMissingAsset(false)
+ , mFirstRun(true)
{
- LLViewerTexture* image = object->getTEImage(te_index);
- return image ? image->getPrimaryFormat() : GL_RGB;
}
- } get_glenum;
- identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_glenum, image_format);
- image_format_to_return = image_format;
+ bool apply(LLViewerObject* object, S32 te_index) override
+ {
+ LLViewerTexture* image = object ? object->getTEImage(te_index) : nullptr;
+ LLGLenum format = GL_RGB;
+ bool missing = false;
+ if (image)
+ {
+ format = image->getPrimaryFormat();
+ missing = image->isMissingAsset();
+ }
+
+ if (mFirstRun)
+ {
+ mFirstRun = false;
+ mImageFormat = format;
+ mMissingAsset = missing;
+ }
+ else
+ {
+ mIdentical &= (mImageFormat == format);
+ mIdentical &= (mMissingAsset == missing);
+ }
+ return true;
+ }
+ LLGLenum mImageFormat;
+ bool mIdentical;
+ bool mMissingAsset;
+ bool mFirstRun;
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
+
+ image_format_to_return = func.mImageFormat;
+ identical_face = func.mIdentical;
+ missing_asset = func.mMissingAsset;
}
void LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 3db4bdbc26..61a6f9f97e 100644
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -664,7 +664,7 @@ public:
{
public:
static void getFace(class LLFace*& face_to_return, bool& identical_face);
- static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
+ static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face, bool& missing_asset);
static void getTexId(LLUUID& id, bool& identical);
static void getPbrMaterialId(LLUUID& id, bool& identical, bool& has_pbr, bool& has_faces_without_pbr);
static void getObjectScaleS(F32& scale_s, bool& identical);
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index c54b1893a5..3b7d3b42d1 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -9021,9 +9021,11 @@ bool LLVOAvatar::shouldRenderRigged() const
// Maybe better naming could make this clearer?
bool LLVOAvatar::isVisible() const
{
+ static LLCachedControl friends_only(gSavedSettings, "RenderAvatarFriendsOnly", false);
return mDrawable.notNull()
&& (!mOrphaned || isSelf())
- && (mDrawable->isVisible() || mIsDummy);
+ && (mDrawable->isVisible() || mIsDummy)
+ && (!friends_only() || isUIAvatar() || isSelf() || isControlAvatar() || isBuddy());
}
// Determine if we have enough avatar data to render