summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorDave Houlton <euclid@lindenlab.com>2022-01-14 10:34:21 -0700
committerDave Houlton <euclid@lindenlab.com>2022-01-27 15:44:35 -0700
commit7dcca7f180c2204daefbc3648ebe766a46c7cf85 (patch)
tree6074e9b9ef3c06cf1e24267e80a200a7cbcc15a2 /indra/newview
parentc8926630af2b80c7db817b78df3a90378f0ecbbb (diff)
SL-16418 bg thread for media texture updates
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/llviewermedia.cpp179
-rw-r--r--indra/newview/llviewermedia.h36
-rw-r--r--indra/newview/llviewerwindow.cpp6
3 files changed, 176 insertions, 45 deletions
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.
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1605,6 +1610,25 @@ LLViewerMediaImpl::~LLViewerMediaImpl()
}
//////////////////////////////////////////////////////////////////////////////////////////
+//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)
{
// Broadcast to observers using the superclass version
@@ -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;