Merge branch 'DRTVWR-588-maint-W' of https://github.com/secondlife/viewer
# Conflicts: # indra/llui/llurlregistry.cpp # indra/newview/llcontrolavatar.cppmaster
commit
c63b3eca4c
|
|
@ -25,6 +25,7 @@ jobs:
|
|||
viewer_channel: ${{ steps.build.outputs.viewer_channel }}
|
||||
viewer_version: ${{ steps.build.outputs.viewer_version }}
|
||||
viewer_branch: ${{ steps.which-branch.outputs.branch }}
|
||||
relnotes: ${{ steps.which-branch.outputs.relnotes }}
|
||||
imagename: ${{ steps.build.outputs.imagename }}
|
||||
env:
|
||||
AUTOBUILD_ADDRSIZE: 64
|
||||
|
|
@ -102,7 +103,7 @@ jobs:
|
|||
|
||||
- name: Determine source branch
|
||||
id: which-branch
|
||||
uses: secondlife/viewer-build-util/which-branch@v1
|
||||
uses: secondlife/viewer-build-util/which-branch@relnotes
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
|
||||
|
|
@ -366,24 +367,31 @@ jobs:
|
|||
mv newview/viewer_version.txt macOS-viewer_version.txt
|
||||
|
||||
# forked from softprops/action-gh-release
|
||||
- uses: secondlife-3p/action-gh-release@v1
|
||||
- name: Create GitHub release
|
||||
id: release
|
||||
uses: secondlife-3p/action-gh-release@v1
|
||||
with:
|
||||
# name the release page for the build number so we can find it
|
||||
# easily (analogous to looking up a codeticket build page)
|
||||
name: "v${{ github.run_id }}"
|
||||
# name the release page for the branch
|
||||
name: "${{ needs.build.outputs.viewer_branch }}"
|
||||
# SL-20546: want the channel and version to be visible on the
|
||||
# release page
|
||||
body: |
|
||||
Build ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
${{ needs.build.outputs.viewer_channel }}
|
||||
${{ needs.build.outputs.viewer_version }}
|
||||
${{ needs.build.outputs.viewer_branch }}
|
||||
${{ needs.build.outputs.relnotes }}
|
||||
prerelease: true
|
||||
generate_release_notes: true
|
||||
target_commitish: ${{ github.sha }}
|
||||
previous_tag: release
|
||||
append_body: true
|
||||
# the only reason we generate a GH release is to post build products
|
||||
fail_on_unmatched_files: true
|
||||
files: |
|
||||
*.dmg
|
||||
*.exe
|
||||
*-autobuild-package.xml
|
||||
*-viewer_version.txt
|
||||
|
||||
- name: post release URL
|
||||
run: |
|
||||
echo "::notice::Release ${{ steps.release.outputs.url }}"
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ std::string LLBase64::encode(const U8* input, size_t input_size)
|
|||
&& input_size > 0)
|
||||
{
|
||||
// Yes, it returns int.
|
||||
int b64_buffer_length = apr_base64_encode_len(narrow(input_size));
|
||||
int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(input_size));
|
||||
char* b64_buffer = new char[b64_buffer_length];
|
||||
|
||||
// This is faster than apr_base64_encode() if you know
|
||||
|
|
@ -52,7 +52,7 @@ std::string LLBase64::encode(const U8* input, size_t input_size)
|
|||
b64_buffer_length = apr_base64_encode_binary(
|
||||
b64_buffer,
|
||||
input,
|
||||
narrow(input_size));
|
||||
narrow<size_t>(input_size));
|
||||
output.assign(b64_buffer);
|
||||
delete[] b64_buffer;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ inline F32 ll_internal_random<F32>()
|
|||
// Per Monty, it's important to clamp using the correct fmodf() rather
|
||||
// than expanding to F64 for fmod() and then truncating back to F32. Prior
|
||||
// to this change, we were getting sporadic ll_frand() == 1.0 results.
|
||||
F32 rv{ narrow(gRandomGenerator()) };
|
||||
F32 rv{ narrow<F32>(gRandomGenerator()) };
|
||||
if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f);
|
||||
return rv;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,12 +197,12 @@ public:
|
|||
typename std::enable_if<std::is_integral<VALUE>::value &&
|
||||
! std::is_same<VALUE, Boolean>::value,
|
||||
bool>::type = true>
|
||||
LLSD(VALUE v): LLSD(Integer(narrow(v))) {}
|
||||
LLSD(VALUE v): LLSD(Integer(narrow<VALUE>(v))) {}
|
||||
// support construction from F32 et al.
|
||||
template <typename VALUE,
|
||||
typename std::enable_if<std::is_floating_point<VALUE>::value,
|
||||
bool>::type = true>
|
||||
LLSD(VALUE v): LLSD(Real(narrow(v))) {}
|
||||
LLSD(VALUE v): LLSD(Real(narrow<VALUE>(v))) {}
|
||||
//@}
|
||||
|
||||
/** @name Scalar Assignment */
|
||||
|
|
|
|||
|
|
@ -2174,7 +2174,7 @@ std::string zip_llsd(LLSD& data)
|
|||
|
||||
U8 out[CHUNK];
|
||||
|
||||
strm.avail_in = narrow(source.size());
|
||||
strm.avail_in = narrow<size_t>(source.size());
|
||||
strm.next_in = (U8*) source.data();
|
||||
U8* output = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -197,12 +197,12 @@ S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr,
|
|||
// *FIX: memory inefficient.
|
||||
// *TODO: convert to use LLBase64
|
||||
ostr << pre << "<binary encoding=\"base64\">";
|
||||
int b64_buffer_length = apr_base64_encode_len(narrow(buffer.size()));
|
||||
int b64_buffer_length = apr_base64_encode_len(narrow<size_t>(buffer.size()));
|
||||
char* b64_buffer = new char[b64_buffer_length];
|
||||
b64_buffer_length = apr_base64_encode_binary(
|
||||
b64_buffer,
|
||||
&buffer[0],
|
||||
narrow(buffer.size()));
|
||||
narrow<size_t>(buffer.size()));
|
||||
ostr.write(b64_buffer, b64_buffer_length - 1);
|
||||
delete[] b64_buffer;
|
||||
ostr << "</binary>" << post;
|
||||
|
|
@ -415,11 +415,18 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
|
|||
if (buffer)
|
||||
{
|
||||
((char*) buffer)[count ? count - 1 : 0] = '\0';
|
||||
if (mEmitErrors)
|
||||
{
|
||||
LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*)buffer << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (mEmitErrors)
|
||||
{
|
||||
LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mEmitErrors)
|
||||
{
|
||||
LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR, null buffer" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
data = LLSD();
|
||||
return LLSDParser::PARSE_FAILURE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -929,7 +929,7 @@ void LLMemoryInfo::stream(std::ostream& s) const
|
|||
// Now stream stats
|
||||
BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap))
|
||||
{
|
||||
s << pfx << std::setw(narrow(key_width+1)) << (pair.first + ':') << ' ';
|
||||
s << pfx << std::setw(narrow<size_t>(key_width+1)) << (pair.first + ':') << ' ';
|
||||
LLSD value(pair.second);
|
||||
if (value.isInteger())
|
||||
s << std::setw(12) << value.asInteger();
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent )
|
|||
llassert_always(parent != mBlock);
|
||||
llassert_always(parent != NULL);
|
||||
|
||||
TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow(parent->getIndex()));
|
||||
TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow<size_t>(parent->getIndex()));
|
||||
if (!parent_tree_node) return;
|
||||
|
||||
if (mParent)
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ void AccumulatorBufferGroup::makeCurrent()
|
|||
// update stacktimer parent pointers
|
||||
for (size_t i = 0, end_i = mStackTimers.size(); i < end_i; i++)
|
||||
{
|
||||
TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow(i));
|
||||
TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow<size_t>(i));
|
||||
if (tree_node)
|
||||
{
|
||||
timer_accumulator_buffer[i].mParent = tree_node->mParent;
|
||||
|
|
|
|||
|
|
@ -164,8 +164,10 @@ void LLUriParser::extractParts()
|
|||
#if LL_DARWIN
|
||||
typedef void(*sighandler_t)(int);
|
||||
jmp_buf return_to_normalize;
|
||||
static int sLastSignal = 0;
|
||||
void uri_signal_handler(int signal)
|
||||
{
|
||||
sLastSignal = signal;
|
||||
// Apparently signal handler throwing an exception doesn't work.
|
||||
// This is ugly and unsafe due to not unwinding content of uriparser library,
|
||||
// but unless we have a way to catch this as NSexception, jump appears to be the only option.
|
||||
|
|
@ -179,8 +181,10 @@ S32 LLUriParser::normalize()
|
|||
if (!mRes)
|
||||
{
|
||||
#if LL_DARWIN
|
||||
sighandler_t last_handler;
|
||||
last_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction
|
||||
sighandler_t last_sigill_handler, last_sigbus_handler;
|
||||
last_sigill_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction
|
||||
last_sigbus_handler = signal(SIGBUS, &uri_signal_handler);
|
||||
|
||||
if (setjmp(return_to_normalize))
|
||||
{
|
||||
// Issue: external library crashed via signal
|
||||
|
|
@ -194,8 +198,9 @@ S32 LLUriParser::normalize()
|
|||
// if this can be handled by NSexception, it needs to be remade
|
||||
llassert(0);
|
||||
|
||||
LL_WARNS() << "Uriparser crashed with SIGILL, while processing: " << mNormalizedUri << LL_ENDL;
|
||||
signal(SIGILL, last_handler);
|
||||
LL_WARNS() << "Uriparser crashed with " << sLastSignal << " , while processing: " << mNormalizedUri << LL_ENDL;
|
||||
signal(SIGILL, last_sigill_handler);
|
||||
signal(SIGBUS, last_sigbus_handler);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -203,7 +208,8 @@ S32 LLUriParser::normalize()
|
|||
mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST);
|
||||
|
||||
#if LL_DARWIN
|
||||
signal(SIGILL, last_handler);
|
||||
signal(SIGILL, last_sigill_handler);
|
||||
signal(SIGBUS, last_sigbus_handler);
|
||||
#endif
|
||||
|
||||
if (!mRes)
|
||||
|
|
@ -226,7 +232,7 @@ S32 LLUriParser::normalize()
|
|||
}
|
||||
}
|
||||
|
||||
if(mTmpScheme)
|
||||
if(mTmpScheme && mNormalizedUri.size() > 7)
|
||||
{
|
||||
mNormalizedUri = mNormalizedUri.substr(7);
|
||||
mTmpScheme = false;
|
||||
|
|
|
|||
|
|
@ -121,8 +121,11 @@ void LL::ThreadPoolBase::close()
|
|||
mQueue->close();
|
||||
for (auto& pair: mThreads)
|
||||
{
|
||||
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
|
||||
pair.second.join();
|
||||
if (pair.second.joinable())
|
||||
{
|
||||
LL_DEBUGS("ThreadPool") << mName << " waiting on thread " << pair.first << LL_ENDL;
|
||||
pair.second.join();
|
||||
}
|
||||
}
|
||||
LL_DEBUGS("ThreadPool") << mName << " shutdown complete" << LL_ENDL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ namespace LL
|
|||
|
||||
protected:
|
||||
std::unique_ptr<WorkQueueBase> mQueue;
|
||||
std::vector<std::pair<std::string, std::thread>> mThreads;
|
||||
bool mAutomaticShutdown;
|
||||
|
||||
private:
|
||||
|
|
@ -94,7 +95,6 @@ namespace LL
|
|||
|
||||
std::string mName;
|
||||
size_t mThreadCount;
|
||||
std::vector<std::pair<std::string, std::thread>> mThreads;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -288,7 +288,7 @@ int BufferArray::findBlock(size_t pos, size_t * ret_offset)
|
|||
if (pos >= mLen)
|
||||
return -1; // Doesn't exist
|
||||
|
||||
const int block_limit(narrow(mBlocks.size()));
|
||||
const int block_limit(narrow<size_t>(mBlocks.size()));
|
||||
for (int i(0); i < block_limit; ++i)
|
||||
{
|
||||
if (pos < mBlocks[i]->mUsed)
|
||||
|
|
|
|||
|
|
@ -5630,9 +5630,9 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
|||
|
||||
U32 stream_count = data.w.empty() ? 4 : 5;
|
||||
|
||||
U32 vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count);
|
||||
size_t vert_count = meshopt_generateVertexRemapMulti(&remap[0], nullptr, data.p.size(), data.p.size(), mos, stream_count);
|
||||
|
||||
if (vert_count < 65535)
|
||||
if (vert_count < 65535 && vert_count != 0)
|
||||
{
|
||||
std::vector<U32> indices;
|
||||
indices.resize(mNumIndices);
|
||||
|
|
@ -5651,6 +5651,13 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
|||
{
|
||||
U32 src_idx = i;
|
||||
U32 dst_idx = remap[i];
|
||||
if (dst_idx >= mNumVertices)
|
||||
{
|
||||
dst_idx = mNumVertices - 1;
|
||||
// Shouldn't happen, figure out what gets returned in remap and why.
|
||||
llassert(false);
|
||||
LL_DEBUGS_ONCE("LLVOLUME") << "Invalid destination index, substituting" << LL_ENDL;
|
||||
}
|
||||
mIndices[i] = dst_idx;
|
||||
|
||||
mPositions[dst_idx].load3(data.p[src_idx].mV);
|
||||
|
|
@ -5684,6 +5691,10 @@ bool LLVolumeFace::cacheOptimize(bool gen_tangents)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (vert_count == 0)
|
||||
{
|
||||
LL_WARNS_ONCE("LLVOLUME") << "meshopt_generateVertexRemapMulti failed to process a model or model was invalid" << LL_ENDL;
|
||||
}
|
||||
// blew past the max vertex size limit, use legacy tangent generation which never adds verts
|
||||
createTangents();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,14 +237,20 @@ bool LLUrlEntryBase::isWikiLinkCorrect(const std::string &labeled_url) const
|
|||
|
||||
std::string LLUrlEntryBase::urlToLabelWithGreyQuery(const std::string &url) const
|
||||
{
|
||||
if (url.empty())
|
||||
{
|
||||
return url;
|
||||
}
|
||||
LLUriParser up(escapeUrl(url));
|
||||
up.normalize();
|
||||
if (up.normalize() == 0)
|
||||
{
|
||||
std::string label;
|
||||
up.extractParts();
|
||||
up.glueFirst(label);
|
||||
|
||||
std::string label;
|
||||
up.extractParts();
|
||||
up.glueFirst(label);
|
||||
|
||||
return unescapeUrl(label);
|
||||
return unescapeUrl(label);
|
||||
}
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string LLUrlEntryBase::urlToGreyQuery(const std::string &url) const
|
||||
|
|
|
|||
|
|
@ -293,16 +293,18 @@ bool LLUrlRegistry::findUrl(const std::string &text, LLUrlMatch &match, const LL
|
|||
//if (match_entry == mUrlEntryTrusted)
|
||||
//{
|
||||
// LLUriParser up(url);
|
||||
// up.normalize();
|
||||
// url = up.normalizedUri();
|
||||
// if (up.normalize() == 0)
|
||||
// {
|
||||
// url = up.normalizedUri();
|
||||
// }
|
||||
//}
|
||||
if (match_entry != mUrlEntryNoLink && match_entry == mUrlEntryTrustedUrl)
|
||||
{
|
||||
LLUriParser up(url);
|
||||
if (!up.normalize())
|
||||
{
|
||||
url = up.normalizedUri();
|
||||
}
|
||||
if (up.normalize() == 0)
|
||||
{
|
||||
url = up.normalizedUri();
|
||||
}
|
||||
}
|
||||
// </FS:Ansariel>
|
||||
|
||||
|
|
|
|||
|
|
@ -352,6 +352,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
|
|||
|
||||
void run() override;
|
||||
|
||||
// closes queue, wakes thread, waits until thread closes
|
||||
void wakeAndDestroy();
|
||||
|
||||
void glReady()
|
||||
{
|
||||
mGLReady = true;
|
||||
|
|
@ -363,6 +366,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool
|
|||
// initialize D3D (if DXGI cannot be used)
|
||||
void initD3D();
|
||||
|
||||
//clean up DXGI/D3D resources
|
||||
void cleanupDX();
|
||||
|
||||
// call periodically to update available VRAM
|
||||
void updateVRAMUsage();
|
||||
|
||||
|
|
@ -989,47 +995,10 @@ void LLWindowWin32::close()
|
|||
|
||||
LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL;
|
||||
|
||||
mWindowThread->post([this, self = mWindowThread]()
|
||||
{
|
||||
if (IsWindow(self->mWindowHandleThrd))
|
||||
{
|
||||
if (self->mhDCThrd)
|
||||
{
|
||||
if (!ReleaseDC(self->mWindowHandleThrd, self->mhDCThrd))
|
||||
{
|
||||
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't leave a blank toolbar button.
|
||||
ShowWindow(self->mWindowHandleThrd, SW_HIDE);
|
||||
|
||||
// This causes WM_DESTROY to be sent *immediately*
|
||||
if (!destroy_window_handler(self->mWindowHandleThrd))
|
||||
{
|
||||
OSMessageBox(mCallbacks->translateString("MBDestroyWinFailed"),
|
||||
mCallbacks->translateString("MBShutdownErr"),
|
||||
OSMB_OK);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something killed the window while we were busy destroying gl or handle somehow got broken
|
||||
LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
|
||||
}
|
||||
self->mWindowHandleThrd = NULL;
|
||||
self->mhDCThrd = NULL;
|
||||
self->mGLReady = false;
|
||||
});
|
||||
|
||||
mhDC = NULL;
|
||||
mWindowHandle = NULL;
|
||||
|
||||
// Window thread might be waiting for a getMessage(), give it
|
||||
// a push to enshure it will process destroy_window_handler
|
||||
kickWindowThread();
|
||||
|
||||
mWindowThread->close();
|
||||
mWindowThread->wakeAndDestroy();
|
||||
}
|
||||
|
||||
BOOL LLWindowWin32::isValid()
|
||||
|
|
@ -4882,6 +4851,28 @@ void LLWindowWin32::LLWindowWin32Thread::initD3D()
|
|||
}
|
||||
}
|
||||
|
||||
void LLWindowWin32::LLWindowWin32Thread::cleanupDX()
|
||||
{
|
||||
//clean up DXGI/D3D resources
|
||||
if (mDXGIAdapter)
|
||||
{
|
||||
mDXGIAdapter->Release();
|
||||
mDXGIAdapter = nullptr;
|
||||
}
|
||||
|
||||
if (mD3DDevice)
|
||||
{
|
||||
mD3DDevice->Release();
|
||||
mD3DDevice = nullptr;
|
||||
}
|
||||
|
||||
if (mD3D)
|
||||
{
|
||||
mD3D->Release();
|
||||
mD3D = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LLWindowWin32::LLWindowWin32Thread::updateVRAMUsage()
|
||||
{
|
||||
LL_PROFILE_ZONE_SCOPED;
|
||||
|
|
@ -5027,25 +5018,109 @@ void LLWindowWin32::LLWindowWin32Thread::run()
|
|||
#endif
|
||||
}
|
||||
|
||||
//clean up DXGI/D3D resources
|
||||
if (mDXGIAdapter)
|
||||
cleanupDX();
|
||||
}
|
||||
|
||||
void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy()
|
||||
{
|
||||
if (mQueue->isClosed())
|
||||
{
|
||||
mDXGIAdapter->Release();
|
||||
mDXGIAdapter = nullptr;
|
||||
LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." <<LL_ENDL;
|
||||
}
|
||||
|
||||
if (mD3DDevice)
|
||||
// Make sure we don't leave a blank toolbar button.
|
||||
// Also hiding window now prevents user from suspending it
|
||||
// via some action (like dragging it around)
|
||||
ShowWindow(mWindowHandleThrd, SW_HIDE);
|
||||
|
||||
// Schedule destruction
|
||||
HWND old_handle = mWindowHandleThrd;
|
||||
post([this]()
|
||||
{
|
||||
if (IsWindow(mWindowHandleThrd))
|
||||
{
|
||||
if (mhDCThrd)
|
||||
{
|
||||
if (!ReleaseDC(mWindowHandleThrd, mhDCThrd))
|
||||
{
|
||||
LL_WARNS("Window") << "Release of ghDC failed!" << LL_ENDL;
|
||||
}
|
||||
mhDCThrd = NULL;
|
||||
}
|
||||
|
||||
// This causes WM_DESTROY to be sent *immediately*
|
||||
if (!destroy_window_handler(mWindowHandleThrd))
|
||||
{
|
||||
LL_WARNS("Window") << "Failed to destroy Window! " << std::hex << GetLastError() << LL_ENDL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something killed the window while we were busy destroying gl or handle somehow got broken
|
||||
LL_WARNS("Window") << "Failed to destroy Window, invalid handle!" << LL_ENDL;
|
||||
}
|
||||
mWindowHandleThrd = NULL;
|
||||
mhDCThrd = NULL;
|
||||
mGLReady = false;
|
||||
});
|
||||
|
||||
LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL;
|
||||
mQueue->close();
|
||||
|
||||
// Post a nonsense user message to wake up the thread in
|
||||
// case it is waiting for a getMessage()
|
||||
if (old_handle)
|
||||
{
|
||||
mD3DDevice->Release();
|
||||
mD3DDevice = nullptr;
|
||||
WPARAM wparam{ 0xB0B0 };
|
||||
LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle
|
||||
<< ", " << WM_DUMMY_
|
||||
<< ", " << wparam << ")" << std::dec << LL_ENDL;
|
||||
PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337);
|
||||
}
|
||||
|
||||
if (mD3D)
|
||||
// There are cases where window will refuse to close,
|
||||
// can't wait forever on join, check state instead
|
||||
LLTimer timeout;
|
||||
timeout.setTimerExpirySec(2.0);
|
||||
while (!getQueue().done() && !timeout.hasExpired() && mWindowHandleThrd)
|
||||
{
|
||||
mD3D->Release();
|
||||
mD3D = nullptr;
|
||||
ms_sleep(100);
|
||||
}
|
||||
|
||||
if (getQueue().done() || mWindowHandleThrd == NULL)
|
||||
{
|
||||
// Window is closed, started closing or is cleaning up
|
||||
// now wait for our single thread to die.
|
||||
if (mWindowHandleThrd)
|
||||
{
|
||||
LL_INFOS("Window") << "Window is closing, waiting on pool's thread to join, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("Window") << "Waiting on pool's thread, time since post: " << timeout.getElapsedSeconds() << "s" << LL_ENDL;
|
||||
}
|
||||
for (auto& pair : mThreads)
|
||||
{
|
||||
pair.second.join();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Something suspended window thread, can't afford to wait forever
|
||||
// so kill thread instead
|
||||
// Ex: This can happen if user starts dragging window arround (if it
|
||||
// was visible) or a modal notification pops up
|
||||
LL_WARNS("Window") << "Window is frozen, couldn't perform clean exit" << LL_ENDL;
|
||||
|
||||
for (auto& pair : mThreads)
|
||||
{
|
||||
// very unsafe
|
||||
TerminateThread(pair.second.native_handle(), 0);
|
||||
pair.second.detach();
|
||||
cleanupDX();
|
||||
}
|
||||
}
|
||||
LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL;
|
||||
}
|
||||
|
||||
void LLWindowWin32::post(const std::function<void()>& func)
|
||||
|
|
|
|||
|
|
@ -101,7 +101,6 @@ LLVOAvatar *LLControlAvatar::getAttachedAvatar()
|
|||
|
||||
void LLControlAvatar::getNewConstraintFixups(LLVector3& new_pos_fixup, F32& new_scale_fixup) const
|
||||
{
|
||||
|
||||
F32 max_legal_offset = MAX_LEGAL_OFFSET;
|
||||
if (gSavedSettings.getControl("AnimatedObjectsMaxLegalOffset"))
|
||||
{
|
||||
|
|
@ -364,6 +363,9 @@ LLControlAvatar *LLControlAvatar::createControlAvatar(LLVOVolume *obj)
|
|||
void LLControlAvatar::markForDeath()
|
||||
{
|
||||
mMarkedForDeath = true;
|
||||
// object unlinked cav and might be dead already
|
||||
// might need to clean mControlAVBridge here as well
|
||||
mRootVolp = NULL;
|
||||
mVolumep = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -443,7 +445,7 @@ void LLControlAvatar::updateDebugText()
|
|||
F32 streaming_cost = 0.f;
|
||||
std::string cam_dist_string = "";
|
||||
S32 cam_dist_count = 0;
|
||||
F32 lod_radius = mRootVolp->mLODRadius;
|
||||
F32 lod_radius = mRootVolp ? mRootVolp->mLODRadius : 0.f;
|
||||
|
||||
for (std::vector<LLVOVolume*>::iterator it = volumes.begin();
|
||||
it != volumes.end(); ++it)
|
||||
|
|
|
|||
|
|
@ -603,8 +603,12 @@ void LLInventoryAddItemByAssetObserver::changed(U32 mask)
|
|||
for (uuid_set_t::iterator it = added.begin(); it != added.end(); ++it)
|
||||
{
|
||||
LLInventoryItem *item = gInventory.getItem(*it);
|
||||
if (!item)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const LLUUID& asset_uuid = item->getAssetUUID();
|
||||
if (item && item->getUUID().notNull() && asset_uuid.notNull())
|
||||
if (item->getUUID().notNull() && asset_uuid.notNull())
|
||||
{
|
||||
if (isAssetWatched(asset_uuid))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1094,8 +1094,11 @@ bool LLOutfitGalleryItem::openOutfitsContent()
|
|||
{
|
||||
outfit_list->setSelectedOutfitByUUID(mUUID);
|
||||
LLAccordionCtrlTab* tab = accordion->getSelectedTab();
|
||||
tab->showAndFocusHeader();
|
||||
return true;
|
||||
if (tab)
|
||||
{
|
||||
tab->showAndFocusHeader();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -411,6 +411,12 @@ LLViewerObject::~LLViewerObject()
|
|||
sNumZombieObjects--;
|
||||
llassert(mChildList.size() == 0);
|
||||
llassert(mControlAvatar.isNull()); // Should have been cleaned by now
|
||||
if (mControlAvatar.notNull())
|
||||
{
|
||||
mControlAvatar->markForDeath();
|
||||
mControlAvatar = NULL;
|
||||
LL_WARNS() << "Dead object owned a live control avatar" << LL_ENDL;
|
||||
}
|
||||
|
||||
clearInventoryListeners();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue