summaryrefslogtreecommitdiff
path: root/indra/llrender/llimagegl.cpp
diff options
context:
space:
mode:
authorDave Parks <davep@lindenlab.com>2022-02-17 22:52:23 +0000
committerDave Parks <davep@lindenlab.com>2022-02-17 22:52:23 +0000
commit0d6aa3c0fe184ae00899304cb3f71315f5c73314 (patch)
tree88196dfd88c70728132cd05b5b7d5d4e630dd50a /indra/llrender/llimagegl.cpp
parent892f7d98d5da2c329472a7075a88e010277b86b0 (diff)
SL-16815 Remove frame stalls from occlusion queries, bumpmap updates, and querying for available video memory.
Diffstat (limited to 'indra/llrender/llimagegl.cpp')
-rw-r--r--indra/llrender/llimagegl.cpp119
1 files changed, 87 insertions, 32 deletions
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 694c4a7b06..110074bdc0 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -40,6 +40,7 @@
#include "llglslshader.h"
#include "llrender.h"
#include "llwindow.h"
+#include "llframetimer.h"
#if !LL_IMAGEGL_THREAD_CHECK
#define checkActiveThread()
@@ -1075,14 +1076,15 @@ 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 /* = FALSE */, bool use_new_name /* = false */)
+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 */, LLGLuint use_name)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
if (!width || !height)
{
return TRUE;
}
- if (0 == (use_new_name ? mNewTexName : mTexName))
+ LLGLuint tex_name = use_name != 0 ? use_name : mTexName;
+ if (0 == tex_name)
{
// *TODO: Re-enable warning? Ran into thread locking issues? DK 2011-02-18
//LL_WARNS() << "Setting subimage on image without GL texture" << LL_ENDL;
@@ -1098,7 +1100,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, use_new_name ? mNewTexName : mTexName);
+ setImage(datap, FALSE, tex_name);
}
else
{
@@ -1150,7 +1152,7 @@ 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, use_new_name ? mNewTexName : mTexName);
+ BOOL res = gGL.getTexUnit(0)->bindManual(mBindTarget, tex_name);
if (!res) LL_ERRS() << "LLImageGL::setSubImage(): bindTexture failed" << LL_ENDL;
stop_glerror();
@@ -1171,10 +1173,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 /* = FALSE */, bool use_new_name /* = false */)
+BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update /* = FALSE */, LLGLuint use_name)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
- return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update, use_new_name);
+ return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update, use_name);
}
// Copy sub image from frame buffer
@@ -1361,7 +1363,7 @@ BOOL LLImageGL::createGLTexture()
return TRUE ;
}
-BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category, bool defer_copy)
+BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
checkActiveThread();
@@ -1474,15 +1476,17 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
setCategory(category);
const U8* rawdata = imageraw->getData();
- return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy);
+ return createGLTexture(discard_level, rawdata, FALSE, usename, defer_copy, tex_name);
}
-BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename, bool defer_copy)
+BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename, bool defer_copy, LLGLuint* tex_name)
// Call with void data, vmem is allocated but unitialized
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
checkActiveThread();
+ bool main_thread = on_main_thread();
+
if (defer_copy)
{
data_in = nullptr;
@@ -1501,29 +1505,40 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
}
discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
- if (!defer_copy // <--- hacky way to force creation of mNewTexName from media texture update
+ if (main_thread // <--- always force creation of mNewTexName when not on main thread
&& mTexName != 0 && discard_level == mCurrentDiscardLevel)
{
+ LL_PROFILE_ZONE_NAMED("cglt - early setImage");
// This will only be true if the size has not changed
+ if (tex_name != nullptr)
+ {
+ *tex_name = mTexName;
+ }
return setImage(data_in, data_hasmips);
}
GLuint old_texname = mTexName;
-
+ GLuint new_texname = 0;
if (usename != 0)
{
- mNewTexName = usename;
+ llassert(main_thread);
+ new_texname = usename;
}
else
{
- LLImageGL::generateTextures(1, &mNewTexName);
+ LLImageGL::generateTextures(1, &new_texname);
{
- gGL.getTexUnit(0)->bind(this, false, false, mNewTexName);
+ gGL.getTexUnit(0)->bind(this, false, false, new_texname);
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel - discard_level);
}
}
+ if (tex_name != nullptr)
+ {
+ *tex_name = new_texname;
+ }
+
if (mUseMipMaps)
{
mAutoGenMips = gGLManager.mHasMipMapGeneration;
@@ -1531,9 +1546,12 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
mCurrentDiscardLevel = discard_level;
- if (!setImage(data_in, data_hasmips, mNewTexName))
{
- return FALSE;
+ LL_PROFILE_ZONE_NAMED("cglt - late setImage");
+ if (!setImage(data_in, data_hasmips, new_texname))
+ {
+ return FALSE;
+ }
}
// Set texture options to our defaults.
@@ -1550,11 +1568,11 @@ 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 (!main_thread)
{
if (!defer_copy)
{
- syncToMainThread();
+ syncToMainThread(new_texname);
}
}
else
@@ -1564,8 +1582,7 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
{
LLImageGL::deleteTextures(1, &old_texname);
}
- mTexName = mNewTexName;
- mNewTexName = 0;
+ mTexName = new_texname;
}
mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel);
@@ -1579,13 +1596,36 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
return TRUE;
}
-void LLImageGL::syncToMainThread()
+void update_free_vram()
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ if (gGLManager.mHasATIMemInfo)
+ {
+ S32 meminfo[4];
+ glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
+ LLImageGLThread::sFreeVRAMMegabytes = meminfo[0];
+
+ }
+ else if (gGLManager.mHasNVXMemInfo)
+ {
+ S32 free_memory;
+ glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
+ LLImageGLThread::sFreeVRAMMegabytes = free_memory / 1024;
+ }
+}
+
+void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
{
+ LL_PROFILE_ZONE_SCOPED;
{
LL_PROFILE_ZONE_NAMED("cglt - sync");
if (gGLManager.mHasSync)
{
// post a sync to the main thread (will execute before tex name swap lambda below)
+ // glFlush calls here are partly superstitious and partly backed by observation
+ // on AMD hardware
+ glFlush();
auto sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
LL::WorkQueue::postMaybe(
@@ -1615,17 +1655,27 @@ void LLImageGL::syncToMainThread()
[=]()
{
LL_PROFILE_ZONE_NAMED("cglt - delete callback");
- if (mNewTexName != 0)
+ if (new_tex_name != 0)
{
if (mTexName != 0)
{
LLImageGL::deleteTextures(1, &mTexName);
}
- mTexName = mNewTexName;
- mNewTexName = 0;
+ mTexName = new_tex_name;
unref();
}
});
+
+
+ //update free vram periodically
+ static LLFrameTimer timer;
+
+ if (timer.getElapsedTimeF32() > 1.f) //call this once per second.
+ {
+ update_free_vram();
+ timer.reset();
+ }
+
}
BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
@@ -1756,14 +1806,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
@@ -2306,6 +2348,8 @@ void LLImageGL::checkActiveThread()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips);
*/
+std::atomic<S32> LLImageGLThread::sFreeVRAMMegabytes;
+
LLImageGLThread::LLImageGLThread(LLWindow* window)
// We want exactly one thread, but a very large capacity: we never want
// anyone, especially inner-loop render code, to have to block on post()
@@ -2332,3 +2376,14 @@ void LLImageGLThread::run()
gGL.shutdown();
mWindow->destroySharedContext(mContext);
}
+
+S32 LLImageGLThread::getFreeVRAMMegabytes()
+{
+ if (!sEnabled)
+ {
+ update_free_vram();
+ }
+
+ return sFreeVRAMMegabytes;
+}
+