From 21947778baaca205615a71a97ac8f563c998fdd3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 16 Apr 2024 23:25:01 +0300 Subject: SL-18721 Window shutdown adjustments On viewer shutdown 1. Instead of handling potential WM_* messages viewer is no longer equiped to handle drop window's pointer and expect only WM_DESTROY 2. Detach thread and let it do its own thing, thread will delete itself 3. Reverts commit 1161262029f9619fb02d81575382b64d82d9cd09 Reason for the change: window was closing too early (as son as "LLApp" status changes) without proper cleanup --- indra/llwindow/llwindowwin32.cpp | 102 ++++++++++++++------------------------- 1 file changed, 36 insertions(+), 66 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 54e5f43e87..3ffc7d3354 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -351,10 +351,9 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool LLWindowWin32Thread(); void run() override; - void close() override; // closes queue, wakes thread, waits until thread closes - void wakeAndDestroy(); + bool wakeAndDestroy(); void glReady() { @@ -425,6 +424,7 @@ 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 mDeleteOnExit = false; // best guess at available video memory in MB std::atomic mAvailableVRAM; @@ -997,7 +997,11 @@ void LLWindowWin32::close() mhDC = NULL; mWindowHandle = NULL; - mWindowThread->wakeAndDestroy(); + if (mWindowThread->wakeAndDestroy()) + { + // thread will delete itselfs once done + mWindowThread = NULL; + } } BOOL LLWindowWin32::isValid() @@ -3104,10 +3108,17 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ break; } } - else + else // (NULL == window_imp) { - // (NULL == window_imp) - LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; + if (u_msg == WM_DESTROY) + { + PostQuitMessage(0); // Posts WM_QUIT with an exit code of 0 + return 0; + } + else + { + LL_DEBUGS("Window") << "No window implementation to handle message with, message code: " << U32(u_msg) << LL_ENDL; + } } // pass unhandled messages down to Windows @@ -4563,25 +4574,11 @@ U32 LLWindowWin32::getAvailableVRAMMegabytes() #endif // LL_WINDOWS inline LLWindowWin32::LLWindowWin32Thread::LLWindowWin32Thread() - : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, true /*should be false, temporary workaround for SL-18721*/) + : LL::ThreadPool("Window Thread", 1, MAX_QUEUE_SIZE, false) { LL::ThreadPool::start(); } -void LLWindowWin32::LLWindowWin32Thread::close() -{ - if (!mQueue->isClosed()) - { - LL_WARNS() << "Closing window thread without using destroy_window_handler" << LL_ENDL; - LL::ThreadPool::close(); - - // Workaround for SL-18721 in case window closes too early and abruptly - LLSplashScreen::show(); - LLSplashScreen::update("..."); // will be updated later - } -} - - /** * LogChange is to log changes in status while trying to avoid spamming the * log with repeated messages, especially in a tight loop. It refuses to log @@ -4926,14 +4923,19 @@ void LLWindowWin32::LLWindowWin32Thread::run() } cleanupDX(); + + if (mDeleteOnExit) + { + delete this; + } } -void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { if (mQueue->isClosed()) { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; - return; + LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." <close(); @@ -4986,49 +4997,8 @@ void LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); } - // 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) - { - 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; + return true; } void LLWindowWin32::post(const std::function& func) -- cgit v1.3 From a620e58daccf92b5b8d61347312739720ed2b51a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 4 Jul 2024 17:31:26 +0300 Subject: SL-18721 Don't 'post' window destruction, make thread do it automatically --- indra/llwindow/llwindowwin32.cpp | 70 ++++++++++++++++++++++------------------ indra/newview/llappviewer.cpp | 2 +- 2 files changed, 40 insertions(+), 32 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index aea7367337..abf86e363c 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -352,7 +352,12 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool void run() override; - // closes queue, wakes thread, waits until thread closes + // Detroys handles and window + // Either post to or call from window thread + void destroyWindow(); + + // Closes queue, wakes thread, waits until thread closes. + // Call from main thread bool wakeAndDestroy(); void glReady() @@ -424,7 +429,7 @@ 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 mDeleteOnExit = false; + LLAtomicBool mDeleteOnExit = false; // best guess at available video memory in MB std::atomic mAvailableVRAM; @@ -873,6 +878,7 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, LLWindowWin32::~LLWindowWin32() { delete mDragDrop; + mDragDrop = NULL; delete [] mWindowTitle; mWindowTitle = NULL; @@ -884,6 +890,7 @@ LLWindowWin32::~LLWindowWin32() mWindowClassName = NULL; delete mWindowThread; + mWindowThread = NULL; } void LLWindowWin32::show() @@ -4931,6 +4938,7 @@ void LLWindowWin32::LLWindowWin32Thread::run() #endif } + destroyWindow(); cleanupDX(); if (mDeleteOnExit) @@ -4939,6 +4947,35 @@ void LLWindowWin32::LLWindowWin32Thread::run() } } +void LLWindowWin32::LLWindowWin32Thread::destroyWindow() +{ + if (mWindowHandleThrd != NULL && 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; +} + bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { if (mQueue->isClosed()) @@ -4954,35 +4991,6 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() // 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; - }); - mDeleteOnExit = true; SetWindowLongPtr(old_handle, GWLP_USERDATA, NULL); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index f36a292e9e..ab3cdfc5a4 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2041,7 +2041,7 @@ bool LLAppViewer::cleanup() sTextureFetch->shutDownTextureCacheThread() ; LLLFSThread::sLocal->shutdown(); - ms_sleep(200); + LL_INFOS() << "Shutting down OpenGL" << LL_ENDL; // Shut down OpenGL -- cgit v1.3 From 28f45962fdf69ea5149133fbaff425f9e2ca6f42 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 15 Oct 2024 12:56:47 +0300 Subject: Post-merge cleanup: llwindowwin32.cpp --- indra/llwindow/llwindowwin32.cpp | 8 -------- 1 file changed, 8 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index beaf910a02..6ce0594c96 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -411,14 +411,6 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool bool mGLReady = false; bool mGotGLBuffer = false; LLAtomicBool mDeleteOnExit = false; - // best guess at available video memory in MB - std::atomic mAvailableVRAM; - - 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; }; -- cgit v1.3 From 19347f7094c9448e02a021ae2d571b5fe8bfcc2e Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 15 Oct 2024 22:35:38 +0200 Subject: Fix merge issues: * Restore changes from 21947778baaca205615a71a97ac8f563c998fdd3 to llwindow/llwindowwin32.cpp * Restore changes from 3758618949684641fc94b5c9478d9002706213cc to newview/llinspecttexture.cpp * Fix apparent merge error in LLInventoryPanel::itemChanged * Restore changes from 1eeecfa1a8bf43a8980217ce34e3b5f4458483e0 in newview/llpaneloutfitsinventory.h * Restore changes from b9633c17e373bfe55b29228996e8473eb041466d in newview/llpaneloutfitsinventory.h & newview/llpanelwearing.cpp * Restore changes from f660f1f0fda4d2363d351fa550b4f8818b46c2c3 in newview/llviewertexture.cpp * Restore changes from b9633c17e373bfe55b29228996e8473eb041466d & 98f7d73d46fdc045759023eda6409e8c791f5cb2 in newview/lloutfitgallery.cpp and newview/lloutfitslist.cpp * Replace changes from 23729442aab7130f3368d433e8a5a9dd45ff6b98 with current implementation in develop branch * Fix more broken changes in LLViewerTexture::saveRawImage * Restore the changes in LLMath both from develop and maint-c * Fix all kind of other merge errors # Conflicts: # indra/llmath/v2math.h # indra/llmath/v3math.h # indra/llui/llfolderviewitem.cpp # indra/llwindow/llwindowwin32.cpp # indra/newview/llfloaterobjectweights.h # indra/newview/lloutfitgallery.cpp # indra/newview/lloutfitslist.cpp # indra/newview/llsidepaneliteminfo.cpp # indra/newview/llvoavatar.cpp --- indra/llmath/llmath.h | 2 +- indra/llmath/v2math.h | 2 +- indra/llmath/v3math.h | 4 +- indra/llmath/v4math.h | 4 +- indra/llwindow/llwindowwin32.cpp | 52 ++++---------------- indra/newview/llagentcamera.h | 4 +- indra/newview/llfloaterobjectweights.h | 2 +- indra/newview/llfolderviewmodelinventory.cpp | 2 +- indra/newview/llinspecttexture.cpp | 3 +- indra/newview/lloutfitgallery.cpp | 2 - indra/newview/lloutfitslist.cpp | 9 +--- indra/newview/llpanelwearing.cpp | 4 -- indra/newview/llviewertexture.cpp | 17 ++++++- indra/newview/llvoavatar.cpp | 71 +++++++++++++--------------- 14 files changed, 71 insertions(+), 107 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index fa315291a3..f5e9cdc7e4 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -75,7 +75,7 @@ constexpr F32 DEG_TO_RAD = 0.017453292519943295769236907684886f; constexpr F32 RAD_TO_DEG = 57.295779513082320876798154814105f; constexpr F32 F_APPROXIMATELY_ZERO = 0.00001f; constexpr F32 F_LN10 = 2.3025850929940456840179914546844f; -constexpr F32 OO_LN10 = 0.43429448190325182765112891891661; +constexpr F32 OO_LN10 = 0.43429448190325182765112891891661f; constexpr F32 F_LN2 = 0.69314718056f; constexpr F32 OO_LN2 = 1.4426950408889634073599246810019f; diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h index 6e3a2933bf..8e366485e7 100644 --- a/indra/llmath/v2math.h +++ b/indra/llmath/v2math.h @@ -212,7 +212,7 @@ inline void LLVector2::setVec(const F32 *vec) inline F32 LLVector2::length(void) const { - return (F32) sqrt(lengthSquared()); + return sqrt(lengthSquared()); } inline F32 LLVector2::lengthSquared(void) const diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index b7691d79b0..d6f2a26c54 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -325,10 +325,10 @@ inline F32 LLVector3::normVec(void) inline F32 LLVector3::length(void) const { - return (F32) sqrt(lengthSquared()); + return sqrt(lengthSquared()); } -inline F32 LLVector3::lengthSquared(void) const +inline F32 LLVector3::lengthSquared() const { return mV[0]*mV[0] + mV[1]*mV[1] + mV[2]*mV[2]; } diff --git a/indra/llmath/v4math.h b/indra/llmath/v4math.h index f155d4db52..e72d5cfa6b 100644 --- a/indra/llmath/v4math.h +++ b/indra/llmath/v4math.h @@ -341,7 +341,7 @@ inline void LLVector4::setVec(const F32 *vec) inline F32 LLVector4::length(void) const { - return (F32) sqrt(lengthSquared()); + return sqrt(lengthSquared()); } inline F32 LLVector4::lengthSquared(void) const @@ -489,7 +489,7 @@ inline LLVector4 lerp(const LLVector4 &a, const LLVector4 &b, F32 u) inline F32 LLVector4::normalize(void) { - F32 mag = (F32) sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); + F32 mag = sqrt(mV[VX]*mV[VX] + mV[VY]*mV[VY] + mV[VZ]*mV[VZ]); if (mag > FP_MAG_THRESHOLD) { diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 6ce0594c96..6fad11d506 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -410,7 +410,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; bool mGotGLBuffer = false; - LLAtomicBool mDeleteOnExit = false; + bool mDeleteOnExit = false; }; @@ -4852,6 +4852,15 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() mGLReady = false; }); + mDeleteOnExit = true; + SetWindowLongPtr(old_handle, GWLP_USERDATA, NULL); + + // Let thread finish on its own and don't block main thread. + for (auto& pair : mThreads) + { + pair.second.detach(); + } + LL_DEBUGS("Window") << "Closing window's pool queue" << LL_ENDL; mQueue->close(); @@ -4866,47 +4875,6 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); } - // 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) - { - 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(); - } - } LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; return true; } diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h index feb396d840..d277fd6158 100644 --- a/indra/newview/llagentcamera.h +++ b/indra/newview/llagentcamera.h @@ -139,12 +139,12 @@ private: //-------------------------------------------------------------------- public: LLVector3d getCameraPositionGlobal() const; - const LLVector3 &getCameraPositionAgent() const; + const LLVector3& getCameraPositionAgent() const; LLVector3d calcCameraPositionTargetGlobal(bool *hit_limit = NULL); // Calculate the camera position target F32 getCameraMinOffGround(); // Minimum height off ground for this mode, meters void setCameraCollidePlane(const LLVector4 &plane) { mCameraCollidePlane = plane; } bool calcCameraMinDistance(F32 &obj_min_distance); - F32 getCurrentCameraBuildOffset() { return (F32)mCameraFocusOffset.length(); } + F32 getCurrentCameraBuildOffset() const { return (F32)mCameraFocusOffset.length(); } void clearCameraLag() { mCameraLag.clearVec(); } const LLVector3& getCameraUpVector() const { return mCameraUpVector; } private: diff --git a/indra/newview/llfloaterobjectweights.h b/indra/newview/llfloaterobjectweights.h index 40f571f4ad..bda625564b 100644 --- a/indra/newview/llfloaterobjectweights.h +++ b/indra/newview/llfloaterobjectweights.h @@ -58,7 +58,7 @@ public: LLFloaterObjectWeights(const LLSD& key); ~LLFloaterObjectWeights(); - /*virtual*/ bool postBuild() override; + bool postBuild() override; void onOpen(const LLSD& key) override; diff --git a/indra/newview/llfolderviewmodelinventory.cpp b/indra/newview/llfolderviewmodelinventory.cpp index 58132299de..9223c13ec1 100644 --- a/indra/newview/llfolderviewmodelinventory.cpp +++ b/indra/newview/llfolderviewmodelinventory.cpp @@ -248,7 +248,7 @@ bool LLFolderViewModelItemInventory::filterChildItem( LLFolderViewModelItem* ite return continue_filtering; } -bool LLFolderViewModelItemInventory::filter( LLFolderViewFilter& filter) +bool LLFolderViewModelItemInventory::filter(LLFolderViewFilter& filter) { const S32 filter_generation = filter.getCurrentGeneration(); const S32 must_pass_generation = filter.getFirstRequiredGeneration(); diff --git a/indra/newview/llinspecttexture.cpp b/indra/newview/llinspecttexture.cpp index 3e7fbe3da3..9f0d236826 100644 --- a/indra/newview/llinspecttexture.cpp +++ b/indra/newview/llinspecttexture.cpp @@ -148,7 +148,8 @@ void LLTexturePreviewView::draw() bool isLoading = (!m_Image->isFullyLoaded()) && (m_Image->getDiscardLevel() > 0); if (isLoading) LLFontGL::getFontSansSerif()->renderUTF8(mLoadingText, 0, rctClient.mLeft + 3, rctClient.mTop - 25, LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW); - m_Image->addTextureStats((isLoading) ? MAX_IMAGE_AREA : (F32)(rctClient.getWidth() * rctClient.getHeight())); + + m_Image->setKnownDrawSize(MAX_IMAGE_SIZE, MAX_IMAGE_SIZE); } } diff --git a/indra/newview/lloutfitgallery.cpp b/indra/newview/lloutfitgallery.cpp index 09dceed2f0..7a6aa05763 100644 --- a/indra/newview/lloutfitgallery.cpp +++ b/indra/newview/lloutfitgallery.cpp @@ -1275,8 +1275,6 @@ void LLOutfitGalleryGearMenu::onUpdateItemsVisibility() { if (!mMenu) return; bool have_selection = getSelectedOutfitID().notNull(); - mMenu->setItemVisible("expand", false); - mMenu->setItemVisible("collapse", false); mMenu->setItemVisible("thumbnail", have_selection); mMenu->setItemVisible("sepatator3", true); mMenu->setItemVisible("sort_folders_by_name", true); diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 4029834ab7..bf413c0438 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -1151,12 +1151,6 @@ void LLOutfitListBase::ChangeOutfitSelection(LLWearableItemsList* list, const LL bool LLOutfitListBase::postBuild() { - mGearMenu = createGearMenu(); - - LLMenuButton* menu_gear_btn = getChild("options_gear_btn"); - - menu_gear_btn->setMouseDownCallback(boost::bind(&LLOutfitListGearMenuBase::updateItemsVisibility, mGearMenu)); - menu_gear_btn->setMenu(mGearMenu->getMenu()); return true; } @@ -1515,9 +1509,8 @@ LLOutfitListGearMenu::~LLOutfitListGearMenu() void LLOutfitListGearMenu::onUpdateItemsVisibility() { if (!mMenu) return; - mMenu->setItemVisible("expand", true); - mMenu->setItemVisible("collapse", true); mMenu->setItemVisible("thumbnail", getSelectedOutfitID().notNull()); + mMenu->setItemVisible("favorite", getSelectedOutfitID().notNull()); mMenu->setItemVisible("sepatator3", false); mMenu->setItemVisible("sort_folders_by_name", false); LLOutfitListGearMenuBase::onUpdateItemsVisibility(); diff --git a/indra/newview/llpanelwearing.cpp b/indra/newview/llpanelwearing.cpp index 779b8d3c11..3aedde74c6 100644 --- a/indra/newview/llpanelwearing.cpp +++ b/indra/newview/llpanelwearing.cpp @@ -263,10 +263,6 @@ bool LLPanelWearing::postBuild() mTempItemsList->setFgUnselectedColor(LLColor4::white); mTempItemsList->setRightMouseDownCallback(boost::bind(&LLPanelWearing::onTempAttachmentsListRightClick, this, _1, _2, _3)); - LLMenuButton* menu_gear_btn = getChild("options_gear_btn"); - - menu_gear_btn->setMenu(mGearMenu->getMenu()); - return true; } diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 5e4fe95fd9..575dafa0f1 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -2110,6 +2110,7 @@ bool LLViewerFetchedTexture::updateFetch() LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("vftuf - request created"); mHasFetcher = true; mIsFetching = true; + mLastWorkerDiscardLevel = worker_discard; // in some cases createRequest can modify discard, as an example // bake textures are always at discard 0 mRequestedDiscardLevel = llmin(desired_discard, fetch_request_response); @@ -2733,6 +2734,8 @@ void LLViewerFetchedTexture::saveRawImage() return; } + LLImageDataSharedLock lock(mRawImage); + mSavedRawDiscardLevel = mRawDiscardLevel; if (mBoostLevel == LLGLTexture::BOOST_ICON) { @@ -2748,13 +2751,25 @@ void LLViewerFetchedTexture::saveRawImage() mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); } } + else if (mBoostLevel == LLGLTexture::BOOST_THUMBNAIL) + { + if (mRawImage->getWidth() > DEFAULT_THUMBNAIL_DIMENSIONS || mRawImage->getHeight() > DEFAULT_THUMBNAIL_DIMENSIONS) + { + mSavedRawImage = new LLImageRaw(DEFAULT_THUMBNAIL_DIMENSIONS, DEFAULT_THUMBNAIL_DIMENSIONS, mRawImage->getComponents()); + mSavedRawImage->copyScaled(mRawImage); + } + else + { + mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()); + } + } else if (mBoostLevel == LLGLTexture::BOOST_SCULPTED) { S32 expected_width = mKnownDrawWidth > 0 ? mKnownDrawWidth : sMaxSculptRez; S32 expected_height = mKnownDrawHeight > 0 ? mKnownDrawHeight : sMaxSculptRez; if (mRawImage->getWidth() > expected_width || mRawImage->getHeight() > expected_height) { - mSavedRawImage = new LLImageRaw(DEFAULT_THUMBNAIL_DIMENSIONS, DEFAULT_THUMBNAIL_DIMENSIONS, mRawImage->getComponents()); + mSavedRawImage = new LLImageRaw(expected_width, expected_height, mRawImage->getComponents()); mSavedRawImage->copyScaled(mRawImage); } else diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 16ffbbffa8..d249d230c6 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -683,6 +683,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mPreviousFullyLoaded(false), mFullyLoadedInitialized(false), mLastCloudAttachmentCount(0), + mFullyLoadedFrameCounter(0), mVisualComplexity(VISUAL_COMPLEXITY_UNKNOWN), mLoadedCallbacksPaused(false), mLoadedCallbackTextures(0), @@ -966,7 +967,7 @@ bool LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) ++grey_avatars; } } - return !grey_avatars; + return grey_avatars == 0; } // static @@ -8210,7 +8211,7 @@ bool LLVOAvatar::getIsCloud() const void LLVOAvatar::updateRezzedStatusTimers(S32 rez_status) { // State machine for rezzed status. Statuses are -1 on startup, 0 - // = cloud, 1 = gray, 2 = downloading, 3 = waiting for attachments, 4 = full. + // Statuses are -1 on startup, 0 = cloud, 1 = gray, 2 = downloading, 3 = waiting for attachments, 4 = full. // Purpose is to collect time data for each it takes avatar to reach // various loading landmarks: gray, textured (partial), textured fully. @@ -8392,15 +8393,15 @@ bool LLVOAvatar::updateIsFullyLoaded() if (mFirstFullyVisible && !mIsControlAvatar) { loading = ((rez_status < 2) - // Wait at least 60s for unfinished textures to finish on first load, - // don't wait forever, it might fail. Even if it will eventually load by - // itself and update mLoadedCallbackTextures (or fail and clean the list), - // avatars are more time-sensitive than textures and can't wait that long. - || (mLoadedCallbackTextures < mCallbackTextureList.size() && mLastTexCallbackAddedTime.getElapsedTimeF32() < MAX_TEXTURE_WAIT_TIME_SEC) - || !mPendingAttachment.empty() - || (rez_status < 3 && !isFullyBaked()) - || hasPendingAttachedMeshes() - ); + // Wait at least 60s for unfinished textures to finish on first load, + // don't wait forever, it might fail. Even if it will eventually load by + // itself and update mLoadedCallbackTextures (or fail and clean the list), + // avatars are more time-sensitive than textures and can't wait that long. + || (mLoadedCallbackTextures < mCallbackTextureList.size() && mLastTexCallbackAddedTime.getElapsedTimeF32() < MAX_TEXTURE_WAIT_TIME_SEC) + || !mPendingAttachment.empty() + || (rez_status < 3 && !isFullyBaked()) + || hasPendingAttachedMeshes() + ); // compare amount of attachments to one reported by simulator if (!loading && !isSelf() && rez_status < 4 && mLastCloudAttachmentCount < mSimAttachments.size()) @@ -8460,41 +8461,33 @@ void LLVOAvatar::updateRuthTimer(bool loading) bool LLVOAvatar::processFullyLoadedChange(bool loading) { // We wait a little bit before giving the 'all clear', to let things to - // settle down (models to snap into place, textures to get first packets). - // And if viewer isn't aware of some parts yet, this gives them a chance - // to arrive. + // settle down: models to snap into place, textures to get first packets, + // LODs to load. const F32 LOADED_DELAY = 1.f; if (loading) { mFullyLoadedTimer.reset(); - mFullyLoaded = false; } - else if (!mFullyLoaded) - { - // We wait a little bit before giving the 'all clear', to let things to - // settle down: models to snap into place, textures to get first packets, - // LODs to load. - const F32 LOADED_DELAY = 1.f; if (mFirstFullyVisible) { F32 first_use_delay = FIRST_APPEARANCE_CLOUD_MIN_DELAY; if (!isSelf() && loading) { - // Note that textures can causes 60s delay on thier own - // so this delay might end up on top of textures' delay - first_use_delay = llclamp( - mFirstAppearanceMessageTimer.getElapsedTimeF32(), - FIRST_APPEARANCE_CLOUD_MIN_DELAY, - FIRST_APPEARANCE_CLOUD_MAX_DELAY); + // Note that textures can causes 60s delay on thier own + // so this delay might end up on top of textures' delay + first_use_delay = llclamp( + mFirstAppearanceMessageTimer.getElapsedTimeF32(), + FIRST_APPEARANCE_CLOUD_MIN_DELAY, + FIRST_APPEARANCE_CLOUD_MAX_DELAY); - if (shouldImpostor()) - { - // Impostors are less of a priority, - // let them stay cloud longer - first_use_delay *= FIRST_APPEARANCE_CLOUD_IMPOSTOR_MODIFIER; - } + if (shouldImpostor()) + { + // Impostors are less of a priority, + // let them stay cloud longer + first_use_delay *= FIRST_APPEARANCE_CLOUD_IMPOSTOR_MODIFIER; + } } mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > first_use_delay); } @@ -8503,10 +8496,9 @@ bool LLVOAvatar::processFullyLoadedChange(bool loading) mFullyLoaded = (mFullyLoadedTimer.getElapsedTimeF32() > LOADED_DELAY); } - if (!mPreviousFullyLoaded && !loading && mFullyLoaded) - { - debugAvatarRezTime("AvatarRezNotification", "fully loaded"); - } + if (!mPreviousFullyLoaded && !loading && mFullyLoaded) + { + debugAvatarRezTime("AvatarRezNotification", "fully loaded"); } // did our loading state "change" from last call? @@ -8516,8 +8508,9 @@ bool LLVOAvatar::processFullyLoadedChange(bool loading) const S32 UPDATE_RATE = 30; bool changed = ((mFullyLoaded != mPreviousFullyLoaded) || // if the value is different from the previous call - (!mFullyLoadedInitialized) || // if we've never been called before - (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change + (!mFullyLoadedInitialized) || // if we've never been called before + (mFullyLoadedFrameCounter % UPDATE_RATE == 0)); // every now and then issue a change + bool fully_loaded_changed = (mFullyLoaded != mPreviousFullyLoaded); mPreviousFullyLoaded = mFullyLoaded; mFullyLoadedInitialized = true; -- cgit v1.3 From bab3bc4ebd8f33d80411d6d28e16eea6b865e8fd Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 15 Oct 2024 23:49:00 +0200 Subject: Fix more merge issues: * Re-apply changes from a620e58daccf92b5b8d61347312739720ed2b51a * Fix duplicate code resulting from 826236f1bc065fba257d7954d11ac98c59493445 # Conflicts: # indra/llwindow/llwindowwin32.cpp --- indra/llwindow/llwindowwin32.cpp | 44 +++++++++++++++++++++++----------------- indra/newview/llvoavatar.cpp | 1 - 2 files changed, 25 insertions(+), 20 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 6fad11d506..3ef162a870 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -351,6 +351,10 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool void run() override; + // Detroys handles and window + // Either post to or call from window thread + void destroyWindow(); + // Closes queue, wakes thread, waits until thread closes. // Call from main thread bool wakeAndDestroy(); @@ -410,7 +414,7 @@ struct LLWindowWin32::LLWindowWin32Thread : public LL::ThreadPool // until after some graphics setup. See SL-20177. -Cosmic,2023-09-18 bool mGLReady = false; bool mGotGLBuffer = false; - bool mDeleteOnExit = false; + LLAtomicBool mDeleteOnExit = false; }; @@ -4802,30 +4806,17 @@ void LLWindowWin32::LLWindowWin32Thread::run() #endif } + destroyWindow(); + if (mDeleteOnExit) { delete this; } } -bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +void LLWindowWin32::LLWindowWin32Thread::destroyWindow() { - if (mQueue->isClosed()) - { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; - return false; - } - - // 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 (mWindowHandleThrd != NULL && IsWindow(mWindowHandleThrd)) { if (mhDCThrd) { @@ -4849,9 +4840,24 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() } mWindowHandleThrd = NULL; mhDCThrd = NULL; +} + +bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() +{ + if (mQueue->isClosed()) + { + LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." < Date: Sat, 12 Apr 2025 06:18:44 +0300 Subject: Refactor LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() Key improvements: 1. Better error handling for thread detachment 2. More careful sequencing of operations 3. Ensuring the window is hidden before proceeding with other shutdown steps 4. Proper checking of thread joinability before detaching --- indra/llwindow/llwindowwin32.cpp | 49 ++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 3ef162a870..83ae302859 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -4846,41 +4846,62 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { if (mQueue->isClosed()) { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." <close(); - // Post a nonsense user message to wake up the thread in - // case it is waiting for a getMessage() + // Wake up the thread if it's stuck in GetMessage() if (old_handle) { WPARAM wparam{ 0xB0B0 }; LL_DEBUGS("Window") << "PostMessage(" << std::hex << old_handle << ", " << WM_DUMMY_ << ", " << wparam << ")" << std::dec << LL_ENDL; + + // Use PostMessage to signal thread to wake up PostMessage(old_handle, WM_DUMMY_, wparam, 0x1337); } + // Cleanly detach threads instead of joining them to avoid blocking the main thread + // This is acceptable since the thread will self-delete with mDeleteOnExit + for (auto& pair : mThreads) + { + try { + // Only detach if the thread is joinable + if (pair.second.joinable()) + { + pair.second.detach(); + } + } + catch (const std::system_error& e) { + LL_WARNS("Window") << "Exception detaching thread: " << e.what() << LL_ENDL; + } + } + LL_DEBUGS("Window") << "thread pool shutdown complete" << LL_ENDL; return true; } -- cgit v1.3 From 23083286601150854f1c4a10e92699e7783cb224 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 11 Aug 2025 21:17:13 +0300 Subject: #4284 Better window shutdown logging To help investigate shutdown freeze --- indra/llwindow/llwindowwin32.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'indra/llwindow') diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index d46357629a..94fd104bcc 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -1000,7 +1000,7 @@ void LLWindowWin32::close() // Restore gamma to the system values. restoreGamma(); - LL_DEBUGS("Window") << "Destroying Window" << LL_ENDL; + LL_INFOS("Window") << "Destroying Window Thread" << LL_ENDL; if (sWindowHandleForMessageBox == mWindowHandle) { @@ -4891,7 +4891,7 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { if (mQueue->isClosed()) { - LL_WARNS() << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; + LL_WARNS("Window") << "Tried to close Queue. Win32 thread Queue already closed." << LL_ENDL; return false; } @@ -4900,6 +4900,11 @@ bool LLWindowWin32::LLWindowWin32Thread::wakeAndDestroy() { ShowWindow(mWindowHandleThrd, SW_HIDE); } + else + { + LL_WARNS("Window") << "Tried to hide window, but Win32 window handle is NULL." << LL_ENDL; + return false; + } mGLReady = false; -- cgit v1.3