From 8d20480c5f77fe1fab8149d3cda79bdd61e77656 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Thu, 28 Oct 2021 18:06:21 +0000 Subject: SL-16148 SL-16244 SL-16270 SL-16253 Remove most BlockTimers, remove LLMemTracked, introduce alignas, hook most/all reamining allocs, disable synchronous occlusion, and convert frequently accessed LLSingletons to LLSimpleton --- indra/llimage/llimage.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index aed8943439..5c49ec02ea 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -623,8 +623,7 @@ void LLImage::setLastError(const std::string& message) //--------------------------------------------------------------------------- LLImageBase::LLImageBase() -: LLTrace::MemTrackable("LLImage"), - mData(NULL), +: mData(NULL), mDataSize(0), mWidth(0), mHeight(0), @@ -673,7 +672,6 @@ void LLImageBase::sanityCheck() void LLImageBase::deleteData() { ll_aligned_free_16(mData); - disclaimMem(mDataSize); mDataSize = 0; mData = NULL; } @@ -731,7 +729,6 @@ U8* LLImageBase::allocateData(S32 size) } } mDataSize = size; - claimMem(mDataSize); return mData; } @@ -752,9 +749,7 @@ U8* LLImageBase::reallocateData(S32 size) ll_aligned_free_16(mData) ; } mData = new_datap; - disclaimMem(mDataSize); mDataSize = size; - claimMem(mDataSize); mBadBufferAllocation = false; return mData; } @@ -2258,9 +2253,7 @@ void LLImageBase::setDataAndSize(U8 *data, S32 size) { ll_assert_aligned(data, 16); mData = data; - disclaimMem(mDataSize); mDataSize = size; - claimMem(mDataSize); } //static -- cgit v1.3 From c8926630af2b80c7db817b78df3a90378f0ecbbb Mon Sep 17 00:00:00 2001 From: Dave Houlton Date: Tue, 11 Jan 2022 17:29:04 -0700 Subject: SL-16418 optimize imageraw clear --- indra/llimage/llimage.cpp | 88 +++++++++++++++++++++++++---------------- indra/newview/llviewermedia.cpp | 41 +++++++++++-------- 2 files changed, 77 insertions(+), 52 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 15b07e5318..2855612158 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -925,47 +925,65 @@ bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) { - llassert( getComponents() <= 4 ); - // This is fairly bogus, but it'll do for now. - if (isBufferInvalid()) - { - LL_WARNS() << "Invalid image buffer" << LL_ENDL; - return; - } + LL_PROFILE_ZONE_NAMED("djh imageraw clear") + S8 components = getComponents(); + llassert( components > 0 && components <= 4 ); - U8 *pos = getData(); - U32 x, y; - for (x = 0; x < getWidth(); x++) - { - for (y = 0; y < getHeight(); y++) - { - *pos = r; - pos++; - if (getComponents() == 1) - { - continue; - } - *pos = g; - pos++; - if (getComponents() == 2) - { - continue; - } - *pos = b; - pos++; - if (getComponents() == 3) - { - continue; - } - *pos = a; - pos++; - } - } + // This is fairly bogus, but it'll do for now. + if (isBufferInvalid()) + { + LL_WARNS() << "Invalid image buffer" << LL_ENDL; + return; + } + + switch (components) + { + case 1: + { + U8 *dst = getData(); + S32 count = getWidth() * getHeight(); + llassert(count == getDataSize()); + std::fill_n(dst, count, r); + break; + } + case 2: + { + U16 *dst = (U16 *)getData(); + S32 count = getWidth() * getHeight(); + llassert(count == getDataSize() / 2); + U16 val = (U16)(r | g << 8); + std::fill_n(dst, count, val); + break; + } + case 3: + { + U8 *dst = getData(); + S32 count = getWidth() * getHeight(); + llassert(count == getDataSize() / 3); + for (S32 i = 0; i < count; i++) + { + *dst++ = r; + *dst++ = g; + *dst++ = b; + } + break; + } + case 4: + { + U32 *dst = (U32 *)getData(); + S32 count = getWidth() * getHeight(); + llassert(count == getDataSize() / 4); + U32 val = (U32)(r | g << 8 | b << 16 | a << 24); + std::fill_n(dst, count, val); + break; + } + } } // Reverses the order of the rows in the image void LLImageRaw::verticalFlip() { + LL_PROFILE_ZONE_SCOPED; S32 row_bytes = getWidth() * getComponents(); llassert(row_bytes > 0); std::vector line_buffer(row_bytes); diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 63f57e81cc..ba9bbcc57e 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -635,6 +635,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"); @@ -2087,6 +2088,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 @@ -2943,7 +2945,7 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() } LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); - + if (mNeedsNewTexture || placeholder_image->getUseMipMaps() || (placeholder_image->getWidth() != mMediaSource->getTextureWidth()) @@ -2960,25 +2962,30 @@ LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() int texture_depth = mMediaSource->getTextureDepth(); // MEDIAOPT: check to see if size actually changed before doing work - placeholder_image->destroyGLTexture(); + 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 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: seems insane that we actually have to make an imageraw then + // immediately discard it + LLPointer 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]; + {LL_PROFILE_ZONE_NAMED("djh clear raw"); + 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 + {LL_PROFILE_ZONE_NAMED("djh setformat raw"); + placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + mMediaSource->getTextureFormatSwapBytes()); + } + { + LL_PROFILE_ZONE_NAMED("djh create ph"); + int discard_level = 0; + placeholder_image->createGLTexture(discard_level, raw); + } // MEDIAOPT: set this dynamically on play/stop // FIXME -- cgit v1.3 From 8d0efb54db96c87a2adb4a824998870ff397846e Mon Sep 17 00:00:00 2001 From: Dave Houlton Date: Thu, 27 Jan 2022 12:57:30 -0700 Subject: SL-16418 rename media tex image per-update to avoid contention stall --- indra/llimage/llimage.cpp | 2 +- indra/llrender/llimagegl.cpp | 66 ++++++-- indra/llrender/llimagegl.h | 10 +- indra/newview/llviewermedia.cpp | 331 +++++++++++++++++++------------------- indra/newview/llviewermedia.h | 7 +- indra/newview/llviewertexture.cpp | 1 + 6 files changed, 234 insertions(+), 183 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 2855612158..fb02a131fd 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -925,7 +925,7 @@ bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) { - LL_PROFILE_ZONE_NAMED("djh imageraw clear") + LL_PROFILE_ZONE_SCOPED; S8 components = getComponents(); llassert( components > 0 && components <= 4 ); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 1e9b9f642e..4b4f071171 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1215,9 +1215,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) { //GL_ALPHA is deprecated, convert to RGBA use_scratch = true; - scratch = new U32[width * height]; - U32 pixel_count = (U32)(width * height); + scratch = new U32[pixel_count]; for (U32 i = 0; i < pixel_count; i++) { U8* pix = (U8*)&scratch[i]; @@ -1232,9 +1231,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA use_scratch = true; - scratch = new U32[width * height]; - U32 pixel_count = (U32)(width * height); + scratch = new U32[pixel_count]; for (U32 i = 0; i < pixel_count; i++) { U8 lum = ((U8*)pixels)[i * 2 + 0]; @@ -1252,9 +1250,8 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB use_scratch = true; - scratch = new U32[width * height]; - U32 pixel_count = (U32)(width * height); + scratch = new U32[pixel_count]; for (U32 i = 0; i < pixel_count; i++) { U8 lum = ((U8*)pixels)[i]; @@ -1314,10 +1311,7 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt } stop_glerror(); - if (use_scratch) - { - delete[] scratch; - } + if (scratch) delete[] scratch; } //create an empty GL texture: just create a texture name @@ -1471,7 +1465,49 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S return createGLTexture(discard_level, rawdata, FALSE, usename); } -BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) +// Create a new GL name and allocate tex storage (unitialized) for it +// Used to break resource contention stall in background media tex updates +void LLImageGL::allocNewTexName() +{ + LL_PROFILE_ZONE_SCOPED; + if (on_main_thread()) return; // Should only be called on bg update thread + if (!mGLTextureCreated) return; + if (0 != mNewTexName) return; // only 1 rename in flight at a time + + generateTextures(1, &mNewTexName); // create new GL name + + mHasMipMaps = false; // Media textures aren't mipped + mMipLevels = 0; + // Set state to match current + gGL.getTexUnit(0)->bind(this, false, false, mNewTexName); + glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel); + glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_WIDTH, mWidth); + glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_HEIGHT, mHeight); + gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps); + gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode); + gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); + + setManualImage(mTarget, 0, mFormatInternal, mWidth, mHeight, mFormatPrimary, mFormatType, + (GLvoid *) nullptr, mAllowCompression); + + gGL.getTexUnit(0)->unbind(mBindTarget); + + mLastBindTime = sLastFrameTime; +} + +// Delete no-longer-needed GL tex name (on main thread) +void LLImageGL::swapTexName() +{ + if (mNewTexName) + { + deleteTextures(1, &mTexName); + mTexName = mNewTexName; + mNewTexName = 0; + } +} + +BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 usename /* = 0 */) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; checkActiveThread(); @@ -1715,6 +1751,14 @@ void LLImageGL::destroyGLTexture() 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..f311170823 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -109,15 +109,17 @@ public: static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); 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 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); - void setImage(const LLImageRaw* imageraw); + 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 setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); - + + void allocNewTexName(); + void swapTexName(); + // 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/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 8515d61f64..de7aaf3173 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" @@ -2824,165 +2825,156 @@ 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. - } + 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. + } 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(); - - // 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; - } + { + // 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(); - // Make sure a navigate doesn't happen during the idle -- it can cause mMediaSource to get destroyed, which can cause a crash. - setNavigateSuspended(true); + // 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(); + } - mMediaSource->idle(); - setNavigateSuspended(false); + 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); - if(mMediaSource->isPluginExited()) - { - resetPreviousMediaState(); - destroyMediaSource(); - return; - } + mMediaSource->idle(); - if(!mMediaSource->textureValid()) - { - return; - } + setNavigateSuspended(false); - if(mSuspendUpdates || !mVisible) - { - return; - } + if(mMediaSource == NULL) + { + return; + } - ref(); + if(mMediaSource->isPluginExited()) + { + resetPreviousMediaState(); + destroyMediaSource(); + return; + } - if (preUpdateMediaTexture()) + if(!mMediaSource->textureValid()) { - // 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(); - } + return; } - unref(); -} + if(mSuspendUpdates || !mVisible) + { + return; + } -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::preUpdateMediaTexture() -{ - return true; -} -////////////////////////////////////////////////////////////////////////////////////////// -bool LLViewerMediaImpl::postUpdateMediaTexture() -{ - return true; + // Push update to worker thread + auto main_queue = LLMediaTextureUpdateThread::sEnabled ? mMainQueue.lock() : nullptr; + ref(); // protect texture from deletion while active on bg queue + if (main_queue) + { + // replace GL name + //llassert(!mTextureId.isNull()); + //LLImageGL* base_image = LLViewerTextureManager::getMediaTexture(mTextureId)->getGLTexture(); + //GLuint retired_name = base_image->allocNew(); + main_queue->postTo( + mTexUpdateQueue, // Worker thread queue + [this]() // work done on update worker thread + { + doMediaTexUpdate(); + }, + [this]() // callback to main thread + { + endMediaTexUpdate(); + unref(); + }); + } + else + { + doMediaTexUpdate(); // otherwise, update on main thread + unref(); + } } ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::doMediaTexUpdate() { - LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); - if (placeholder_image) + LLViewerMediaTexture* media_tex = updateMediaImage(); + + if (media_tex && mMediaSource) { + llassert(mMediaSource); + LLRect dirty_rect; + S32 media_width = mMediaSource->getTextureWidth(); + S32 media_height = mMediaSource->getTextureHeight(); + S32 media_depth = mMediaSource->getTextureDepth(); // 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); + media_tex->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; + S32 width = llmin(dirty_rect.mRight, media_width) - x_pos; + S32 height = llmin(dirty_rect.mTop, media_height) - y_pos; if (width > 0 && height > 0) { - U8* data = NULL; - { - LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA); - data = mMediaSource->getBitsData(); - } + S32 data_width = mMediaSource->getBitsWidth(); + S32 data_height = mMediaSource->getBitsHeight(); + 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()); + data += (x_pos * media_depth * data_width); + data += (y_pos * media_depth); { LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE); - placeholder_image->setSubImage( + media_tex->setSubImage( data, - mMediaSource->getBitsWidth(), - mMediaSource->getBitsHeight(), + data_width, + data_height, x_pos, y_pos, width, @@ -2997,75 +2989,87 @@ void LLViewerMediaImpl::doMediaTexUpdate() } } +////////////////////////////////////////////////////////////////////////////////////////// +// runs on main thread, but only called when bg thread updates are active +void LLViewerMediaImpl::endMediaTexUpdate() +{ + LLViewerMediaTexture* base_image = LLViewerTextureManager::findMediaTexture(mTextureId); + llassert(base_image); + + LLImageGL* image = base_image->getGLTexture(); + image->swapTexName(); // retire old GL name +} + ////////////////////////////////////////////////////////////////////////////////////////// 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; - } + if (!mMediaSource) + { + return nullptr; // not ready for updating + } - 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 + llassert(!mTextureId.isNull()); + LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId ); + + // if on bg thread, create new GL tex image resource to avoid resource contention + if (!on_main_thread()) + { + LLImageGL* image = media_tex->getGLTexture(); + image->allocNewTexName(); + } + + 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 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]; - {LL_PROFILE_ZONE_NAMED("djh clear raw"); 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 - {LL_PROFILE_ZONE_NAMED("djh setformat raw"); - placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + media_tex->setExplicitFormat(mMediaSource->getTextureFormatInternal(), mMediaSource->getTextureFormatPrimary(), mMediaSource->getTextureFormatType(), mMediaSource->getTextureFormatSwapBytes()); - } - { - LL_PROFILE_ZONE_NAMED("djh create ph"); - int discard_level = 0; - placeholder_image->createGLTexture(discard_level, raw); - } - // MEDIAOPT: set this dynamically on play/stop - // FIXME -// placeholder_image->mIsMediaTexture = true; - mNeedsNewTexture = false; + int discard_level = 0; + media_tex->createGLTexture(discard_level, raw); - // 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(); - } + // MEDIAOPT: set this dynamically on play/stop + // FIXME +// media_tex->mIsMediaTexture = true; + mNeedsNewTexture = false; - return placeholder_image; + // 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; } @@ -4017,6 +4021,7 @@ void LLMediaTextureUpdateThread::run() mWindow->makeContextCurrent(mContext); gGL.init(); ThreadPool::run(); + LLMediaTextureUpdateThread::sEnabled = false; gGL.shutdown(); mWindow->destroySharedContext(mContext); } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index c2e6564166..03a14421ff 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -269,9 +269,8 @@ public: void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y); void update(); - bool preUpdateMediaTexture(); void doMediaTexUpdate(); - bool postUpdateMediaTexture(); + void endMediaTexUpdate(); void updateImagesMediaStreams(); LLUUID getMediaTextureID() const; @@ -495,13 +494,13 @@ private: bool mCanceling; private: - LLViewerMediaTexture *updatePlaceholderImage(); + LLViewerMediaTexture *updateMediaImage(); LL::WorkQueue::weak_t mMainQueue; LL::WorkQueue::weak_t mTexUpdateQueue; }; -// Define a worker thread pool for media updates ( LLImageGLThread) +// Define a worker thread pool for media updates (ref LLImageGLThread) class LLMediaTextureUpdateThread : public LLSimpleton, LL::ThreadPool { public: diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 5fed46f437..d652b76794 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1643,6 +1643,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture() #endif mNeedsCreateTexture = TRUE; auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr; + ref(); // protect texture from deletion while active on bg queue if (mainq) { mainq->postTo( -- cgit v1.3 From d28a271fa819c076e2cedb87d9f305468e436b25 Mon Sep 17 00:00:00 2001 From: Dave Houlton Date: Fri, 28 Jan 2022 09:43:21 -0700 Subject: SL-16418 add some big-endian future-proofing --- indra/llimage/llimage.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index fb02a131fd..ba7ee0b465 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -951,7 +951,11 @@ void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) U16 *dst = (U16 *)getData(); S32 count = getWidth() * getHeight(); llassert(count == getDataSize() / 2); +#ifdef LL_LITTLE_ENDIAN U16 val = (U16)(r | g << 8); +#else + U16 val = (U16)(r << 8 | g); +#endif std::fill_n(dst, count, val); break; } @@ -973,7 +977,11 @@ void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) U32 *dst = (U32 *)getData(); S32 count = getWidth() * getHeight(); llassert(count == getDataSize() / 4); +#ifdef LL_LITTLE_ENDIAN U32 val = (U32)(r | g << 8 | b << 16 | a << 24); +#else + U32 val = (U32)(r << 24 | g << 16 | b << 8 | a); +#endif std::fill_n(dst, count, val); break; } -- cgit v1.3 From fdc4a81b578f26ce573d6b60760c8235312a6372 Mon Sep 17 00:00:00 2001 From: Dave Houlton Date: Tue, 1 Feb 2022 15:49:32 -0700 Subject: Revert "Merged in euclid-16418 (pull request #846)" This reverts commit 40fe5277e1390c975d9a3184ff8fc46d69dfb450, reversing changes made to af830e5fc5840194be95140f644a27011b9b7e06. --- indra/llimage/llimage.cpp | 96 ++++----- indra/llrender/llimagegl.cpp | 66 +----- indra/llrender/llimagegl.h | 10 +- indra/newview/llviewermedia.cpp | 427 ++++++++++++++------------------------ indra/newview/llviewermedia.h | 37 +--- indra/newview/llviewertexture.cpp | 2 +- indra/newview/llviewerwindow.cpp | 6 +- 7 files changed, 214 insertions(+), 430 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index ba7ee0b465..15b07e5318 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -925,73 +925,47 @@ bool LLImageRaw::setSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height, void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) { - LL_PROFILE_ZONE_SCOPED; - S8 components = getComponents(); - llassert( components > 0 && components <= 4 ); - - // This is fairly bogus, but it'll do for now. - if (isBufferInvalid()) - { - LL_WARNS() << "Invalid image buffer" << LL_ENDL; - return; - } + llassert( getComponents() <= 4 ); + // This is fairly bogus, but it'll do for now. + if (isBufferInvalid()) + { + LL_WARNS() << "Invalid image buffer" << LL_ENDL; + return; + } - switch (components) - { - case 1: - { - U8 *dst = getData(); - S32 count = getWidth() * getHeight(); - llassert(count == getDataSize()); - std::fill_n(dst, count, r); - break; - } - case 2: - { - U16 *dst = (U16 *)getData(); - S32 count = getWidth() * getHeight(); - llassert(count == getDataSize() / 2); -#ifdef LL_LITTLE_ENDIAN - U16 val = (U16)(r | g << 8); -#else - U16 val = (U16)(r << 8 | g); -#endif - std::fill_n(dst, count, val); - break; - } - case 3: - { - U8 *dst = getData(); - S32 count = getWidth() * getHeight(); - llassert(count == getDataSize() / 3); - for (S32 i = 0; i < count; i++) - { - *dst++ = r; - *dst++ = g; - *dst++ = b; - } - break; - } - case 4: - { - U32 *dst = (U32 *)getData(); - S32 count = getWidth() * getHeight(); - llassert(count == getDataSize() / 4); -#ifdef LL_LITTLE_ENDIAN - U32 val = (U32)(r | g << 8 | b << 16 | a << 24); -#else - U32 val = (U32)(r << 24 | g << 16 | b << 8 | a); -#endif - std::fill_n(dst, count, val); - break; - } - } + U8 *pos = getData(); + U32 x, y; + for (x = 0; x < getWidth(); x++) + { + for (y = 0; y < getHeight(); y++) + { + *pos = r; + pos++; + if (getComponents() == 1) + { + continue; + } + *pos = g; + pos++; + if (getComponents() == 2) + { + continue; + } + *pos = b; + pos++; + if (getComponents() == 3) + { + continue; + } + *pos = a; + pos++; + } + } } // Reverses the order of the rows in the image void LLImageRaw::verticalFlip() { - LL_PROFILE_ZONE_SCOPED; S32 row_bytes = getWidth() * getComponents(); llassert(row_bytes > 0); std::vector line_buffer(row_bytes); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 4b4f071171..1e9b9f642e 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -1215,8 +1215,9 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (pixformat == GL_ALPHA && pixtype == GL_UNSIGNED_BYTE) { //GL_ALPHA is deprecated, convert to RGBA use_scratch = true; + scratch = new U32[width * height]; + U32 pixel_count = (U32)(width * height); - scratch = new U32[pixel_count]; for (U32 i = 0; i < pixel_count; i++) { U8* pix = (U8*)&scratch[i]; @@ -1231,8 +1232,9 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (pixformat == GL_LUMINANCE_ALPHA && pixtype == GL_UNSIGNED_BYTE) { //GL_LUMINANCE_ALPHA is deprecated, convert to RGBA use_scratch = true; + scratch = new U32[width * height]; + U32 pixel_count = (U32)(width * height); - scratch = new U32[pixel_count]; for (U32 i = 0; i < pixel_count; i++) { U8 lum = ((U8*)pixels)[i * 2 + 0]; @@ -1250,8 +1252,9 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt if (pixformat == GL_LUMINANCE && pixtype == GL_UNSIGNED_BYTE) { //GL_LUMINANCE_ALPHA is deprecated, convert to RGB use_scratch = true; + scratch = new U32[width * height]; + U32 pixel_count = (U32)(width * height); - scratch = new U32[pixel_count]; for (U32 i = 0; i < pixel_count; i++) { U8 lum = ((U8*)pixels)[i]; @@ -1311,7 +1314,10 @@ void LLImageGL::setManualImage(U32 target, S32 miplevel, S32 intformat, S32 widt } stop_glerror(); - if (scratch) delete[] scratch; + if (use_scratch) + { + delete[] scratch; + } } //create an empty GL texture: just create a texture name @@ -1465,49 +1471,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S return createGLTexture(discard_level, rawdata, FALSE, usename); } -// Create a new GL name and allocate tex storage (unitialized) for it -// Used to break resource contention stall in background media tex updates -void LLImageGL::allocNewTexName() -{ - LL_PROFILE_ZONE_SCOPED; - if (on_main_thread()) return; // Should only be called on bg update thread - if (!mGLTextureCreated) return; - if (0 != mNewTexName) return; // only 1 rename in flight at a time - - generateTextures(1, &mNewTexName); // create new GL name - - mHasMipMaps = false; // Media textures aren't mipped - mMipLevels = 0; - // Set state to match current - gGL.getTexUnit(0)->bind(this, false, false, mNewTexName); - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel); - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_WIDTH, mWidth); - glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_HEIGHT, mHeight); - gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps); - gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode); - gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption); - - setManualImage(mTarget, 0, mFormatInternal, mWidth, mHeight, mFormatPrimary, mFormatType, - (GLvoid *) nullptr, mAllowCompression); - - gGL.getTexUnit(0)->unbind(mBindTarget); - - mLastBindTime = sLastFrameTime; -} - -// Delete no-longer-needed GL tex name (on main thread) -void LLImageGL::swapTexName() -{ - if (mNewTexName) - { - deleteTextures(1, &mTexName); - mTexName = mNewTexName; - mNewTexName = 0; - } -} - -BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips /* = FALSE */, S32 usename /* = 0 */) +BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename) { LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE; checkActiveThread(); @@ -1751,14 +1715,6 @@ void LLImageGL::destroyGLTexture() 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 f311170823..d6f4b13a51 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -109,17 +109,15 @@ public: static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels, bool allow_compression = true); 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 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); - void setImage(const LLImageRaw* imageraw); + 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 setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); - - void allocNewTexName(); - void swapTexName(); - + // 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/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 6c04321539..63f57e81cc 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -39,7 +39,6 @@ #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" @@ -79,9 +78,6 @@ #include // for SkinFolder listener #include -// Statics -bool LLMediaTextureUpdateThread::sEnabled = false; - class LLMediaFilePicker : public LLFilePickerThread // deletes itself when done { public: @@ -639,7 +635,6 @@ 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"); @@ -1595,8 +1590,6 @@ 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. } ////////////////////////////////////////////////////////////////////////////////////////// @@ -1610,25 +1603,6 @@ LLViewerMediaImpl::~LLViewerMediaImpl() remove_media_impl(this); } -////////////////////////////////////////////////////////////////////////////////////////// -//static -void LLViewerMediaImpl::initClass(LLWindow* window, bool multi_threaded /* = false */) -{ - LL_PROFILE_ZONE_SCOPED; - if (multi_threaded) - { - LLMediaTextureUpdateThread::createInstance(window); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -//static -void LLViewerMediaImpl::cleanupClass() -{ - LL_PROFILE_ZONE_SCOPED; - LLMediaTextureUpdateThread::deleteSingleton(); -} - ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::emitEvent(LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event) { @@ -2113,7 +2087,6 @@ 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 @@ -2826,252 +2799,199 @@ 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(); - // Push update to worker thread - auto main_queue = LLMediaTextureUpdateThread::sEnabled ? mMainQueue.lock() : nullptr; - ref(); // protect texture from deletion while active on bg queue - if (main_queue) - { - // replace GL name - //llassert(!mTextureId.isNull()); - //LLImageGL* base_image = LLViewerTextureManager::getMediaTexture(mTextureId)->getGLTexture(); - //GLuint retired_name = base_image->allocNew(); - main_queue->postTo( - mTexUpdateQueue, // Worker thread queue - [this]() // work done on update worker thread - { - doMediaTexUpdate(); - }, - [this]() // callback to main thread - { - endMediaTexUpdate(); - unref(); - }); - } - else - { - doMediaTexUpdate(); // otherwise, update on main thread - unref(); - } -} + if(placeholder_image) + { + LLRect dirty_rect; -////////////////////////////////////////////////////////////////////////////////////////// -void LLViewerMediaImpl::doMediaTexUpdate() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; - LLViewerMediaTexture* media_tex = updateMediaImage(); + // 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 (media_tex && mMediaSource) - { - llassert(mMediaSource); - - LLRect dirty_rect; - S32 media_width = mMediaSource->getTextureWidth(); - S32 media_height = mMediaSource->getTextureHeight(); - S32 media_depth = mMediaSource->getTextureDepth(); + 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; - // 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(width > 0 && height > 0) + { - 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, media_width) - x_pos; - S32 height = llmin(dirty_rect.mTop, media_height) - y_pos; + U8* data = NULL; + { + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media get data"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_GET_DATA); + data = mMediaSource->getBitsData(); + } - if (width > 0 && height > 0) - { - U8* data = NULL; - S32 data_width = mMediaSource->getBitsWidth(); - S32 data_height = mMediaSource->getBitsHeight(); - 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() ); - if (data != NULL) - { - // Offset the pixels pointer to match x_pos and y_pos - data += (x_pos * media_depth * data_width); - data += (y_pos * media_depth); - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media set subimage"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE); - media_tex->setSubImage( - data, - data_width, - data_height, - x_pos, - y_pos, - width, - height); - } - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_MEDIA("media set subimage"); //LL_RECORD_BLOCK_TIME(FTM_MEDIA_SET_SUBIMAGE); + placeholder_image->setSubImage( + data, + mMediaSource->getBitsWidth(), + mMediaSource->getBitsHeight(), + x_pos, + y_pos, + width, + height); + } + } - } + } - mMediaSource->resetDirty(); - } - } + mMediaSource->resetDirty(); + } + } } -////////////////////////////////////////////////////////////////////////////////////////// -// runs on main thread, but only called when bg thread updates are active -void LLViewerMediaImpl::endMediaTexUpdate() -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; - LLViewerMediaTexture* base_image = LLViewerTextureManager::findMediaTexture(mTextureId); - llassert(base_image); - - LLImageGL* image = base_image->getGLTexture(); - image->swapTexName(); // retire old GL name -} ////////////////////////////////////////////////////////////////////////////////////////// void LLViewerMediaImpl::updateImagesMediaStreams() { } + ////////////////////////////////////////////////////////////////////////////////////////// -LLViewerMediaTexture* LLViewerMediaImpl::updateMediaImage() +LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_MEDIA; - if (!mMediaSource) - { - return nullptr; // not ready for updating - } + if(mTextureId.isNull()) + { + // The code that created this instance will read from the plugin's bits. + return NULL; + } - llassert(!mTextureId.isNull()); - LLViewerMediaTexture* media_tex = LLViewerTextureManager::getMediaTexture( mTextureId ); - - // if on bg thread, create new GL tex image resource to avoid resource contention - if (!on_main_thread()) - { - LLImageGL* image = media_tex->getGLTexture(); - image->allocNewTexName(); - } + LLViewerMediaTexture* placeholder_image = 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 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; + 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 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(); + } + + return placeholder_image; } @@ -4000,30 +3920,3 @@ 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(); - LLMediaTextureUpdateThread::sEnabled = false; - gGL.shutdown(); - mWindow->destroySharedContext(mContext); -} diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 03a14421ff..71cec5125d 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -197,10 +197,7 @@ 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); @@ -269,8 +266,6 @@ public: void scaleTextureCoords(const LLVector2& texture_coords, S32 *x, S32 *y); void update(); - void doMediaTexUpdate(); - void endMediaTexUpdate(); void updateImagesMediaStreams(); LLUUID getMediaTextureID() const; @@ -494,35 +489,7 @@ private: bool mCanceling; private: - LLViewerMediaTexture *updateMediaImage(); - LL::WorkQueue::weak_t mMainQueue; - LL::WorkQueue::weak_t mTexUpdateQueue; - -}; - -// Define a worker thread pool for media updates (ref LLImageGLThread) -class LLMediaTextureUpdateThread : public LLSimpleton, LL::ThreadPool -{ -public: - // follows gSavedSettings "RenderGLMultiThreaded" - static bool sEnabled; - - LLMediaTextureUpdateThread(LLWindow* window); - - // post a function to be executed on the LLMediaTextureUpdateThread background thread - template - bool post(CALLABLE&& func) - { - return getQueue().postIfOpen(std::forward(func)); - } - - void run() override; - -private: - LLWindow* mWindow; - void* mContext = nullptr; - LLAtomicBool mFinished; + LLViewerMediaTexture *updatePlaceholderImage(); }; - #endif // LLVIEWERMEDIA_H diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index ccf4c5bbec..5fed46f437 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -1629,6 +1629,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture() mNeedsCreateTexture = TRUE; if (preCreateTexture()) { + ref(); #if LL_IMAGEGL_THREAD_CHECK //grab a copy of the raw image data to make sure it isn't modified pending texture creation U8* data = mRawImage->getData(); @@ -1642,7 +1643,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture() #endif mNeedsCreateTexture = TRUE; auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr; - ref(); // protect texture from deletion while active on bg queue if (mainq) { mainq->postTo( diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ba93f4f5f9..b9a5e90df0 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -2027,9 +2027,6 @@ 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; @@ -2419,8 +2416,7 @@ 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; -- cgit v1.3 From f47730b92c309092d0a5a95e2d49d7ad53230a97 Mon Sep 17 00:00:00 2001 From: Dave Parks Date: Mon, 14 Feb 2022 18:07:24 +0000 Subject: SL-16418 Media texture update stall fix. Make media texture updates use LLImageGL thread to update, fix AMD sync issue on ImageGL thread and install debug callbacks on LLImageGL thread when debug gl enabled. --- indra/llimage/llimage.cpp | 6 + indra/llimage/llimage.h | 6 + indra/llmath/llvolume.cpp | 2 +- indra/llrender/llgl.cpp | 11 -- indra/llrender/llgltexture.cpp | 12 +- indra/llrender/llgltexture.h | 14 +- indra/llrender/llimagegl.cpp | 139 +++++++++----- indra/llrender/llimagegl.h | 14 +- indra/llrender/llrender.cpp | 20 ++ indra/newview/llviewermedia.cpp | 393 +++++++++++++++++++++++---------------- indra/newview/llviewermedia.h | 13 +- indra/newview/llviewerwindow.cpp | 6 +- 12 files changed, 398 insertions(+), 238 deletions(-) (limited to 'indra/llimage/llimage.cpp') 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 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 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 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 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 sMimeTypesFailed; - + LLPointer 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; -- cgit v1.3 From 5b67aa2c58a2c144d9013d4534520741e48596f5 Mon Sep 17 00:00:00 2001 From: Ptolemy Date: Mon, 7 Mar 2022 19:11:59 -0800 Subject: SL-16933: Fix texture stat Raw Total always increasing --- indra/llimage/llimage.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'indra/llimage/llimage.cpp') diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 5fa19ce9c6..0fa027c9c3 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -884,8 +884,6 @@ void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) LLImageBase::setSize(width, height, components) ; LLImageBase::setDataAndSize(data, width * height * components) ; - - sGlobalRawMemory += getDataSize(); } bool LLImageRaw::resize(U16 width, U16 height, S8 components) -- cgit v1.3