diff options
| -rw-r--r-- | indra/llimage/llimage.cpp | 6 | ||||
| -rw-r--r-- | indra/llimage/llimage.h | 6 | ||||
| -rw-r--r-- | indra/llmath/llvolume.cpp | 2 | ||||
| -rw-r--r-- | indra/llrender/llgl.cpp | 11 | ||||
| -rw-r--r-- | indra/llrender/llgltexture.cpp | 12 | ||||
| -rw-r--r-- | indra/llrender/llgltexture.h | 14 | ||||
| -rw-r--r-- | indra/llrender/llimagegl.cpp | 139 | ||||
| -rw-r--r-- | indra/llrender/llimagegl.h | 14 | ||||
| -rw-r--r-- | indra/llrender/llrender.cpp | 20 | ||||
| -rw-r--r-- | indra/newview/llviewermedia.cpp | 393 | ||||
| -rw-r--r-- | indra/newview/llviewermedia.h | 13 | ||||
| -rw-r--r-- | indra/newview/llviewerwindow.cpp | 6 | 
12 files changed, 398 insertions, 238 deletions
| diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 15b07e5318..5fa19ce9c6 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -860,6 +860,12 @@ U8* LLImageRaw::reallocateData(S32 size)  	return res;  } +void LLImageRaw::releaseData() +{ +    LLImageBase::setSize(0, 0, 0); +    LLImageBase::setDataAndSize(nullptr, 0); +} +  // virtual  void LLImageRaw::deleteData()  { diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 354926ee58..7a588cfb03 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -191,6 +191,12 @@ public:  	/*virtual*/ void deleteData();  	/*virtual*/ U8* allocateData(S32 size = -1);  	/*virtual*/ U8* reallocateData(S32 size); + +    // use in conjunction with "no_copy" constructor to release data pointer before deleting +    // so that deletion of this LLImageRaw will not free the memory at the "data" parameter  +    // provided to "no_copy" constructor +    void releaseData(); +  	bool resize(U16 width, U16 height, S8 components); diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index e9ccde5fae..d91a973153 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -88,7 +88,7 @@ const F32 SKEW_MAX	=  0.95f;  const F32 SCULPT_MIN_AREA = 0.002f;  const S32 SCULPT_MIN_AREA_DETAIL = 1; -BOOL gDebugGL = FALSE; +BOOL gDebugGL = FALSE; // See settings.xml "RenderDebugGL"  BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)  {     diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 922fcb867b..50a5972d28 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -757,17 +757,6 @@ bool LLGLManager::initGL()  	stop_glerror(); -#if LL_WINDOWS -	if (mHasDebugOutput && gDebugGL) -	{ //setup debug output callback -		//glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE); -		glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); -		glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); -	} -#endif - -	stop_glerror(); -  	//HACK always disable texture multisample, use FXAA instead  	mHasTextureMultisample = FALSE;  #if LL_WINDOWS diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp index b6a02f1c0a..c7de8bc338 100644 --- a/indra/llrender/llgltexture.cpp +++ b/indra/llrender/llgltexture.cpp @@ -164,11 +164,11 @@ BOOL LLGLTexture::createGLTexture()  	return mGLTexturep->createGLTexture() ;  } -BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category) +BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category, bool defer_copy)  {  	llassert(mGLTexturep.notNull()) ;	 -	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ; +	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category, defer_copy) ;  	if(ret)  	{ @@ -260,20 +260,20 @@ LLTexUnit::eTextureType LLGLTexture::getTarget(void) const  	return mGLTexturep->getTarget() ;  } -BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, bool use_new_name /* = false */)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	llassert(mGLTexturep.notNull()) ; -	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ; +	return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height, 0, use_new_name) ;  } -BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool use_new_name /* = false */)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	llassert(mGLTexturep.notNull()) ; -	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ; +	return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height, 0, use_new_name) ;  }  void LLGLTexture::setGLTextureCreated (bool initialized) diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h index 028457c510..216e7f640d 100644 --- a/indra/llrender/llgltexture.h +++ b/indra/llrender/llgltexture.h @@ -124,13 +124,21 @@ public:  	BOOL       hasGLTexture() const ;  	LLGLuint   getTexName() const ;		  	BOOL       createGLTexture() ; -	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER); +	 +    // Create a GL Texture from an image raw +    // discard_level - mip level, 0 for highest resultion mip +    // imageraw - the image to copy from +    // usename - explicit GL name override +    // to_create - set to FALSE to force gl texture to not be created +    // category - LLGLTexture category for this LLGLTexture +    // defer_copy - set to true to allocate GL texture but NOT initialize with imageraw data +    BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER, bool defer_copy = false);  	void       setFilteringOption(LLTexUnit::eTextureFilterOptions option);  	void       setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);  	void       setAddressMode(LLTexUnit::eTextureAddressMode mode); -	BOOL       setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); -	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); +	BOOL       setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, bool use_new_name = false); +	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool use_new_name = false);  	void       setGLTextureCreated (bool initialized);  	void       setCategory(S32 category) ;      void       setTexName(LLGLuint); // for forcing w/ externally created textures only diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 1e9b9f642e..694c4a7b06 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -550,7 +550,7 @@ bool LLImageGL::setSize(S32 width, S32 height, S32 ncomponents, S32 discard_leve  	if (width != mWidth || height != mHeight || ncomponents != mComponents)  	{  		// Check if dimensions are a power of two! -		if (!checkSize(width,height)) +		if (!checkSize(width, height))  		{  			LL_WARNS() << llformat("Texture has non power of two dimension: %dx%d",width,height) << LL_ENDL;  			return false; @@ -674,7 +674,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)  	setImage(rawdata, FALSE);  } -BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename) +BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 usename /* = 0 */)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	bool is_compressed = false; @@ -709,8 +709,14 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)      gGL.getTexUnit(0)->bind(this, false, false, usename); - -    if (mUseMipMaps) +    if (data_in == nullptr) +    { +        S32 w = getWidth(); +        S32 h = getHeight(); +        LLImageGL::setManualImage(mTarget, 0, mFormatInternal, w, h, +            mFormatPrimary, mFormatType, (GLvoid*)data_in, mAllowCompression); +    } +    else if (mUseMipMaps)  	{  		if (data_hasmips)  		{ @@ -1069,14 +1075,14 @@ void LLImageGL::postAddToAtlas()  	stop_glerror();	  } -BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) +BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, bool use_new_name /* = false */)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;  	if (!width || !height)  	{  		return TRUE;  	} -	if (mTexName == 0) +	if (0 == (use_new_name ? mNewTexName : mTexName))  	{  		// *TODO: Re-enable warning?  Ran into thread locking issues? DK 2011-02-18  		//LL_WARNS() << "Setting subimage on image without GL texture" << LL_ENDL; @@ -1092,7 +1098,7 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3  	// HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture.  	if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height)  	{ -		setImage(datap, FALSE); +		setImage(datap, FALSE, use_new_name ? mNewTexName : mTexName);  	}  	else  	{ @@ -1144,12 +1150,11 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3  		datap += (y_pos * data_width + x_pos) * getComponents();  		// Update the GL texture -		BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, mTexName); +		BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, use_new_name ? mNewTexName : mTexName);  		if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL;  		stop_glerror(); -		glTexSubImage2D(mTarget, 0, x_pos, y_pos,  -						width, height, mFormatPrimary, mFormatType, datap); +		glTexSubImage2D(mTarget, 0, x_pos, y_pos, width, height, mFormatPrimary, mFormatType, datap);  		gGL.getTexUnit(0)->disable();  		stop_glerror(); @@ -1166,10 +1171,10 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3  	return TRUE;  } -BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) +BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, bool use_new_name /* = false */)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; -	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update); +	return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update, use_new_name);  }  // Copy sub image from frame buffer @@ -1356,7 +1361,7 @@ BOOL LLImageGL::createGLTexture()  	return TRUE ;  } -BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category) +BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category, bool defer_copy)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;      checkActiveThread(); @@ -1386,6 +1391,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S  	// Actual image width/height = raw image width/height * 2^discard_level  	S32 raw_w = imageraw->getWidth() ;  	S32 raw_h = imageraw->getHeight() ; +  	S32 w = raw_w << discard_level;  	S32 h = raw_h << discard_level; @@ -1468,15 +1474,24 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S  	setCategory(category);   	const U8* rawdata = imageraw->getData(); -	return createGLTexture(discard_level, rawdata, FALSE, usename); +	return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy);  } -BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) +BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename, bool defer_copy) +    // Call with void data, vmem is allocated but unitialized  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;      checkActiveThread(); -    llassert(data_in); +    if (defer_copy) +    { +        data_in = nullptr; +    } +    else +    { +        llassert(data_in); +    } +      stop_glerror();      if (discard_level < 0) @@ -1486,7 +1501,8 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      }      discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); -    if (mTexName != 0 && discard_level == mCurrentDiscardLevel) +    if (!defer_copy // <--- hacky way to force creation of mNewTexName from media texture update +        && mTexName != 0 && discard_level == mCurrentDiscardLevel)      {          // This will only be true if the size has not changed          return setImage(data_in, data_hasmips); @@ -1534,36 +1550,12 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      }      //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread -    if (! on_main_thread()) +    if (!on_main_thread())      { +        if (!defer_copy)          { -            LL_PROFILE_ZONE_NAMED("cglt - sync"); -            if (gGLManager.mHasSync) -            { -                auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); -                glClientWaitSync(sync, 0, 0); -                glDeleteSync(sync); -            } -            else -            { -                glFinish(); -            } +            syncToMainThread();          } - -        ref(); -        LL::WorkQueue::postMaybe( -            mMainQueue, -            [=]() -            { -                LL_PROFILE_ZONE_NAMED("cglt - delete callback"); -                if (old_texname != 0) -                { -                    LLImageGL::deleteTextures(1, &old_texname); -                } -                mTexName = mNewTexName; -                mNewTexName = 0; -                unref(); -            });      }      else       { @@ -1587,6 +1579,55 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_      return TRUE;  } +void LLImageGL::syncToMainThread() +{ +    { +        LL_PROFILE_ZONE_NAMED("cglt - sync"); +        if (gGLManager.mHasSync) +        { +            // post a sync to the main thread (will execute before tex name swap lambda below) +            auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); +            glFlush(); +            LL::WorkQueue::postMaybe( +                mMainQueue, +                [=]() +                { +                    LL_PROFILE_ZONE_NAMED("cglt - wait sync"); +                    { +                        LL_PROFILE_ZONE_NAMED("glWaitSync"); +                        glWaitSync(sync, 0, GL_TIMEOUT_IGNORED); +                    } +                    { +                        LL_PROFILE_ZONE_NAMED("glDeleteSync"); +                        glDeleteSync(sync); +                    } +                }); +        } +        else +        { +            glFinish(); +        } +    } + +    ref(); +    LL::WorkQueue::postMaybe( +        mMainQueue, +        [=]() +        { +            LL_PROFILE_ZONE_NAMED("cglt - delete callback"); +            if (mNewTexName != 0) +            { +                if (mTexName != 0) +                { +                    LLImageGL::deleteTextures(1, &mTexName); +                } +                mTexName = mNewTexName; +                mNewTexName = 0; +                unref(); +            } +        }); +} +  BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const  {  	llassert_always(sAllowReadBackRaw) ; @@ -1714,7 +1755,15 @@ void LLImageGL::destroyGLTexture()  		mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.  		mTexName = 0;		  		mGLTextureCreated = FALSE ; -	}	 +	} + +    // clean up any in-flight name change +    if (0 != mNewTexName) +    { +        // Memory is transient, not tracked by sGlobalTextuerMemory +        LLImageGL::deleteTextures(1, &mNewTexName); +        mNewTexName = 0; +    }  }  //force to invalidate the gl texture, most likely a sculpty texture diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index d6f4b13a51..6c6e327e42 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -110,14 +110,18 @@ public:  	BOOL createGLTexture() ;  	BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, -		S32 category = sMaxCategories-1); -	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); +		S32 category = sMaxCategories-1, bool defer_copy = false); +	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false);  	void setImage(const LLImageRaw* imageraw);  	BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE, S32 usename = 0); -	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); -	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); +	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, bool use_new_name = false); +	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, bool use_new_name = false);  	BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); -	 + +    // wait for gl commands to finish on current thread and push +    // a lambda to main thread to swap mNewTexName and mTexName +    void syncToMainThread(); +  	// Read back a raw image for this discard level, if it exists  	BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;  	void destroyGLTexture(); diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 92d8e6193f..a03a27cf94 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -36,6 +36,17 @@  #include "lltexture.h"  #include "llshadermgr.h" +#if LL_WINDOWS +extern void APIENTRY gl_debug_callback(GLenum source, +                                GLenum type, +                                GLuint id, +                                GLenum severity, +                                GLsizei length, +                                const GLchar* message, +                                GLvoid* userParam) +; +#endif +  thread_local LLRender gGL;  // Handy copies of last good GL matrices @@ -860,6 +871,15 @@ LLRender::~LLRender()  void LLRender::init()  { +#if LL_WINDOWS +    if (gGLManager.mHasDebugOutput && gDebugGL) +    { //setup debug output callback +        //glDebugMessageControlARB(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE); +        glDebugMessageCallbackARB((GLDEBUGPROCARB) gl_debug_callback, NULL); +        glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB); +    } +#endif +      glPixelStorei(GL_PACK_ALIGNMENT, 1);      glPixelStorei(GL_UNPACK_ALIGNMENT, 1); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 63f57e81cc..bd60b9f1e2 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" @@ -635,6 +636,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"); @@ -654,6 +656,13 @@ void LLViewerMedia::updateMedia(void *dummy_arg)  	// Enable/disable the plugin read thread  	LLPluginProcessParent::setUseReadThread(gSavedSettings.getBOOL("PluginUseReadThread")); +    // SL-16418 We can't call LLViewerMediaImpl->update() if we are in the state of shutting down. +    if(LLApp::isExiting()) +    { +        setAllMediaEnabled(false); +        return; +    } +  	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.  	// 2017-04-19 Removed CP - this doesn't appear to buy us much and consumes a lot of resources so  	// removing it for now. @@ -1590,6 +1599,8 @@ LLViewerMediaImpl::LLViewerMediaImpl(	  const LLUUID& texture_id,  		media_tex->setMediaImpl();  	} +    mMainQueue = LL::WorkQueue::getInstance("mainloop"); +    mTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -1676,11 +1687,13 @@ void LLViewerMediaImpl::destroyMediaSource()  	cancelMimeTypeProbe(); +    mLock.lock();   // Delay tear-down while bg thread is updating  	if(mMediaSource)  	{  		mMediaSource->setDeleteOK(true) ;  		mMediaSource = NULL; // shared pointer  	} +    mLock.unlock();  }  ////////////////////////////////////////////////////////////////////////////////////////// @@ -2087,6 +2100,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 @@ -2799,199 +2813,256 @@ 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. -		} +    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(); +        { +            // 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(); -	} +        // 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; -	} +    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); +    // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. +    setNavigateSuspended(true); -	mMediaSource->idle(); +    mMediaSource->idle(); -	setNavigateSuspended(false); +    setNavigateSuspended(false); -	if(mMediaSource == NULL) -	{ -		return; -	} +    if(mMediaSource == NULL) +    { +        return; +    } -	if(mMediaSource->isPluginExited()) -	{ -		resetPreviousMediaState(); -		destroyMediaSource(); -		return; -	} +    if(mMediaSource->isPluginExited()) +    { +        resetPreviousMediaState(); +        destroyMediaSource(); +        return; +    } -	if(!mMediaSource->textureValid()) -	{ -		return; -	} +    if(!mMediaSource->textureValid()) +    { +        return; +    } -	if(mSuspendUpdates || !mVisible) -	{ -		return; -	} +    if(mSuspendUpdates || !mVisible) +    { +        return; +    } -	LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); +     +    LLViewerMediaTexture* media_tex; +    U8* data; +    S32 data_width; +    S32 data_height; +    S32 x_pos; +    S32 y_pos; +    S32 width; +    S32 height; + +    if (preMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height)) +    { +        // Push update to worker thread +        auto main_queue = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr; +        if (main_queue) +        { +            mTextureUpdatePending = true; +            ref();  // protect texture from deletion while active on bg queue +            media_tex->ref(); +            main_queue->postTo( +                mTexUpdateQueue, // Worker thread queue +                [=]() // work done on update worker thread +                { +                    doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, true); +                }, +                [=]() // callback to main thread +                { +                    mTextureUpdatePending = false; +                    media_tex->unref(); +                    unref(); +                }); +        } +        else +        { +            doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, false); // otherwise, update on main thread +        } +    } +} -	if(placeholder_image) -	{ -		LLRect dirty_rect; +bool LLViewerMediaImpl::preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height) +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; -		// 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); +    bool retval = false; -		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 (!mTextureUpdatePending) +    { +        media_tex = updateMediaImage(); -			if(width > 0 && height > 0) -			{ +        if (media_tex && mMediaSource) +        { +            LLRect dirty_rect; +            S32 media_width = mMediaSource->getTextureWidth(); +            S32 media_height = mMediaSource->getTextureHeight(); +            //S32 media_depth = mMediaSource->getTextureDepth(); -				U8* data = NULL; -				{ -					LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media get data"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA); -					data = mMediaSource->getBitsData(); -				} +            // Since we're updating this texture, we know it's playing.  Tell the texture to do its replacement magic so it gets rendered. +            media_tex->setPlaying(TRUE); -				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 (mMediaSource->getDirty(&dirty_rect)) +            { +                // Constrain the dirty rect to be inside the texture +                x_pos = llmax(dirty_rect.mLeft, 0); +                y_pos = llmax(dirty_rect.mBottom, 0); +                width = llmin(dirty_rect.mRight, media_width) - x_pos; +                height = llmin(dirty_rect.mTop, media_height) - y_pos; -					{ -						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); -					} -				} +                if (width > 0 && height > 0) +                { +                    data = mMediaSource->getBitsData(); +                    data_width = mMediaSource->getWidth(); +                    data_height = mMediaSource->getHeight(); + +                    if (data != NULL) +                    { +                        // data is ready to be copied to GL +                        retval = true; +                    } +                } -			} +                mMediaSource->resetDirty(); +            } +        } +    } -			mMediaSource->resetDirty(); -		} -	} +    return retval;  } +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync) +{ +    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; +    mLock.lock();   // don't allow media source tear-down during update + +    // wrap "data" in an LLImageRaw but do NOT make a copy +    LLPointer<LLImageRaw> raw = new LLImageRaw(data, media_tex->getWidth(), media_tex->getHeight(), media_tex->getComponents(), true); +         +    // Allocate GL texture based on LLImageRaw but do NOT copy to GL +    media_tex->createGLTexture(0, raw, 0, TRUE, LLGLTexture::OTHER, true); + +    // copy just the subimage covered by the image raw to GL +    media_tex->setSubImage(data, data_width, data_height, x_pos, y_pos, width, height, sync); +    media_tex->getGLTexture()->syncToMainThread(); +     +    // release the data pointer before freeing raw so LLImageRaw destructor doesn't +    // free memory at data pointer +    raw->releaseData(); + +    mLock.unlock(); +}  //////////////////////////////////////////////////////////////////////////////////////////  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; -	} - -	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 - -		// 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: set this dynamically on play/stop -		// FIXME -//		placeholder_image->mIsMediaTexture = true; -		mNeedsNewTexture = false; - -		// 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(); -	} +    LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; +    if (!mMediaSource) +    { +        return nullptr; // not ready for updating +    } -	return placeholder_image; +    llassert(!mTextureId.isNull()); +    LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId ); +  +    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]; +        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 +        media_tex->setExplicitFormat(mMediaSource->getTextureFormatInternal(), +            mMediaSource->getTextureFormatPrimary(), +            mMediaSource->getTextureFormatType(), +            mMediaSource->getTextureFormatSwapBytes()); + +        int discard_level = 0; +        media_tex->createGLTexture(discard_level, raw); + +        // MEDIAOPT: set this dynamically on play/stop +        // FIXME +//		media_tex->mIsMediaTexture = true; +        mNeedsNewTexture = false; + +        // 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;  } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 71cec5125d..806692929a 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -197,7 +197,7 @@ public:  		U8 media_loop);  	~LLViewerMediaImpl(); -	 +  	// Override inherited version from LLViewerMediaEventEmitter   	virtual void emitEvent(LLPluginClassMedia* self, LLViewerMediaObserver::EMediaEvent event); @@ -266,6 +266,8 @@ public:  	void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y);  	void update(); +    bool preMediaTexUpdate(LLViewerMediaTexture*& media_tex, U8*& data, S32& data_width, S32& data_height, S32& x_pos, S32& y_pos, S32& width, S32& height); +    void doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* data, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, bool sync);  	void updateImagesMediaStreams();  	LLUUID getMediaTextureID() const; @@ -427,6 +429,7 @@ private:  private:  	// a single media url with some data and an impl.  	boost::shared_ptr<LLPluginClassMedia> mMediaSource; +    LLMutex mLock;  	F64		mZoomFactor;  	LLUUID mTextureId;  	bool  mMovieImageHasMips; @@ -446,6 +449,7 @@ private:  	S32 mTextureUsedWidth;  	S32 mTextureUsedHeight;  	bool mSuspendUpdates; +    bool mTextureUpdatePending = false;  	bool mVisible;  	ECursorType mLastSetCursor;  	EMediaNavState mMediaNavState; @@ -479,7 +483,7 @@ private:  	LLNotificationPtr mNotification;      bool mCleanBrowser;     // force the creation of a clean browsing target with full options enabled      static std::vector<std::string> sMimeTypesFailed; - +    LLPointer<LLImageRaw> mRawImage; //backing buffer for texture updates  private:  	BOOL mIsUpdated ;  	std::list< LLVOVolume* > mObjectList ; @@ -489,7 +493,10 @@ private:      bool mCanceling;  private: -	LLViewerMediaTexture *updatePlaceholderImage(); +	LLViewerMediaTexture *updateMediaImage(); +    LL::WorkQueue::weak_t mMainQueue; +    LL::WorkQueue::weak_t mTexUpdateQueue; +  };  #endif	// LLVIEWERMEDIA_H diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index b9a5e90df0..80850265bc 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2023,12 +2023,12 @@ LLViewerWindow::LLViewerWindow(const Params& p)  	// Init the image list.  Must happen after GL is initialized and before the images that  	// LLViewerWindow needs are requested. -	LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded")); +    LLImageGL::initClass(mWindow, LLViewerTexture::MAX_GL_IMAGE_CATEGORY, false, gSavedSettings.getBOOL("RenderGLMultiThreaded"));  	gTextureList.init();  	LLViewerTextureManager::init() ;  	gBumpImageList.init(); -	// Create container for all sub-views +    // Create container for all sub-views  	LLView::Params rvp;  	rvp.name("root");  	rvp.rect(mWindowRectScaled); @@ -2416,7 +2416,7 @@ void LLViewerWindow::shutdownGL()  	LLViewerTextureManager::cleanup() ;  	SUBSYSTEM_CLEANUP(LLImageGL) ; - +      	LL_INFOS() << "All textures and llimagegl images are destroyed!" << LL_ENDL ;  	LL_INFOS() << "Cleaning up select manager" << LL_ENDL; | 
