From c8926630af2b80c7db817b78df3a90378f0ecbbb Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Tue, 11 Jan 2022 17:29:04 -0700
Subject: SL-16418 optimize imageraw clear

---
 indra/newview/llviewermedia.cpp | 41 ++++++++++++++++++++++++-----------------
 1 file changed, 24 insertions(+), 17 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 63f57e81cc..ba9bbcc57e 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -635,6 +635,7 @@ static bool proximity_comparitor(const LLViewerMediaImpl* i1, const LLViewerMedi
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE("Update Media");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_SPARE_IDLE("Spare Idle");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_INTEREST("Update/Interest");
+static LLTrace::BlockTimerStatHandle FTM_MEDIA_UPDATE_VOLUME("Update/Volume");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT("Media Sort");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_SORT2("Media Sort 2");
 static LLTrace::BlockTimerStatHandle FTM_MEDIA_MISC("Misc");
@@ -2087,6 +2088,7 @@ void LLViewerMediaImpl::setMute(bool mute)
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::updateVolume()
 {
+    LL_RECORD_BLOCK_TIME(FTM_MEDIA_UPDATE_VOLUME);
 	if(mMediaSource)
 	{
 		// always scale the volume by the global media volume
@@ -2943,7 +2945,7 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
 	}
 
 	LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId );
-
+    
 	if (mNeedsNewTexture
 		|| placeholder_image->getUseMipMaps()
 		|| (placeholder_image->getWidth() != mMediaSource->getTextureWidth())
@@ -2960,25 +2962,30 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
 		int texture_depth = mMediaSource->getTextureDepth();
 
 		// MEDIAOPT: check to see if size actually changed before doing work
-		placeholder_image->destroyGLTexture();
+            placeholder_image->destroyGLTexture();
 		// MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
 		placeholder_image->reinit(FALSE);	// probably not needed
 
-		// MEDIAOPT: seems insane that we actually have to make an imageraw then
-		// immediately discard it
-		LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
-		// Clear the texture to the background color, ignoring alpha.
-		// convert background color channels from [0.0, 1.0] to [0, 255];
-		raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff);
-		int discard_level = 0;
-
-		// ask media source for correct GL image format constants
-		placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
-											 mMediaSource->getTextureFormatPrimary(),
-											 mMediaSource->getTextureFormatType(),
-											 mMediaSource->getTextureFormatSwapBytes());
-
-		placeholder_image->createGLTexture(discard_level, raw);
+        // MEDIAOPT: seems insane that we actually have to make an imageraw then
+        // immediately discard it
+        LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
+        // Clear the texture to the background color, ignoring alpha.
+        // convert background color channels from [0.0, 1.0] to [0, 255];
+        {LL_PROFILE_ZONE_NAMED("djh clear raw");
+        raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff);
+        }
+        // ask media source for correct GL image format constants
+        {LL_PROFILE_ZONE_NAMED("djh setformat raw");
+        placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
+            mMediaSource->getTextureFormatPrimary(),
+            mMediaSource->getTextureFormatType(),
+            mMediaSource->getTextureFormatSwapBytes());
+        }
+        {
+            LL_PROFILE_ZONE_NAMED("djh create ph");
+            int discard_level = 0;
+            placeholder_image->createGLTexture(discard_level, raw);
+        }
 
 		// MEDIAOPT: set this dynamically on play/stop
 		// FIXME
-- 
cgit v1.2.3


From 7dcca7f180c2204daefbc3648ebe766a46c7cf85 Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Fri, 14 Jan 2022 10:34:21 -0700
Subject: SL-16418 bg thread for media texture updates

---
 indra/newview/llviewermedia.cpp  | 179 +++++++++++++++++++++++++++++----------
 indra/newview/llviewermedia.h    |  36 +++++++-
 indra/newview/llviewerwindow.cpp |   6 +-
 3 files changed, 176 insertions(+), 45 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index ba9bbcc57e..8515d61f64 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -78,6 +78,9 @@
 #include <boost/bind.hpp>	// for SkinFolder listener
 #include <boost/signals2.hpp>
 
+// Statics
+bool LLMediaTextureUpdateThread::sEnabled = false;
+
 class LLMediaFilePicker : public LLFilePickerThread // deletes itself when done
 {
 public:
@@ -1591,6 +1594,8 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,
 		media_tex->setMediaImpl();
 	}
 
+    mMainQueue = LL::WorkQueue::getInstance("mainloop");
+    mTexUpdateQueue = LL::WorkQueue::getInstance("LLMediaTextureUpdate"); // Share work queue with tex loader.
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -1604,6 +1609,25 @@ LLViewerMediaImpl::~LLViewerMediaImpl()
 	remove_media_impl(this);
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+//static 
+void LLViewerMediaImpl::initClass(LLWindow* window, bool multi_threaded /* = false */)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    if (multi_threaded)
+    {
+        LLMediaTextureUpdateThread::createInstance(window);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+//static 
+void LLViewerMediaImpl::cleanupClass()
+{
+    LL_PROFILE_ZONE_SCOPED;
+    LLMediaTextureUpdateThread::deleteSingleton();
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event)
 {
@@ -2876,65 +2900,108 @@ void LLViewerMediaImpl::update()
 		return;
 	}
 
-	LLViewerMediaTexture* placeholder_image = updatePlaceholderImage();
+    ref();
 
-	if(placeholder_image)
-	{
-		LLRect dirty_rect;
+    if (preUpdateMediaTexture())
+    {
+        // Push update to worker thread
+        auto main_queue = LLMediaTextureUpdateThread::sEnabled ? mMainQueue.lock() : nullptr;
+        if (main_queue)
+        {
+            main_queue->postTo(
+                mTexUpdateQueue, // Worker thread queue
+                [this]() // work done on update worker thread
+                {
+                    doMediaTexUpdate();
+                },
+                [this]() // callback to main thread
+                {
+                    postUpdateMediaTexture();
+                    //unref();
+                });
+        }
+        else
+        {
+            doMediaTexUpdate(); // otherwise, update on main thread
+            //unref();
+        }
+    }
+    unref();
 
-		// Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered.
-		placeholder_image->setPlaying(TRUE);
+}
 
-		if(mMediaSource->getDirty(&dirty_rect))
-		{
-			// Constrain the dirty rect to be inside the texture
-			S32 x_pos = llmax(dirty_rect.mLeft, 0);
-			S32 y_pos = llmax(dirty_rect.mBottom, 0);
-			S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
-			S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
+//////////////////////////////////////////////////////////////////////////////////////////
+bool LLViewerMediaImpl::preUpdateMediaTexture()
+{
+    return true;
+}
 
-			if(width > 0 && height > 0)
-			{
+//////////////////////////////////////////////////////////////////////////////////////////
+bool LLViewerMediaImpl::postUpdateMediaTexture()
+{
+    return true;
+}
 
-				U8* data = NULL;
-				{
-					LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media get data"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
-					data = mMediaSource->getBitsData();
-				}
+//////////////////////////////////////////////////////////////////////////////////////////
+void LLViewerMediaImpl::doMediaTexUpdate()
+{
+    LLViewerMediaTexture* placeholder_image = updatePlaceholderImage();
 
-				if(data != NULL)
-				{
-					// Offset the pixels pointer to match x_pos and y_pos
-					data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() );
-					data += ( y_pos * mMediaSource->getTextureDepth() );
+    if (placeholder_image)
+    {
+        LLRect dirty_rect;
 
-					{
-						LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media set subimage"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
-									placeholder_image->setSubImage(
-									data,
-									mMediaSource->getBitsWidth(),
-									mMediaSource->getBitsHeight(),
-									x_pos,
-									y_pos,
-									width,
-									height);
-					}
-				}
+        // Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered.
+        placeholder_image->setPlaying(TRUE);
 
-			}
+        if (mMediaSource->getDirty(&dirty_rect))
+        {
+            // Constrain the dirty rect to be inside the texture
+            S32 x_pos = llmax(dirty_rect.mLeft, 0);
+            S32 y_pos = llmax(dirty_rect.mBottom, 0);
+            S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
+            S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
 
-			mMediaSource->resetDirty();
-		}
-	}
-}
+            if (width > 0 && height > 0)
+            {
 
+                U8* data = NULL;
+                {
+                    LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
+                    data = mMediaSource->getBitsData();
+                }
+
+                if (data != NULL)
+                {
+                    // Offset the pixels pointer to match x_pos and y_pos
+                    data += (x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth());
+                    data += (y_pos * mMediaSource->getTextureDepth());
+
+                    {
+                        LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
+                        placeholder_image->setSubImage(
+                            data,
+                            mMediaSource->getBitsWidth(),
+                            mMediaSource->getBitsHeight(),
+                            x_pos,
+                            y_pos,
+                            width,
+                            height);
+                    }
+                }
+
+            }
+
+            mMediaSource->resetDirty();
+        }
+    }
+}
 
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::updateImagesMediaStreams()
 {
 }
 
-
 //////////////////////////////////////////////////////////////////////////////////////////
 LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
 {
@@ -3927,3 +3994,29 @@ bool LLViewerMediaImpl::isObjectInAgentParcel(LLVOVolume *obj)
 {
 	return (LLViewerParcelMgr::getInstance()->inAgentParcel(obj->getPositionGlobal()));
 }
+
+LLMediaTextureUpdateThread::LLMediaTextureUpdateThread(LLWindow* window)
+// We want exactly one thread, of moderate capacity: there are likely only a handful
+// of media texture frames in-flight at any one time 
+    : ThreadPool("LLMediaTextureUpdate", 1, 4096)
+    , mWindow(window)
+{
+    LL_PROFILE_ZONE_SCOPED;
+    sEnabled = true;
+    mFinished = false;
+
+    mContext = mWindow->createSharedContext();
+    ThreadPool::start();
+}
+
+void LLMediaTextureUpdateThread::run()
+{
+    LL_PROFILE_ZONE_SCOPED;
+    // We must perform setup on this thread before actually servicing our
+    // WorkQueue, likewise cleanup afterwards.
+    mWindow->makeContextCurrent(mContext);
+    gGL.init();
+    ThreadPool::run();
+    gGL.shutdown();
+    mWindow->destroySharedContext(mContext);
+}
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index 71cec5125d..c2e6564166 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -197,7 +197,10 @@ public:
 		U8 media_loop);
 
 	~LLViewerMediaImpl();
-	
+
+    static void initClass(LLWindow* window, bool multi_threaded = false);
+    static void cleanupClass();
+
 	// Override inherited version from LLViewerMediaEventEmitter 
 	virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event);
 
@@ -266,6 +269,9 @@ public:
 	void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);
 
 	void update();
+    bool preUpdateMediaTexture();
+    void doMediaTexUpdate();
+    bool postUpdateMediaTexture();
 	void updateImagesMediaStreams();
 	LLUUID getMediaTextureID() const;
 	
@@ -490,6 +496,34 @@ private:
 
 private:
 	LLViewerMediaTexture *updatePlaceholderImage();
+    LL::WorkQueue::weak_t mMainQueue;
+    LL::WorkQueue::weak_t mTexUpdateQueue;
+
+};
+
+// Define a worker thread pool for media updates ( LLImageGLThread)
+class LLMediaTextureUpdateThread : public LLSimpleton<LLMediaTextureUpdateThread>, LL::ThreadPool
+{
+public:
+    // follows gSavedSettings "RenderGLMultiThreaded"
+    static bool sEnabled;
+
+    LLMediaTextureUpdateThread(LLWindow* window);
+
+    // post a function to be executed on the LLMediaTextureUpdateThread background thread
+    template <typename CALLABLE>
+    bool post(CALLABLE&& func)
+    {
+        return getQueue().postIfOpen(std::forward<CALLABLE>(func));
+    }
+
+    void run() override;
+
+private:
+    LLWindow* mWindow;
+    void* mContext = nullptr;
+    LLAtomicBool mFinished;
 };
 
+
 #endif	// LLVIEWERMEDIA_H
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index b9a5e90df0..ba93f4f5f9 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2027,6 +2027,9 @@ LLViewerWindow::LLViewerWindow(const Params& p)
 	gTextureList.init();
 	LLViewerTextureManager::init() ;
 	gBumpImageList.init();
+
+    // Init Media texture worker queue
+    LLViewerMediaImpl::initClass(mWindow, gSavedSettings.getBOOL("RenderGLMultiThreaded"));
 	
 	// Create container for all sub-views
 	LLView::Params rvp;
@@ -2416,7 +2419,8 @@ void LLViewerWindow::shutdownGL()
 
 	LLViewerTextureManager::cleanup() ;
 	SUBSYSTEM_CLEANUP(LLImageGL) ;
-
+    SUBSYSTEM_CLEANUP(LLViewerMediaImpl);
+    
 	LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ;
 
 	LL_INFOS() << "Cleaning up select manager" << LL_ENDL;
-- 
cgit v1.2.3


From 8d0efb54db96c87a2adb4a824998870ff397846e Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Thu, 27 Jan 2022 12:57:30 -0700
Subject: SL-16418 rename media tex image per-update to avoid contention stall

---
 indra/newview/llviewermedia.cpp   | 331 +++++++++++++++++++-------------------
 indra/newview/llviewermedia.h     |   7 +-
 indra/newview/llviewertexture.cpp |   1 +
 3 files changed, 172 insertions(+), 167 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 8515d61f64..de7aaf3173 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -39,6 +39,7 @@
 #include "llfilepicker.h"
 #include "llfloaterwebcontent.h"	// for handling window close requests and geometry change requests in media browser windows.
 #include "llfocusmgr.h"
+#include "llimagegl.h"
 #include "llkeyboard.h"
 #include "lllogininstance.h"
 #include "llmarketplacefunctions.h"
@@ -2824,165 +2825,156 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage");
 
 void LLViewerMediaImpl::update()
 {
-    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
-	if(mMediaSource == NULL)
-	{
-		if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
-		{
-			// This media source should not be loaded.
-		}
-		else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW)
-		{
-			// Don't load new instances that are at PRIORITY_SLIDESHOW or below.  They're just kept around to preserve state.
-		}
+    LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
+    if(mMediaSource == NULL)
+    {
+        if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
+        {
+            // This media source should not be loaded.
+        }
+        else if(mPriority <= LLPluginClassMedia::PRIORITY_SLIDESHOW)
+        {
+            // Don't load new instances that are at PRIORITY_SLIDESHOW or below.  They're just kept around to preserve state.
+        }
         else if (!mMimeProbe.expired())
-		{
-			// this media source is doing a MIME type probe -- don't try loading it again.
-		}
-		else
-		{
-			// This media may need to be loaded.
-			if(sMediaCreateTimer.hasExpired())
-			{
-				LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL;
-				createMediaSource();
-				sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY);
-			}
-			else
-			{
-				LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL;
-			}
-		}
-	}
-	else
-	{
-		updateVolume();
-
-		// TODO: this is updated every frame - is this bad?
-		// Removing this as part of the post viewer64 media update
-		// Removed as not implemented in CEF embedded browser
-		// See MAINT-8194 for a more fuller description
-		// updateJavascriptObject();
-	}
-
-
-	if(mMediaSource == NULL)
-	{
-		return;
-	}
+        {
+            // this media source is doing a MIME type probe -- don't try loading it again.
+        }
+        else
+        {
+            // This media may need to be loaded.
+            if(sMediaCreateTimer.hasExpired())
+            {
+                LL_DEBUGS("PluginPriority") << this << ": creating media based on timer expiration" << LL_ENDL;
+                createMediaSource();
+                sMediaCreateTimer.setTimerExpirySec(LLVIEWERMEDIA_CREATE_DELAY);
+            }
+            else
+            {
+                LL_DEBUGS("PluginPriority") << this << ": NOT creating media (waiting on timer)" << LL_ENDL;
+            }
+        }
+    }
+    else
+    {
+        updateVolume();
 
-	// Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash.
-	setNavigateSuspended(true);
+        // TODO: this is updated every frame - is this bad?
+        // Removing this as part of the post viewer64 media update
+        // Removed as not implemented in CEF embedded browser
+        // See MAINT-8194 for a more fuller description
+        // updateJavascriptObject();
+    }
 
-	mMediaSource->idle();
 
-	setNavigateSuspended(false);
+    if(mMediaSource == NULL)
+    {
+        return;
+    }
 
-	if(mMediaSource == NULL)
-	{
-		return;
-	}
+    // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash.
+    setNavigateSuspended(true);
 
-	if(mMediaSource->isPluginExited())
-	{
-		resetPreviousMediaState();
-		destroyMediaSource();
-		return;
-	}
+    mMediaSource->idle();
 
-	if(!mMediaSource->textureValid())
-	{
-		return;
-	}
+    setNavigateSuspended(false);
 
-	if(mSuspendUpdates || !mVisible)
-	{
-		return;
-	}
+    if(mMediaSource == NULL)
+    {
+        return;
+    }
 
-    ref();
+    if(mMediaSource->isPluginExited())
+    {
+        resetPreviousMediaState();
+        destroyMediaSource();
+        return;
+    }
 
-    if (preUpdateMediaTexture())
+    if(!mMediaSource->textureValid())
     {
-        // Push update to worker thread
-        auto main_queue = LLMediaTextureUpdateThread::sEnabled ? mMainQueue.lock() : nullptr;
-        if (main_queue)
-        {
-            main_queue->postTo(
-                mTexUpdateQueue, // Worker thread queue
-                [this]() // work done on update worker thread
-                {
-                    doMediaTexUpdate();
-                },
-                [this]() // callback to main thread
-                {
-                    postUpdateMediaTexture();
-                    //unref();
-                });
-        }
-        else
-        {
-            doMediaTexUpdate(); // otherwise, update on main thread
-            //unref();
-        }
+        return;
     }
-    unref();
 
-}
+    if(mSuspendUpdates || !mVisible)
+    {
+        return;
+    }
 
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::preUpdateMediaTexture()
-{
-    return true;
-}
 
-//////////////////////////////////////////////////////////////////////////////////////////
-bool LLViewerMediaImpl::postUpdateMediaTexture()
-{
-    return true;
+    // Push update to worker thread
+    auto main_queue = LLMediaTextureUpdateThread::sEnabled ? mMainQueue.lock() : nullptr;
+    ref();  // protect texture from deletion while active on bg queue
+    if (main_queue)
+    {
+        // replace GL name
+        //llassert(!mTextureId.isNull());
+        //LLImageGL* base_image = LLViewerTextureManager::getMediaTexture(mTextureId)->getGLTexture();
+        //GLuint retired_name = base_image->allocNew();
+        main_queue->postTo(
+            mTexUpdateQueue, // Worker thread queue
+            [this]() // work done on update worker thread
+            {
+                doMediaTexUpdate();
+            },
+            [this]() // callback to main thread
+            {
+                endMediaTexUpdate();
+                unref();
+            });
+    }
+    else
+    {
+        doMediaTexUpdate(); // otherwise, update on main thread
+        unref();
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::doMediaTexUpdate()
 {
-    LLViewerMediaTexture* placeholder_image = updatePlaceholderImage();
 
-    if (placeholder_image)
+    LLViewerMediaTexture* media_tex = updateMediaImage();
+
+    if (media_tex && mMediaSource)
     {
+        llassert(mMediaSource); 
+        
         LLRect dirty_rect;
+        S32 media_width = mMediaSource->getTextureWidth();
+        S32 media_height = mMediaSource->getTextureHeight();
+        S32 media_depth = mMediaSource->getTextureDepth();
 
         // Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered.
-        placeholder_image->setPlaying(TRUE);
+        media_tex->setPlaying(TRUE);
 
         if (mMediaSource->getDirty(&dirty_rect))
         {
             // Constrain the dirty rect to be inside the texture
             S32 x_pos = llmax(dirty_rect.mLeft, 0);
             S32 y_pos = llmax(dirty_rect.mBottom, 0);
-            S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos;
-            S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos;
+            S32 width = llmin(dirty_rect.mRight, media_width) - x_pos;
+            S32 height = llmin(dirty_rect.mTop, media_height) - y_pos;
 
             if (width > 0 && height > 0)
             {
-
                 U8* data = NULL;
-                {
-                    LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA);
-                    data = mMediaSource->getBitsData();
-                }
+                S32 data_width = mMediaSource->getBitsWidth();
+                S32 data_height = mMediaSource->getBitsHeight();
+                data = mMediaSource->getBitsData();
 
                 if (data != NULL)
                 {
                     // Offset the pixels pointer to match x_pos and y_pos
-                    data += (x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth());
-                    data += (y_pos * mMediaSource->getTextureDepth());
+                    data += (x_pos * media_depth * data_width);
+                    data += (y_pos * media_depth);
 
                     {
                         LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
-                        placeholder_image->setSubImage(
+                        media_tex->setSubImage(
                             data,
-                            mMediaSource->getBitsWidth(),
-                            mMediaSource->getBitsHeight(),
+                            data_width,
+                            data_height,
                             x_pos,
                             y_pos,
                             width,
@@ -2997,75 +2989,87 @@ void LLViewerMediaImpl::doMediaTexUpdate()
     }
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+// runs on main thread, but only called when bg thread updates are active
+void LLViewerMediaImpl::endMediaTexUpdate()
+{
+    LLViewerMediaTexture* base_image = LLViewerTextureManager::findMediaTexture(mTextureId);
+    llassert(base_image);
+
+    LLImageGL* image = base_image->getGLTexture();
+    image->swapTexName(); // retire old GL name
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::updateImagesMediaStreams()
 {
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage()
+LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage()
 {
-	if(mTextureId.isNull())
-	{
-		// The code that created this instance will read from the plugin's bits.
-		return NULL;
-	}
+    if (!mMediaSource)
+    {
+        return nullptr; // not ready for updating
+    }
 
-	LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId );
-    
-	if (mNeedsNewTexture
-		|| placeholder_image->getUseMipMaps()
-		|| (placeholder_image->getWidth() != mMediaSource->getTextureWidth())
-		|| (placeholder_image->getHeight() != mMediaSource->getTextureHeight())
-		|| (mTextureUsedWidth != mMediaSource->getWidth())
-		|| (mTextureUsedHeight != mMediaSource->getHeight())
-		)
-	{
-		LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL;
-		LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL;
-
-		int texture_width = mMediaSource->getTextureWidth();
-		int texture_height = mMediaSource->getTextureHeight();
-		int texture_depth = mMediaSource->getTextureDepth();
-
-		// MEDIAOPT: check to see if size actually changed before doing work
-            placeholder_image->destroyGLTexture();
-		// MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
-		placeholder_image->reinit(FALSE);	// probably not needed
+    llassert(!mTextureId.isNull());
+    LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId );
+ 
+    // if on bg thread, create new GL tex image resource to avoid resource contention
+    if (!on_main_thread())
+    {
+        LLImageGL* image = media_tex->getGLTexture();
+        image->allocNewTexName();
+    }
+
+    if ( mNeedsNewTexture
+        || media_tex->getUseMipMaps()
+        || (media_tex->getWidth() != mMediaSource->getTextureWidth())
+        || (media_tex->getHeight() != mMediaSource->getTextureHeight())
+        || (mTextureUsedWidth != mMediaSource->getWidth())
+        || (mTextureUsedHeight != mMediaSource->getHeight())
+        )
+    {
+        LL_DEBUGS("Media") << "initializing media placeholder" << LL_ENDL;
+        LL_DEBUGS("Media") << "movie image id " << mTextureId << LL_ENDL;
+
+        int texture_width = mMediaSource->getTextureWidth();
+        int texture_height = mMediaSource->getTextureHeight();
+        int texture_depth = mMediaSource->getTextureDepth();
+
+        // MEDIAOPT: check to see if size actually changed before doing work
+        media_tex->destroyGLTexture();
+        // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work?
+        media_tex->reinit(FALSE);	// probably not needed
 
         // MEDIAOPT: seems insane that we actually have to make an imageraw then
         // immediately discard it
         LLPointer<LLImageRaw> raw = new LLImageRaw(texture_width, texture_height, texture_depth);
         // Clear the texture to the background color, ignoring alpha.
         // convert background color channels from [0.0, 1.0] to [0, 255];
-        {LL_PROFILE_ZONE_NAMED("djh clear raw");
         raw->clear(int(mBackgroundColor.mV[VX] * 255.0f), int(mBackgroundColor.mV[VY] * 255.0f), int(mBackgroundColor.mV[VZ] * 255.0f), 0xff);
-        }
+
         // ask media source for correct GL image format constants
-        {LL_PROFILE_ZONE_NAMED("djh setformat raw");
-        placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
+        media_tex->setExplicitFormat(mMediaSource->getTextureFormatInternal(),
             mMediaSource->getTextureFormatPrimary(),
             mMediaSource->getTextureFormatType(),
             mMediaSource->getTextureFormatSwapBytes());
-        }
-        {
-            LL_PROFILE_ZONE_NAMED("djh create ph");
-            int discard_level = 0;
-            placeholder_image->createGLTexture(discard_level, raw);
-        }
 
-		// MEDIAOPT: set this dynamically on play/stop
-		// FIXME
-//		placeholder_image->mIsMediaTexture = true;
-		mNeedsNewTexture = false;
+        int discard_level = 0;
+        media_tex->createGLTexture(discard_level, raw);
 
-		// If the amount of the texture being drawn by the media goes down in either width or height,
-		// recreate the texture to avoid leaving parts of the old image behind.
-		mTextureUsedWidth = mMediaSource->getWidth();
-		mTextureUsedHeight = mMediaSource->getHeight();
-	}
+        // MEDIAOPT: set this dynamically on play/stop
+        // FIXME
+//		media_tex->mIsMediaTexture = true;
+        mNeedsNewTexture = false;
 
-	return placeholder_image;
+        // If the amount of the texture being drawn by the media goes down in either width or height,
+        // recreate the texture to avoid leaving parts of the old image behind.
+        mTextureUsedWidth = mMediaSource->getWidth();
+        mTextureUsedHeight = mMediaSource->getHeight();
+    }
+    return media_tex;
 }
 
 
@@ -4017,6 +4021,7 @@ void LLMediaTextureUpdateThread::run()
     mWindow->makeContextCurrent(mContext);
     gGL.init();
     ThreadPool::run();
+    LLMediaTextureUpdateThread::sEnabled = false;
     gGL.shutdown();
     mWindow->destroySharedContext(mContext);
 }
diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h
index c2e6564166..03a14421ff 100644
--- a/indra/newview/llviewermedia.h
+++ b/indra/newview/llviewermedia.h
@@ -269,9 +269,8 @@ public:
 	void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);
 
 	void update();
-    bool preUpdateMediaTexture();
     void doMediaTexUpdate();
-    bool postUpdateMediaTexture();
+    void endMediaTexUpdate();
 	void updateImagesMediaStreams();
 	LLUUID getMediaTextureID() const;
 	
@@ -495,13 +494,13 @@ private:
     bool mCanceling;
 
 private:
-	LLViewerMediaTexture *updatePlaceholderImage();
+	LLViewerMediaTexture *updateMediaImage();
     LL::WorkQueue::weak_t mMainQueue;
     LL::WorkQueue::weak_t mTexUpdateQueue;
 
 };
 
-// Define a worker thread pool for media updates ( LLImageGLThread)
+// Define a worker thread pool for media updates (ref LLImageGLThread)
 class LLMediaTextureUpdateThread : public LLSimpleton<LLMediaTextureUpdateThread>, LL::ThreadPool
 {
 public:
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5fed46f437..d652b76794 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1643,6 +1643,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
 #endif
             mNeedsCreateTexture = TRUE;
             auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
+            ref(); // protect texture from deletion while active on bg queue
             if (mainq)
             {
                 mainq->postTo(
-- 
cgit v1.2.3


From 7f1832c1ca0a18f34ba993f58ab2e05360bb36fd Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Thu, 27 Jan 2022 15:41:24 -0700
Subject: SL-16418 restore tracy macros stomped in merge

---
 indra/newview/llviewermedia.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index de7aaf3173..6c04321539 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -2825,7 +2825,7 @@ static LLTrace::BlockTimerStatHandle FTM_MEDIA_SET_SUBIMAGE("Set Subimage");
 
 void LLViewerMediaImpl::update()
 {
-    LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; //LL_RECORD_BLOCK_TIME(FTM_MEDIA_DO_UPDATE);
     if(mMediaSource == NULL)
     {
         if(mPriority == LLPluginClassMedia::PRIORITY_UNLOADED)
@@ -2933,7 +2933,7 @@ void LLViewerMediaImpl::update()
 //////////////////////////////////////////////////////////////////////////////////////////
 void LLViewerMediaImpl::doMediaTexUpdate()
 {
-
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
     LLViewerMediaTexture* media_tex = updateMediaImage();
 
     if (media_tex && mMediaSource)
@@ -2970,7 +2970,7 @@ void LLViewerMediaImpl::doMediaTexUpdate()
                     data += (y_pos * media_depth);
 
                     {
-                        LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
+                        LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media set subimage"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE);
                         media_tex->setSubImage(
                             data,
                             data_width,
@@ -2993,6 +2993,7 @@ void LLViewerMediaImpl::doMediaTexUpdate()
 // runs on main thread, but only called when bg thread updates are active
 void LLViewerMediaImpl::endMediaTexUpdate()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
     LLViewerMediaTexture* base_image = LLViewerTextureManager::findMediaTexture(mTextureId);
     llassert(base_image);
 
@@ -3008,6 +3009,7 @@ void LLViewerMediaImpl::updateImagesMediaStreams()
 //////////////////////////////////////////////////////////////////////////////////////////
 LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage()
 {
+    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA;
     if (!mMediaSource)
     {
         return nullptr; // not ready for updating
-- 
cgit v1.2.3


From c76f8f7bcc69b13885f22d425a1f29d3446c4c2a Mon Sep 17 00:00:00 2001
From: Dave Houlton <euclid@lindenlab.com>
Date: Thu, 27 Jan 2022 17:25:42 -0700
Subject: SL-16418 remove duplicated ref()

---
 indra/newview/llviewertexture.cpp | 1 -
 1 file changed, 1 deletion(-)

(limited to 'indra/newview')

diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index d652b76794..ccf4c5bbec 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1629,7 +1629,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
         mNeedsCreateTexture = TRUE;
         if (preCreateTexture())
         {
-            ref();
 #if LL_IMAGEGL_THREAD_CHECK
             //grab a copy of the raw image data to make sure it isn't modified pending texture creation
             U8* data = mRawImage->getData();
-- 
cgit v1.2.3