diff options
Diffstat (limited to 'indra')
-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; |