diff options
| author | Dave Houlton <euclid@lindenlab.com> | 2022-01-14 10:34:21 -0700 | 
|---|---|---|
| committer | Dave Houlton <euclid@lindenlab.com> | 2022-01-27 15:44:35 -0700 | 
| commit | 7dcca7f180c2204daefbc3648ebe766a46c7cf85 (patch) | |
| tree | 6074e9b9ef3c06cf1e24267e80a200a7cbcc15a2 | |
| parent | c8926630af2b80c7db817b78df3a90378f0ecbbb (diff) | |
SL-16418 bg thread for media texture updates
| -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; | 
