summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2021-10-21 21:19:48 +0000
committerDave Parks <davep@lindenlab.com>2021-10-21 21:19:48 +0000
commite774bffb28a71730792931aeb1ed6a46d3cfe67b (patch)
treed82248f9fc0678fb5e6e3c39f5d0011707b0a86c /indra
parent6ecf8f2c01dc90c26a8a0ccbd11abc2241debfa9 (diff)
SL-16202 Fix for textures appearing black or flashing white due to optimization bugs.
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/workqueue.cpp2
-rw-r--r--indra/llrender/llimagegl.cpp241
-rw-r--r--indra/llrender/llimagegl.h16
-rw-r--r--indra/llrender/llrender.cpp14
-rw-r--r--indra/llrender/llrender.h2
-rw-r--r--indra/newview/llglsandbox.cpp3
-rw-r--r--indra/newview/llviewertexture.cpp13
7 files changed, 141 insertions, 150 deletions
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index ffc9a97dc0..b32357e832 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -54,6 +54,7 @@ void LL::WorkQueue::runUntilClose()
bool LL::WorkQueue::runPending()
{
+ LL_PROFILE_ZONE_SCOPED;
for (Work work; mQueue.tryPop(work); )
{
callWork(work);
@@ -110,6 +111,7 @@ void LL::WorkQueue::callWork(const Queue::DataTuple& work)
void LL::WorkQueue::callWork(const Work& work)
{
+ LL_PROFILE_ZONE_SCOPED;
try
{
work();
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index aff29bd857..b5e1910242 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -683,7 +683,7 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
}
static LLTrace::BlockTimerStatHandle FTM_SET_IMAGE("setImage");
-BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
+BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips, S32 usename)
{
LL_RECORD_BLOCK_TIME(FTM_SET_IMAGE);
bool is_compressed = false;
@@ -702,12 +702,11 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
break;
}
-
-
if (mUseMipMaps)
{
//set has mip maps to true before binding image so tex parameters get set properly
- gGL.getTexUnit(0)->unbind(mBindTarget);
+ gGL.getTexUnit(0)->unbind(mBindTarget);
+
mHasMipMaps = true;
mTexOptionsDirty = true;
setFilteringOption(LLTexUnit::TFO_ANISOTROPIC);
@@ -717,7 +716,8 @@ BOOL LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
mHasMipMaps = false;
}
- llverify(gGL.getTexUnit(0)->bind(this));
+ gGL.getTexUnit(0)->bind(this, false, false, usename);
+
if (mUseMipMaps)
{
@@ -1211,7 +1211,7 @@ void LLImageGL::generateTextures(S32 numTextures, U32 *textures)
}
// static
-void LLImageGL::deleteTextures(S32 numTextures, U32 *textures)
+void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures)
{
if (gGLManager.mInited)
{
@@ -1381,13 +1381,13 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
return FALSE;
}
- mGLTextureCreated = false ;
llassert(gGLManager.mInited);
stop_glerror();
if (!imageraw || imageraw->isBufferInvalid())
{
LL_WARNS() << "Trying to create a texture from invalid image data" << LL_ENDL;
+ mGLTextureCreated = false;
return FALSE;
}
@@ -1407,6 +1407,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
if (!setSize(w, h, imageraw->getComponents(), discard_level))
{
LL_WARNS() << "Trying to create a texture with incorrect dimensions!" << LL_ENDL;
+ mGLTextureCreated = false;
return FALSE;
}
@@ -1475,6 +1476,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
destroyGLTexture();
mCurrentDiscardLevel = discard_level;
mLastBindTime = sLastFrameTime;
+ mGLTextureCreated = false;
return TRUE ;
}
@@ -1486,104 +1488,123 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
static LLTrace::BlockTimerStatHandle FTM_CREATE_GL_TEXTURE3("createGLTexture3(data)");
BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
{
- LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE3);
- llassert(data_in);
- stop_glerror();
-
- if (discard_level < 0)
- {
- llassert(mCurrentDiscardLevel >= 0);
- discard_level = mCurrentDiscardLevel;
- }
- discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
+ LL_RECORD_BLOCK_TIME(FTM_CREATE_GL_TEXTURE3);
+ llassert(data_in);
+ stop_glerror();
- if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
- {
- // This will only be true if the size has not changed
- return setImage(data_in, data_hasmips);
- }
-
- U32 old_name = mTexName;
-// S32 old_discard = mCurrentDiscardLevel;
-
- if (usename != 0)
- {
- mTexName = usename;
- }
- else
- {
- LLImageGL::generateTextures(1, &mTexName);
- stop_glerror();
- {
- llverify(gGL.getTexUnit(0)->bind(this));
- stop_glerror();
- glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
- stop_glerror();
- glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level);
- stop_glerror();
- }
- }
- if (!mTexName)
- {
- if (old_name)
- {
- sGlobalTextureMemory -= mTextureMemory;
- LLImageGL::deleteTextures(1, &old_name);
- disclaimMem(mTextureMemory);
- stop_glerror();
- }
+ if (discard_level < 0)
+ {
+ llassert(mCurrentDiscardLevel >= 0);
+ discard_level = mCurrentDiscardLevel;
+ }
+ discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
- LL_WARNS() << "LLImageGL::createGLTexture failed to make texture" << LL_ENDL;
- return FALSE;
- }
+ if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
+ {
+ // This will only be true if the size has not changed
+ return setImage(data_in, data_hasmips);
+ }
- if (mUseMipMaps)
- {
- mAutoGenMips = gGLManager.mHasMipMapGeneration;
+ GLuint old_texname = mTexName;
+
+ if (usename != 0)
+ {
+ mNewTexName = usename;
+ }
+ else
+ {
+ LLImageGL::generateTextures(1, &mNewTexName);
+ {
+ 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 - discard_level);
+ }
+ }
+
+ if (mUseMipMaps)
+ {
+ mAutoGenMips = gGLManager.mHasMipMapGeneration;
#if LL_DARWIN
- // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
- if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
- {
- mAutoGenMips = FALSE;
- }
+ // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
+ if (gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
+ {
+ mAutoGenMips = FALSE;
+ }
#endif
- }
+ }
- mCurrentDiscardLevel = discard_level;
+ mCurrentDiscardLevel = discard_level;
- if (!setImage(data_in, data_hasmips))
- {
- stop_glerror();
- return FALSE;
- }
+ if (!setImage(data_in, data_hasmips, mNewTexName))
+ {
+ return FALSE;
+ }
- // Set texture options to our defaults.
- gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps);
- gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode);
- gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
+ // Set texture options to our defaults.
+ gGL.getTexUnit(0)->setHasMipMaps(mHasMipMaps);
+ gGL.getTexUnit(0)->setTextureAddressMode(mAddressMode);
+ gGL.getTexUnit(0)->setTextureFilteringOption(mFilterOption);
- // things will break if we don't unbind after creation
- gGL.getTexUnit(0)->unbind(mBindTarget);
- stop_glerror();
+ // things will break if we don't unbind after creation
+ gGL.getTexUnit(0)->unbind(mBindTarget);
- if (old_name != 0)
- {
- sGlobalTextureMemory -= mTextureMemory;
+ if (old_texname != 0)
+ {
+ sGlobalTextureMemory -= mTextureMemory;
+ }
- LLImageGL::deleteTextures(1, &old_name);
+ //if we're on the image loading thread, be sure to delete old_texname and update mTexName on the main thread
+ if (LLImageGLThread::sInstance != nullptr &&
+ LLThread::currentID() == LLImageGLThread::sInstance->getID())
+ {
+ {
+ 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();
+ }
+ }
- stop_glerror();
- }
+ ref();
+ LLImageGLThread::sInstance->postCallback([=]()
+ {
+ LL_PROFILE_ZONE_NAMED("cglt - delete callback");
+ if (old_texname != 0)
+ {
+ LLImageGL::deleteTextures(1, &old_texname);
+ }
+ mTexName = mNewTexName;
+ mNewTexName = 0;
+ unref();
+ });
+ }
+ else
+ {
+ //not on background thread, immediately set mTexName
+ if (old_texname != 0)
+ {
+ LLImageGL::deleteTextures(1, &old_texname);
+ }
+ mTexName = mNewTexName;
+ mNewTexName = 0;
+ }
+
+ disclaimMem(mTextureMemory);
+ mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel);
+ claimMem(mTextureMemory);
+ sGlobalTextureMemory += mTextureMemory;
+ mTexelsInGLTexture = getWidth() * getHeight();
- disclaimMem(mTextureMemory);
- mTextureMemory = (S32Bytes)getMipBytes(discard_level);
- claimMem(mTextureMemory);
- sGlobalTextureMemory += mTextureMemory;
- mTexelsInGLTexture = getWidth() * getHeight() ;
+ // mark this as bound at this point, so we don't throw it out immediately
+ mLastBindTime = sLastFrameTime;
- // mark this as bound at this point, so we don't throw it out immediately
- mLastBindTime = sLastFrameTime;
- return TRUE;
+ return TRUE;
}
BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
@@ -2274,17 +2295,7 @@ bool LLImageGLThread::post(const std::function<void()>& func)
{
try
{
- if (mFunctionQueue.size() < mFunctionQueue.capacity())
- {
- //NOTE: tryPushFront will return immediately if the lock is held
- // desired behavior here is to push and return true unless the
- // queue is full or closed
- mFunctionQueue.pushFront(func);
- }
- else
- {
- return false;
- }
+ mFunctionQueue.post(func);
}
catch (LLThreadSafeQueueInterrupt e)
{
@@ -2300,7 +2311,7 @@ bool LLImageGLThread::postCallback(const std::function<void()>& callback)
{
try
{
- mCallbackQueue.pushFront(callback);
+ mCallbackQueue.post(callback);
}
catch (LLThreadSafeQueueInterrupt e)
{
@@ -2315,34 +2326,14 @@ void LLImageGLThread::executeCallbacks()
{
LL_PROFILE_ZONE_SCOPED;
//executed from main thread
- std::function<void()> callback;
- while (mCallbackQueue.tryPopBack(callback))
- {
- LL_PROFILE_ZONE_NAMED("iglt - callback");
- callback();
- }
+ mCallbackQueue.runPending();
}
void LLImageGLThread::run()
{
mWindow->makeContextCurrent(mContext);
gGL.init();
- try
- {
- while (true)
- {
- LL_PROFILE_ZONE_SCOPED;
- std::function<void()> curFunc = mFunctionQueue.popBack();
- {
- LL_PROFILE_ZONE_NAMED("iglt - function")
- curFunc();
- }
- }
- }
- catch (LLThreadSafeQueueInterrupt e)
- {
- //queue is closed, fall out of run loop
- }
+ mFunctionQueue.runUntilClose();
gGL.shutdown();
mWindow->destroySharedContext(mContext);
}
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 8e9b483c2d..da626a1093 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -37,6 +37,8 @@
#include "llunits.h"
#include "llthreadsafequeue.h"
#include "llrender.h"
+#include "workqueue.h"
+
class LLTextureAtlas ;
class LLWindow;
@@ -50,7 +52,7 @@ class LLImageGL : public LLRefCount, public LLTrace::MemTrackable<LLImageGL>
public:
// These 2 functions replace glGenTextures() and glDeleteTextures()
static void generateTextures(S32 numTextures, U32 *textures);
- static void deleteTextures(S32 numTextures, U32 *textures);
+ static void deleteTextures(S32 numTextures, const U32 *textures);
static void deleteDeadTextures();
// Size calculation
@@ -110,7 +112,7 @@ public:
S32 category = sMaxCategories-1);
BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
void setImage(const LLImageRaw* imageraw);
- BOOL setImage(const U8* data_in, BOOL data_hasmips = FALSE);
+ 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);
@@ -210,8 +212,9 @@ private:
bool mGLTextureCreated ;
LLGLuint mTexName;
+ LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread
U16 mWidth;
- U16 mHeight;
+ U16 mHeight;
S8 mCurrentDiscardLevel;
S8 mDiscardLevelInAtlas;
@@ -319,8 +322,11 @@ public:
void run() override;
- LLThreadSafeQueue<std::function<void()>> mFunctionQueue;
- LLThreadSafeQueue<std::function<void()>> mCallbackQueue;
+ // Work Queue for background thread
+ LL::WorkQueue mFunctionQueue;
+
+ // Work Queue for main thread (run from updateClass)
+ LL::WorkQueue mCallbackQueue;
LLWindow* mWindow;
void* mContext;
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 669a09d3ce..aad04beea2 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -236,6 +236,10 @@ void LLTexUnit::bindFast(LLTexture* texture)
glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
gGL.mCurrTextureUnitIndex = mIndex;
mCurrTexture = gl_tex->getTexName();
+ if (!mCurrTexture)
+ {
+ mCurrTexture = LLImageGL::sDefaultGLTexture->getTexName();
+ }
glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
mHasMipMaps = gl_tex->mHasMipMaps;
}
@@ -306,18 +310,20 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
return true;
}
-bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
+bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32 usename)
{
stop_glerror();
if (mIndex < 0) return false;
+ U32 texname = usename ? usename : texture->getTexName();
+
if(!texture)
{
LL_DEBUGS() << "NULL LLTexUnit::bind texture" << LL_ENDL;
return false;
}
- if(!texture->getTexName())
+ if(!texname)
{
if(LLImageGL::sDefaultGLTexture && LLImageGL::sDefaultGLTexture->getTexName())
{
@@ -327,7 +333,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
return false ;
}
- if ((mCurrTexture != texture->getTexName()) || forceBind)
+ if ((mCurrTexture != texname) || forceBind)
{
gGL.flush();
stop_glerror();
@@ -335,7 +341,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
stop_glerror();
enable(texture->getTarget());
stop_glerror();
- mCurrTexture = texture->getTexName();
+ mCurrTexture = texname;
glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
stop_glerror();
texture->updateBindStats(texture->mTextureMemory);
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 6e2647a16b..7f19a45410 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -158,7 +158,7 @@ public:
// Binds the LLImageGL to this texture unit
// (automatically enables the unit for the LLImageGL's texture type)
- bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false);
+ bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false, S32 usename = 0);
bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false);
// bind implementation for inner loops
diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp
index 0f288e05ca..91f314c115 100644
--- a/indra/newview/llglsandbox.cpp
+++ b/indra/newview/llglsandbox.cpp
@@ -1090,7 +1090,7 @@ F32 gpu_benchmark()
delete [] pixels;
//make a dummy triangle to draw with
- LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, GL_STREAM_DRAW_ARB);
+ LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, GL_STREAM_DRAW_ARB);
if (!buff->allocateBuffer(3, 0, true))
{
@@ -1100,7 +1100,6 @@ F32 gpu_benchmark()
}
LLStrider<LLVector3> v;
- LLStrider<LLVector2> tc;
if (! buff->getVertexStrider(v))
{
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 949e71a4c9..34847d8618 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1637,19 +1637,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
{
//actually create the texture on a background thread
createTexture();
- {
- LL_PROFILE_ZONE_NAMED("iglt - sync");
- if (gGLManager.mHasSync)
- {
- auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
- glClientWaitSync(sync, 0, 0);
- glDeleteSync(sync);
- }
- else
- {
- glFinish();
- }
- }
LLImageGLThread::sInstance->postCallback([this]()
{
//finalize on main thread