diff options
35 files changed, 256 insertions, 100 deletions
diff --git a/.github/workflows/cla.yaml b/.github/workflows/cla.yaml index 013adc9ca8..7866f943b5 100644 --- a/.github/workflows/cla.yaml +++ b/.github/workflows/cla.yaml @@ -23,4 +23,4 @@ jobs: path-to-signatures: signatures.json remote-organization-name: secondlife remote-repository-name: cla-signatures - allowlist: callum@mbp.localdomain + allowlist: callum@mbp.localdomain,rye@lindenlab.com diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index 3d18864b80..57f5a112d9 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -282,7 +282,7 @@ public: LLRunner& getRunner() { return mRunner; } #ifdef LL_WINDOWS - virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { } + virtual bool reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { return false; } #endif public: diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 1539b48bd3..b16f166d28 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -228,22 +228,6 @@ std::string LLCoros::logname() return data.mName.empty()? data.getKey() : data.mName; } -void LLCoros::saveException(const std::string& name, std::exception_ptr exc) -{ - mExceptionQueue.emplace(name, exc); -} - -void LLCoros::rethrow() -{ - if (! mExceptionQueue.empty()) - { - ExceptionData front = mExceptionQueue.front(); - mExceptionQueue.pop(); - LL_WARNS("LLCoros") << "Rethrowing exception from coroutine " << front.name << LL_ENDL; - std::rethrow_exception(front.exception); - } -} - void LLCoros::setStackSize(S32 stacksize) { LL_DEBUGS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL; @@ -310,18 +294,25 @@ namespace static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific -U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) +U32 exception_filter(U32 code, struct _EXCEPTION_POINTERS* exception_infop) { - if (code == STATUS_MSC_EXCEPTION) + if (LLApp::instance()->reportCrashToBugsplat((void*)exception_infop)) + { + // Handled + return EXCEPTION_CONTINUE_SEARCH; + } + else if (code == STATUS_MSC_EXCEPTION) { // C++ exception, go on return EXCEPTION_CONTINUE_SEARCH; } else { - // handle it + // handle it, convert to std::exception return EXCEPTION_EXECUTE_HANDLER; } + + return EXCEPTION_CONTINUE_SEARCH; } void sehandle(const LLCoros::callable_t& callable) @@ -379,14 +370,7 @@ void LLCoros::toplevel(std::string name, callable_t callable) // viewer will carry on. LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name)); } - catch (...) - { - // Stash any OTHER kind of uncaught exception in the rethrow() queue - // to be rethrown by the main fiber. - LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine " - << name << LL_ENDL; - LLCoros::instance().saveException(name, std::current_exception()); - } + // uncaught exception by default will cause std::terminate() } //static diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index c3820ae987..913414fbc1 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -171,19 +171,6 @@ public: static std::string getName(); /** - * rethrow() is called by the thread's main fiber to propagate an - * exception from any coroutine into the main fiber, where it can engage - * the normal unhandled-exception machinery, up to and including crash - * reporting. - * - * LLCoros maintains a queue of otherwise-uncaught exceptions from - * terminated coroutines. Each call to rethrow() pops the first of those - * and rethrows it. When the queue is empty (normal case), rethrow() is a - * no-op. - */ - void rethrow(); - - /** * This variation returns a name suitable for log messages: the explicit * name for an explicitly-launched coroutine, or "mainN" for the default * coroutine on a thread. @@ -327,20 +314,6 @@ private: void toplevel(std::string name, callable_t callable); struct CoroData; static CoroData& get_CoroData(const std::string& caller); - void saveException(const std::string& name, std::exception_ptr exc); - - struct ExceptionData - { - ExceptionData(const std::string& nm, std::exception_ptr exc): - name(nm), - exception(exc) - {} - // name of coroutine that originally threw this exception - std::string name; - // the thrown exception - std::exception_ptr exception; - }; - std::queue<ExceptionData> mExceptionQueue; S32 mStackSize; diff --git a/indra/llmessage/llcoproceduremanager.cpp b/indra/llmessage/llcoproceduremanager.cpp index 263670bdac..6a663a8e97 100644 --- a/indra/llmessage/llcoproceduremanager.cpp +++ b/indra/llmessage/llcoproceduremanager.cpp @@ -301,12 +301,12 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): mPoolSize(size), mActiveCoprocsCount(0), mPending(0), - mPendingCoprocs(std::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE)), mHTTPPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID), mCoroMapping() { try { + mPendingCoprocs = std::make_shared<CoprocQueue_t>(LLCoprocedureManager::DEFAULT_QUEUE_SIZE); // store in our LLTempBoundListener so that when the LLCoprocedurePool is // destroyed, we implicitly disconnect from this LLEventPump // Monitores application status @@ -339,6 +339,11 @@ LLCoprocedurePool::LLCoprocedurePool(const std::string &poolName, size_t size): llassert(0); // Fix Me! Ignoring missing listener! } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("CoProcMgr") << "Bad memory allocation in LLCoprocedurePool::LLCoprocedurePool!" << LL_ENDL; + } for (size_t count = 0; count < mPoolSize; ++count) { diff --git a/indra/llmessage/llcorehttputil.cpp b/indra/llmessage/llcorehttputil.cpp index 918a69be6f..992e145758 100644 --- a/indra/llmessage/llcorehttputil.cpp +++ b/indra/llmessage/llcorehttputil.cpp @@ -295,7 +295,15 @@ void HttpCoroHandler::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRespons } else { - result = this->handleSuccess(response, status); + try + { + result = this->handleSuccess(response, status); + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS("CoreHTTP") << "Failed to allocate memory for response handling." << LL_ENDL; + } } buildStatusEntry(response, status, result); diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index 83f5d31186..6a3af1e608 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -141,6 +141,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp bitmap_num = getNumBitmaps(bitmap_type) - 1; mCurrentOffsetX[bitmap_idx] += width + 1; + mGeneration++; return true; } @@ -168,6 +169,7 @@ void LLFontBitmapCache::reset() mBitmapWidth = 0; mBitmapHeight = 0; + mGeneration++; } //static diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h index f2dfd87877..0ae4e6bed0 100644 --- a/indra/llrender/llfontbitmapcache.h +++ b/indra/llrender/llfontbitmapcache.h @@ -63,6 +63,7 @@ public: U32 getNumBitmaps(EFontGlyphType bitmapType) const { return (bitmapType < EFontGlyphType::Count) ? static_cast<U32>(mImageRawVec[static_cast<U32>(bitmapType)].size()) : 0U; } S32 getBitmapWidth() const { return mBitmapWidth; } S32 getBitmapHeight() const { return mBitmapHeight; } + S32 getCacheGeneration() const { return mGeneration; } protected: static U32 getNumComponents(EFontGlyphType bitmap_type); @@ -74,6 +75,7 @@ private: S32 mCurrentOffsetY[static_cast<U32>(EFontGlyphType::Count)] = { 1 }; S32 mMaxCharWidth = 0; S32 mMaxCharHeight = 0; + S32 mGeneration = 0; std::vector<LLPointer<LLImageRaw>> mImageRawVec[static_cast<U32>(EFontGlyphType::Count)]; std::vector<LLPointer<LLImageGL>> mImageGLVec[static_cast<U32>(EFontGlyphType::Count)]; }; diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp index 38dc23d1dc..62b551f1e0 100644 --- a/indra/llrender/llfontfreetype.cpp +++ b/indra/llrender/llfontfreetype.cpp @@ -146,7 +146,6 @@ LLFontFreetype::LLFontFreetype() mIsFallback(false), mFTFace(NULL), mRenderGlyphCount(0), - mAddGlyphCount(0), mStyle(0), mPointSize(0) { @@ -574,7 +573,6 @@ LLFontGlyphInfo* LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, l S32 pos_x, pos_y; U32 bitmap_num; mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_glyph_type, bitmap_num); - mAddGlyphCount++; LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index, requested_glyph_type); gi->mXBitmapOffset = pos_x; diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index a2d925c5f6..783bf4a4b3 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -148,7 +148,6 @@ public: void setStyle(U8 style); U8 getStyle() const; - S32 getAddedGlyphs() const { return mAddGlyphCount; } private: void resetBitmapCache(); @@ -188,7 +187,6 @@ private: mutable LLFontBitmapCache* mFontBitmapCachep; mutable S32 mRenderGlyphCount; - mutable S32 mAddGlyphCount; }; #endif // LL_FONTFREETYPE_H diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 4037c036e5..16eec1fdd2 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -110,9 +110,10 @@ S32 LLFontGL::getNumFaces(const std::string& filename) return mFontFreetype->getNumFaces(filename); } -S32 LLFontGL::getKnownGlyphCount() const +S32 LLFontGL::getCacheGeneration() const { - return mFontFreetype ? mFontFreetype->getAddedGlyphs() : 0; + const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); + return font_bitmap_cache->getCacheGeneration(); } S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 73efc6b1eb..1c8e036f58 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -90,7 +90,7 @@ public: bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n); S32 getNumFaces(const std::string& filename); - S32 getKnownGlyphCount() const; + S32 getCacheGeneration() const; S32 render(const LLWString &text, S32 begin_offset, const LLRect& rect, diff --git a/indra/llrender/llfontvertexbuffer.cpp b/indra/llrender/llfontvertexbuffer.cpp index b53a841a87..a223509d30 100644 --- a/indra/llrender/llfontvertexbuffer.cpp +++ b/indra/llrender/llfontvertexbuffer.cpp @@ -148,7 +148,7 @@ S32 LLFontVertexBuffer::render( || mLastHorizDPI != LLFontGL::sHorizDPI || mLastOrigin != LLFontGL::sCurOrigin || mLastResGeneration != LLFontGL::sResolutionGeneration - || mLastFontGlyphCount != fontp->getKnownGlyphCount()) + || mLastFontCacheGen != fontp->getCacheGeneration()) { genBuffers(fontp, text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color); @@ -180,6 +180,9 @@ void LLFontVertexBuffer::genBuffers( { // todo: add a debug build assert if this triggers too often for to long? mBufferList.clear(); + // Save before rendreing, it can change mid-render, + // so will need to rerender previous characters + mLastFontCacheGen = fontp->getCacheGeneration(); gGL.beginList(&mBufferList); mChars = fontp->render(text, begin_offset, x, y, color, halign, valign, @@ -204,7 +207,6 @@ void LLFontVertexBuffer::genBuffers( mLastHorizDPI = LLFontGL::sHorizDPI; mLastOrigin = LLFontGL::sCurOrigin; mLastResGeneration = LLFontGL::sResolutionGeneration; - mLastFontGlyphCount = fontp->getKnownGlyphCount(); if (right_x) { diff --git a/indra/llrender/llfontvertexbuffer.h b/indra/llrender/llfontvertexbuffer.h index d5e1280dbf..a9e1e2337c 100644 --- a/indra/llrender/llfontvertexbuffer.h +++ b/indra/llrender/llfontvertexbuffer.h @@ -122,7 +122,7 @@ private: // Adding new characters to bitmap cache can alter value from getBitmapWidth(); // which alters whole string. So rerender when new characters were added to cache. - S32 mLastFontGlyphCount = 0; + S32 mLastFontCacheGen = 0; static bool sEnableBufferCollection; }; diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 1bc5e79835..1966e48f2e 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -2458,12 +2458,15 @@ void LLGLState::checkStates(GLboolean writeAlpha) return; } - GLint src; - GLint dst; - glGetIntegerv(GL_BLEND_SRC, &src); - glGetIntegerv(GL_BLEND_DST, &dst); - llassert_always(src == GL_SRC_ALPHA); - llassert_always(dst == GL_ONE_MINUS_SRC_ALPHA); + GLint srcRGB, dstRGB, srcAlpha, dstAlpha; + glGetIntegerv(GL_BLEND_SRC_RGB, &srcRGB); + glGetIntegerv(GL_BLEND_DST_RGB, &dstRGB); + glGetIntegerv(GL_BLEND_SRC_ALPHA, &srcAlpha); + glGetIntegerv(GL_BLEND_DST_ALPHA, &dstAlpha); + llassert_always(srcRGB == GL_SRC_ALPHA); + llassert_always(srcAlpha == GL_SRC_ALPHA); + llassert_always(dstRGB == GL_ONE_MINUS_SRC_ALPHA); + llassert_always(dstAlpha == GL_ONE_MINUS_SRC_ALPHA); // disable for now until usage is consistent //GLboolean colorMask[4]; diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index a059c4d741..b664065532 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -2011,7 +2011,7 @@ void LLFolderView::onIdleUpdateMenu(void* user_data) self->updateMenuOptions(menu); menu->needsArrange(); // update menu height if needed } - gIdleCallbacks.deleteFunction(onIdleUpdateMenu, NULL); + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, self); } bool LLFolderView::isFolderSelected() diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt index 0f9f025fe4..991d8e5c5f 100644 --- a/indra/newview/VIEWER_VERSION.txt +++ b/indra/newview/VIEWER_VERSION.txt @@ -1 +1 @@ -7.1.12 +7.1.13 diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index 35b2f8bd10..2121088405 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -255,7 +255,7 @@ void main() shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, distort); #endif - vec3 sunlit_linear = srgb_to_linear(sunlit); + vec3 sunlit_linear = sunlit; float fade = 1; #ifdef TRANSPARENT_WATER float depth = texture(depthMap, distort).r; @@ -317,7 +317,7 @@ void main() pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, normalize(wavef+up*max(dist, 32.0)/32.0*(1.0-vdu)), v, normalize(light_dir), nl, diffPunc, specPunc); - vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit_linear * shadow; + vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit_linear * shadow * atten; radiance *= df2.y; //radiance = toneMapNoExposure(radiance); vec3 color = vec3(0); diff --git a/indra/newview/gltfscenemanager.cpp b/indra/newview/gltfscenemanager.cpp index 7863d25696..c33d15228c 100644 --- a/indra/newview/gltfscenemanager.cpp +++ b/indra/newview/gltfscenemanager.cpp @@ -356,8 +356,9 @@ void GLTFSceneManager::addGLTFObject(LLViewerObject* obj, LLUUID gltf_id) llassert(obj->getVolume()->getParams().getSculptID() == gltf_id); llassert(obj->getVolume()->getParams().getSculptType() == LL_SCULPT_TYPE_GLTF); - if (obj->mGLTFAsset) - { // object already has a GLTF asset, don't reload it + if (obj->mGLTFAsset || obj->mIsGLTFAssetMissing ) + { + // object already has a GLTF asset or load failed, don't reload it // TODO: below assertion fails on dupliate requests for assets -- possibly need to touch up asset loading state machine // llassert(std::find(mObjects.begin(), mObjects.end(), obj) != mObjects.end()); @@ -398,16 +399,19 @@ void GLTFSceneManager::onGLTFBinLoadComplete(const LLUUID& id, LLAssetType::ETyp } else { - LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << LL_ENDL; + LL_WARNS("GLTF") << "Failed to prepare GLTF asset: " << id << ". Marking as missing." << LL_ENDL; + obj->mIsGLTFAssetMissing = true; obj->mGLTFAsset = nullptr; } } } + obj->unref(); // todo: use LLPointer } } else { - LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL; + LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << ". Marking as missing." << LL_ENDL; + obj->mIsGLTFAssetMissing = true; obj->unref(); } }); @@ -446,7 +450,8 @@ void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType a } else { - LL_WARNS("GLTF") << "Buffer URI is not a valid UUID: " << buffer.mUri << LL_ENDL; + LL_WARNS("GLTF") << "Buffer URI is not a valid UUID: " << buffer.mUri << " for asset id: " << id << ". Marking as missing." << LL_ENDL; + obj->mIsGLTFAssetMissing = true; obj->unref(); return; } @@ -455,7 +460,8 @@ void GLTFSceneManager::onGLTFLoadComplete(const LLUUID& id, LLAssetType::EType a } else { - LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << LL_ENDL; + LL_WARNS("GLTF") << "Failed to load GLTF asset: " << id << ". Marking as missing." << LL_ENDL; + obj->mIsGLTFAssetMissing = true; obj->unref(); } } @@ -517,6 +523,7 @@ void GLTFSceneManager::update() if (mUploadingObject) { mUploadingObject->mGLTFAsset = nullptr; + mUploadingObject->mIsGLTFAssetMissing = false; mUploadingObject->setGLTFAsset(assetId); mUploadingObject->markForUpdate(); mUploadingObject = nullptr; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 18ad19f6bc..a05466b476 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1402,8 +1402,6 @@ bool LLAppViewer::doFrame() LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df suspend"); // give listeners a chance to run llcoro::suspend(); - // if one of our coroutines threw an uncaught exception, rethrow it now - LLCoros::instance().rethrow(); } } @@ -5609,6 +5607,27 @@ void LLAppViewer::forceErrorCoroutineCrash() LLCoros::instance().launch("LLAppViewer::crashyCoro", [] {throw LLException("A deliberate crash from LLCoros"); }); } +void LLAppViewer::forceErrorCoroprocedureCrash() +{ + LL_WARNS() << "Forcing a crash in LLCoprocedureManager" << LL_ENDL; + LLCoprocedureManager::instance().enqueueCoprocedure("Upload", "DeliberateCrash", + [](LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t&, const LLUUID&) + { + LL_WARNS() << "Forcing a deliberate bad memory access from LLCoprocedureManager" << LL_ENDL; + S32* crash = NULL; + *crash = 0xDEADBEEF; + }); +} + +void LLAppViewer::forceErrorWorkQueueCrash() +{ + LL::WorkQueue::ptr_t workqueue = LL::WorkQueue::getInstance("General"); + if (workqueue) + { + workqueue->post([]() { throw LLException("This is a deliberate crash from General Queue"); }); + } +} + void LLAppViewer::forceErrorThreadCrash() { class LLCrashTestThread : public LLThread diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index ad42c4a6f1..10d71c9d42 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -175,6 +175,8 @@ public: virtual void forceErrorOSSpecificException(); virtual void forceErrorDriverCrash(); virtual void forceErrorCoroutineCrash(); + virtual void forceErrorCoroprocedureCrash(); + virtual void forceErrorWorkQueueCrash(); virtual void forceErrorThreadCrash(); // The list is found in app_settings/settings_files.xml diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 023ec3410a..b4a2479520 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -804,14 +804,16 @@ bool LLAppViewerWin32::cleanup() return result; } -void LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) +bool LLAppViewerWin32::reportCrashToBugsplat(void* pExcepInfo) { #if defined(LL_BUGSPLAT) if (sBugSplatSender) { sBugSplatSender->createReport((EXCEPTION_POINTERS*)pExcepInfo); + return true; } #endif // LL_BUGSPLAT + return false; } void LLAppViewerWin32::initLoggingAndGetLastDuration() diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h index 2242c95b06..250e72edf3 100644 --- a/indra/newview/llappviewerwin32.h +++ b/indra/newview/llappviewerwin32.h @@ -43,7 +43,7 @@ public: bool init() override; // Override to do application initialization bool cleanup() override; - void reportCrashToBugsplat(void* pExcepInfo) override; + bool reportCrashToBugsplat(void* pExcepInfo) override; protected: void initLoggingAndGetLastDuration() override; // Override to clean stack_trace info. diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp index 6277e65b2d..7dce627044 100644 --- a/indra/newview/llavatarpropertiesprocessor.cpp +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -669,6 +669,7 @@ void LLAvatarPropertiesProcessor::sendClassifiedInfoUpdate(const LLAvatarClassif void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id) { + LL_DEBUGS("PickInfo") << " Requiesting pick info for " << pick_id << LL_ENDL; // Must ask for a pick based on the creator id because // the pick database is distributed to the inventory cluster. JC std::vector<std::string> request_params{ creator_id.asString(), pick_id.asString() }; diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 32de0e5ee7..7d58511d41 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -213,7 +213,7 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) else if (tex_b && !tex_a) { shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_b); - tex_a->setFilteringOption(filter_mode); + tex_b->setFilteringOption(filter_mode); blend_factor = 0; // only one tex provided, no blending } else if (tex_b != tex_a) diff --git a/indra/newview/llheroprobemanager.cpp b/indra/newview/llheroprobemanager.cpp index e754de2fd1..675a8dfe7d 100644 --- a/indra/newview/llheroprobemanager.cpp +++ b/indra/newview/llheroprobemanager.cpp @@ -80,6 +80,17 @@ void LLHeroProbeManager::update() return; } + // Part of a hacky workaround to fix #3331. + // For some reason clearing shaders will cause mirrors to actually work. + // There's likely some deeper state issue that needs to be resolved. + // - Geenz 2025-02-25 + if (!mInitialized && LLStartUp::getStartupState() > STATE_PRECACHE) + { + LLViewerShaderMgr::instance()->clearShaderCache(); + LLViewerShaderMgr::instance()->setShaders(); + mInitialized = true; + } + LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; llassert(!gCubeSnapshot); // assert a snapshot is not in progress if (LLAppViewer::instance()->logoutRequestSent()) diff --git a/indra/newview/llheroprobemanager.h b/indra/newview/llheroprobemanager.h index 58a94a3de8..2737ec5ddf 100644 --- a/indra/newview/llheroprobemanager.h +++ b/indra/newview/llheroprobemanager.h @@ -144,6 +144,7 @@ private: std::vector<LLPointer<LLVOVolume>> mHeroVOList; LLPointer<LLVOVolume> mNearestHero; - + // Part of a hacky workaround to fix #3331. + bool mInitialized = false; }; diff --git a/indra/newview/llpanelprofilepicks.cpp b/indra/newview/llpanelprofilepicks.cpp index 08f3d3af5a..c2edc58687 100644 --- a/indra/newview/llpanelprofilepicks.cpp +++ b/indra/newview/llpanelprofilepicks.cpp @@ -55,6 +55,8 @@ static LLPanelInjector<LLPanelProfilePicks> t_panel_profile_picks("panel_profile_picks"); static LLPanelInjector<LLPanelProfilePick> t_panel_profile_pick("panel_profile_pick"); +static const F32 REQUEST_TIMOUT = 60; +static const F32 LOCATION_CACHE_TIMOUT = 900; class LLPickHandler : public LLCommandHandler { @@ -306,6 +308,7 @@ void LLPanelProfilePicks::processProperties(void* data, EAvatarProcessorType typ void LLPanelProfilePicks::processProperties(const LLAvatarData* avatar_picks) { + LL_DEBUGS("PickInfo") << "Processing picks for avatar " << getAvatarId() << LL_ENDL; LLUUID selected_id = mPickToSelectOnLoad; bool has_selection = false; if (mPickToSelectOnLoad.isNull()) @@ -320,6 +323,25 @@ void LLPanelProfilePicks::processProperties(const LLAvatarData* avatar_picks) } } + // Avoid pointlesly requesting parcel data, + // store previous values + std::map<LLUUID, std::string> parcelid_location_map; + std::map<LLUUID, LLUUID> pickid_parcelid_map; + + for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) + { + LLPanelProfilePick* pick_panel = dynamic_cast<LLPanelProfilePick*>(mTabContainer->getPanelByIndex(tab_idx)); + if (pick_panel && pick_panel->getPickId().notNull()) + { + std::string location = pick_panel->getPickLocation(); + if (!location.empty()) + { + parcelid_location_map[pick_panel->getParcelID()] = pick_panel->getPickLocation(); + pickid_parcelid_map[pick_panel->getPickId()] = pick_panel->getParcelID(); + } + } + } + mTabContainer->deleteAllTabs(); LLAvatarData::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); @@ -334,6 +356,15 @@ void LLPanelProfilePicks::processProperties(const LLAvatarData* avatar_picks) pick_panel->setPickName(pick_name); pick_panel->setAvatarId(getAvatarId()); + std::map<LLUUID, LLUUID>::const_iterator found_pick = pickid_parcelid_map.find(pick_id); + if (found_pick != pickid_parcelid_map.end()) + { + std::map<LLUUID, std::string>::const_iterator found = parcelid_location_map.find(found_pick->second); + if (found != parcelid_location_map.end() && !found->second.empty()) + { + pick_panel->setPickLocation(found_pick->second, found->second); + } + } mTabContainer->addTabPanel( LLTabContainer::TabPanelParams(). panel(pick_panel). @@ -353,6 +384,11 @@ void LLPanelProfilePicks::processProperties(const LLAvatarData* avatar_picks) LLPanelProfilePick* pick_panel = LLPanelProfilePick::create(); pick_panel->setAvatarId(getAvatarId()); + std::map<LLUUID, std::string>::const_iterator found = parcelid_location_map.find(data.parcel_id); + if (found != parcelid_location_map.end() && !found->second.empty()) + { + pick_panel->setPickLocation(data.parcel_id, found->second); + } pick_panel->processProperties(&data); mTabContainer->addTabPanel( LLTabContainer::TabPanelParams(). @@ -638,9 +674,14 @@ void LLPanelProfilePick::processProperties(void* data, EAvatarProcessorType type void LLPanelProfilePick::processProperties(const LLPickData* pick_info) { + LL_DEBUGS("PickInfo") << "Processing properties for pick " << mPickId << LL_ENDL; mIsEditing = false; mPickDescription->setParseHTML(true); - mParcelId = pick_info->parcel_id; + if (mParcelId != pick_info->parcel_id) + { + mParcelId = pick_info->parcel_id; + mPickLocationStr.clear(); + } setSnapshotId(pick_info->snapshot_id); if (!getSelfProfile()) { @@ -650,8 +691,11 @@ void LLPanelProfilePick::processProperties(const LLPickData* pick_info) setPickDesc(pick_info->desc); setPosGlobal(pick_info->pos_global); - // Send remote parcel info request to get parcel name and sim (region) name. - sendParcelInfoRequest(); + if (mPickLocationStr.empty() || mLastRequestTimer.getElapsedTimeF32() > LOCATION_CACHE_TIMOUT) + { + // Send remote parcel info request to get parcel name and sim (region) name. + sendParcelInfoRequest(); + } // *NOTE dzaporozhan // We want to keep listening to APT_PICK_INFO because user may @@ -691,9 +735,17 @@ void LLPanelProfilePick::setPickDesc(const std::string& desc) mPickDescription->setValue(desc); } +void LLPanelProfilePick::setPickLocation(const LLUUID &parcel_id, const std::string& location) +{ + setParcelID(parcel_id); // resets mPickLocationStr + setPickLocation(location); +} + void LLPanelProfilePick::setPickLocation(const std::string& location) { getChild<LLUICtrl>("pick_location")->setValue(location); + mPickLocationStr = location; + mLastRequestTimer.reset(); } void LLPanelProfilePick::onClickMap() @@ -790,16 +842,19 @@ std::string LLPanelProfilePick::getLocationNotice() void LLPanelProfilePick::sendParcelInfoRequest() { - if (mParcelId != mRequestedId) + if (mParcelId != mRequestedId || mLastRequestTimer.getElapsedTimeF32() > REQUEST_TIMOUT) { if (mRequestedId.notNull()) { LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this); } + LL_DEBUGS("PickInfo") << "Sending parcel request " << mParcelId << " for pick " << mPickId << LL_ENDL; LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelId, this); LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelId); mRequestedId = mParcelId; + mLastRequestTimer.reset(); + mPickLocationStr.clear(); } } @@ -816,6 +871,20 @@ void LLPanelProfilePick::processParcelInfo(const LLParcelData& parcel_data) } } +void LLPanelProfilePick::setParcelID(const LLUUID& parcel_id) +{ + if (mParcelId != parcel_id) + { + mParcelId = parcel_id; + mPickLocationStr.clear(); + } + if (mRequestedId.notNull() && mRequestedId != parcel_id) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mRequestedId, this); + mRequestedId.setNull(); + } +} + void LLPanelProfilePick::sendUpdate() { LLPickData pick_data; diff --git a/indra/newview/llpanelprofilepicks.h b/indra/newview/llpanelprofilepicks.h index e3f50f5576..b4d3eb010e 100644 --- a/indra/newview/llpanelprofilepicks.h +++ b/indra/newview/llpanelprofilepicks.h @@ -117,6 +117,8 @@ public: virtual void setPickName(const std::string& name); const std::string getPickName(); + virtual void setPickLocation(const LLUUID& parcel_id, const std::string& location); + std::string getPickLocation() { return mPickLocationStr; }; void processProperties(void* data, EAvatarProcessorType type) override; void processProperties(const LLPickData* pick_data); @@ -135,7 +137,8 @@ public: //This stuff we got from LLRemoteParcelObserver, in the last one we intentionally do nothing void processParcelInfo(const LLParcelData& parcel_data) override; - void setParcelID(const LLUUID& parcel_id) override { mParcelId = parcel_id; } + void setParcelID(const LLUUID& parcel_id) override; + LLUUID getParcelID() const { return mParcelId; } void setErrorStatus(S32 status, const std::string& reason) override {}; protected: @@ -230,6 +233,8 @@ protected: LLUUID mPickId; LLUUID mRequestedId; std::string mPickNameStr; + std::string mPickLocationStr; + LLTimer mLastRequestTimer; boost::signals2::connection mRegionCallbackConnection; boost::signals2::connection mParcelCallbackConnection; diff --git a/indra/newview/llscrollingpanelparam.h b/indra/newview/llscrollingpanelparam.h index 3aba4e4e40..93daf22e76 100644 --- a/indra/newview/llscrollingpanelparam.h +++ b/indra/newview/llscrollingpanelparam.h @@ -81,7 +81,6 @@ public: protected: LLTimer mMouseDownTimer; // timer for how long mouse has been held down on a hint. F32 mLastHeldTime; - bool mAllowModify; LLButton* mLessBtn; LLButton* mMoreBtn; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index d92faf4d1b..6281ac1f9e 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -286,6 +286,8 @@ void force_error_software_exception(); void force_error_os_exception(); void force_error_driver_crash(); void force_error_coroutine_crash(); +void force_error_coroprocedure_crash(); +void force_error_work_queue_crash(); void force_error_thread_crash(); void handle_force_delete(); @@ -2634,6 +2636,24 @@ class LLAdvancedForceErrorCoroutineCrash : public view_listener_t } }; +class LLAdvancedForceErrorCoroprocedureCrash : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_coroprocedure_crash(); + return true; + } +}; + +class LLAdvancedForceErrorWorkQueueCrash : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_work_queue_crash(); + return true; + } +}; + class LLAdvancedForceErrorThreadCrash : public view_listener_t { bool handleEvent(const LLSD& userdata) @@ -8657,6 +8677,16 @@ void force_error_coroutine_crash() LLAppViewer::instance()->forceErrorCoroutineCrash(); } +void force_error_coroprocedure_crash() +{ + LLAppViewer::instance()->forceErrorCoroprocedureCrash(); +} + +void force_error_work_queue_crash() +{ + LLAppViewer::instance()->forceErrorWorkQueueCrash(); +} + void force_error_thread_crash() { LLAppViewer::instance()->forceErrorThreadCrash(); @@ -9861,6 +9891,8 @@ void initialize_menus() view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareExceptionCoro(), "Advanced.ForceErrorSoftwareExceptionCoro"); view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorCoroutineCrash(), "Advanced.ForceErrorCoroutineCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorCoroprocedureCrash(), "Advanced.ForceErrorCoroprocedureCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorWorkQueueCrash(), "Advanced.ForceErrorWorkQueueCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorThreadCrash(), "Advanced.ForceErrorThreadCrash"); view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer"); diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index 206840ebfb..119b07b1f5 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -758,6 +758,7 @@ public: // Associated GLTF Asset std::shared_ptr<LL::GLTF::Asset> mGLTFAsset; + bool mIsGLTFAssetMissing = false; // Pipeline classes LLPointer<LLDrawable> mDrawable; diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index ab8d0d2564..38c702c4ca 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -100,8 +100,16 @@ LLSkyTex::LLSkyTex() : void LLSkyTex::init(bool isShiny) { mIsShiny = isShiny; - mSkyData = new LLColor4[(U32)(SKYTEX_RESOLUTION * SKYTEX_RESOLUTION)]; - mSkyDirs = new LLVector3[(U32)(SKYTEX_RESOLUTION * SKYTEX_RESOLUTION)]; + try + { + mSkyData = new LLColor4[(U32)(SKYTEX_RESOLUTION * SKYTEX_RESOLUTION)]; + mSkyDirs = new LLVector3[(U32)(SKYTEX_RESOLUTION * SKYTEX_RESOLUTION)]; + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + LL_ERRS() << "Failed to allocate memory for sky texture data" << LL_ENDL; + } for (S32 i = 0; i < 2; ++i) { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 18dd694246..5f096a5356 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -1412,7 +1412,18 @@ void LLPipeline::createLUTBuffers() { U32 lightResX = gSavedSettings.getU32("RenderSpecularResX"); U32 lightResY = gSavedSettings.getU32("RenderSpecularResY"); - F32* ls = new F32[lightResX*lightResY]; + F32* ls = nullptr; + try + { + ls = new F32[lightResX*lightResY]; + } + catch (std::bad_alloc&) + { + LLError::LLUserWarningMsg::showOutOfMemory(); + // might be better to set the error into mFatalMessage and rethrow + LL_ERRS() << "Bad memory allocation in createLUTBuffers! lightResX: " + << lightResX << " lightResY: " << lightResY << LL_ENDL; + } F32 specExp = gSavedSettings.getF32("RenderSpecularExponent"); // Calculate the (normalized) blinn-phong specular lookup texture. (with a few tweaks) for (U32 y = 0; y < lightResY; ++y) diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 0e70e75c0b..349c8d0e20 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -2788,7 +2788,7 @@ function="World.EnvPreset" function="Advanced.ForceErrorOSException" /> <menu_item_call.on_visible function="Advanced.EnableErrorOSException" /> - </menu_item_call> + </menu_item_call> <menu_item_call label="Force a Crash in a Coroutine" name="Force a Crash in a Coroutine"> @@ -2796,6 +2796,18 @@ function="World.EnvPreset" function="Advanced.ForceErrorCoroutineCrash" /> </menu_item_call> <menu_item_call + label="Force a Crash in a Coroprocedure" + name="Force a Crash in a Coroprocedure"> + <menu_item_call.on_click + function="Advanced.ForceErrorCoroprocedureCrash" /> + </menu_item_call> + <menu_item_call + label="Force a Crash in a Work Queue" + name="Force a Crash in a Work Queue"> + <menu_item_call.on_click + function="Advanced.ForceErrorWorkQueueCrash" /> + </menu_item_call> + <menu_item_call label="Force a Crash in a Thread" name="Force a Crash in a Thread"> <menu_item_call.on_click |