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