Merge branch 'DRTVWR-600-maint-A' of https://github.com/secondlife/viewer
# Conflicts: # .gitattributes # indra/cmake/Copy3rdPartyLibs.cmake # indra/newview/llpanelface.cppmaster
commit
1fda083f6c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -124,7 +124,6 @@ if(WINDOWS)
|
|||
MESSAGE(WARNING "New MSVC_VERSION ${MSVC_VERSION} of MSVC: adapt Copy3rdPartyLibs.cmake")
|
||||
endif (MSVC80)
|
||||
|
||||
# <FS:Ansariel> 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})
|
||||
# </FS:Ansariel>
|
||||
|
||||
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
|
||||
)
|
||||
# <FS:Ansariel> 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})
|
||||
# </FS:Ansariel>
|
||||
elseif(EXISTS "${registry_path}/${release_msvc_file}")
|
||||
MESSAGE(STATUS "Copying redist file from ${registry_path}/${release_msvc_file}")
|
||||
to_staging_dirs(
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@
|
|||
#include <algorithm>
|
||||
// std headers
|
||||
// external library headers
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
// 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<LLSDParser> 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<LLSDParser> 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<LLEventPump::Blocker> mBlocker;
|
||||
mStdinConnection, mStdoutConnection, mStderrConnection;
|
||||
LLProcess::ReadPipe::size_type mExpect;
|
||||
LLError::RecorderPtr mRecorder;
|
||||
std::unique_ptr<LLLeapListener> mListener;
|
||||
bool mReadPrefix;
|
||||
};
|
||||
|
||||
// These must follow the declaration of LLLeapImpl, so they may as well be last.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <typename CALLABLE>
|
||||
|
|
@ -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<IDXGIAdapter**>(&dxgi_adapter));
|
||||
res = p_factory->EnumAdapters(graphics_adapter_index, reinterpret_cast<IDXGIAdapter**>(&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<IDXGIAdapter**>(&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;
|
||||
|
|
|
|||
|
|
@ -12750,7 +12750,7 @@ Change of this parameter will affect the layout of buttons in notification toast
|
|||
<key>Comment</key>
|
||||
<string>0 - complexity limit applies to everyone, 1 - always show friends, 2 - only show friends</string>
|
||||
<key>Persist</key>
|
||||
<integer>0</integer>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>S32</string>
|
||||
<key>Value</key>
|
||||
|
|
|
|||
|
|
@ -37,10 +37,10 @@ FSFloaterWhiteListHelper::FSFloaterWhiteListHelper(const LLSD& key) : LLFloater(
|
|||
{
|
||||
}
|
||||
|
||||
BOOL FSFloaterWhiteListHelper::postBuild()
|
||||
bool FSFloaterWhiteListHelper::postBuild()
|
||||
{
|
||||
populateWhitelistInfo();
|
||||
return TRUE;
|
||||
return true;
|
||||
}
|
||||
|
||||
void FSFloaterWhiteListHelper::populateWhitelistInfo()
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public:
|
|||
explicit FSFloaterWhiteListHelper(const LLSD& key);
|
||||
~FSFloaterWhiteListHelper() final = default;
|
||||
|
||||
BOOL postBuild() override final;
|
||||
bool postBuild() override final;
|
||||
|
||||
private:
|
||||
void populateWhitelistInfo();
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ protected:
|
|||
std::string appendTime();
|
||||
void assignResizeLimits();
|
||||
|
||||
void updateUsedEmojis(LLWString text);
|
||||
void updateUsedEmojis(LLWStringView text);
|
||||
|
||||
S32 mFloaterExtraWidth;
|
||||
|
||||
|
|
|
|||
|
|
@ -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<LLGLenum>
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -9021,9 +9021,11 @@ bool LLVOAvatar::shouldRenderRigged() const
|
|||
// Maybe better naming could make this clearer?
|
||||
bool LLVOAvatar::isVisible() const
|
||||
{
|
||||
static LLCachedControl<bool> 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
|
||||
|
|
|
|||
Loading…
Reference in New Issue