diff options
-rw-r--r-- | indra/newview/llviewermedia.cpp | 179 | ||||
-rw-r--r-- | indra/newview/llviewermedia.h | 36 | ||||
-rw-r--r-- | indra/newview/llviewerwindow.cpp | 6 |
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; |