SL-16418 bg thread for media texture updates

meow-7.2.2
Dave Houlton 2022-01-14 10:34:21 -07:00
parent c8926630af
commit 7dcca7f180
3 changed files with 182 additions and 51 deletions

View File

@ -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;
if(width > 0 && height > 0)
{
U8* data = NULL;
{
LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media get data"); //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_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);
}
}
}
mMediaSource->resetDirty();
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
bool LLViewerMediaImpl::preUpdateMediaTexture()
{
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
bool LLViewerMediaImpl::postUpdateMediaTexture()
{
return true;
}
//////////////////////////////////////////////////////////////////////////////////////////
void LLViewerMediaImpl::doMediaTexUpdate()
{
LLViewerMediaTexture* placeholder_image = updatePlaceholderImage();
if (placeholder_image)
{
LLRect dirty_rect;
// 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;
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);
}

View File

@ -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

View File

@ -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;