summaryrefslogtreecommitdiff
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
parent892f7d98d5da2c329472a7075a88e010277b86b0 (diff)
SL-16815 Remove frame stalls from occlusion queries, bumpmap updates, and querying for available video memory.
-rw-r--r--indra/llrender/llgl.cpp90
-rw-r--r--indra/llrender/llgl.h45
-rw-r--r--indra/llrender/llgltexture.cpp14
-rw-r--r--indra/llrender/llgltexture.h7
-rw-r--r--indra/llrender/llimagegl.cpp119
-rw-r--r--indra/llrender/llimagegl.h17
-rw-r--r--indra/llwindow/llwindowwin32.cpp1
-rw-r--r--indra/newview/lldrawpoolbump.cpp203
-rw-r--r--indra/newview/lldrawpoolbump.h2
-rw-r--r--indra/newview/llviewerdisplay.cpp3
-rw-r--r--indra/newview/llviewermedia.cpp7
-rw-r--r--indra/newview/llvieweroctree.cpp93
-rw-r--r--indra/newview/llviewertexture.cpp24
-rw-r--r--indra/newview/pipeline.cpp5
14 files changed, 316 insertions, 314 deletions
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 50a5972d28..639d1fba32 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -2150,95 +2150,6 @@ LLGLUserClipPlane::~LLGLUserClipPlane()
disable();
}
-LLGLNamePool::LLGLNamePool()
-{
-}
-
-LLGLNamePool::~LLGLNamePool()
-{
-}
-
-void LLGLNamePool::upkeep()
-{
- std::sort(mNameList.begin(), mNameList.end(), CompareUsed());
-}
-
-void LLGLNamePool::cleanup()
-{
- for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
- {
- releaseName(iter->name);
- }
-
- mNameList.clear();
-}
-
-GLuint LLGLNamePool::allocate()
-{
- LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
-#if LL_GL_NAME_POOLING
- for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
- {
- if (!iter->used)
- {
- iter->used = TRUE;
- return iter->name;
- }
- }
-
- NameEntry entry;
- entry.name = allocateName();
- entry.used = TRUE;
- mNameList.push_back(entry);
-
- return entry.name;
-#else
- return allocateName();
-#endif
-}
-
-void LLGLNamePool::release(GLuint name)
-{
-#if LL_GL_NAME_POOLING
- for (name_list_t::iterator iter = mNameList.begin(); iter != mNameList.end(); ++iter)
- {
- if (iter->name == name)
- {
- if (iter->used)
- {
- iter->used = FALSE;
- return;
- }
- else
- {
- LL_ERRS() << "Attempted to release a pooled name that is not in use!" << LL_ENDL;
- }
- }
- }
- LL_ERRS() << "Attempted to release a non pooled name!" << LL_ENDL;
-#else
- releaseName(name);
-#endif
-}
-
-//static
-void LLGLNamePool::upkeepPools()
-{
- for (auto& pool : instance_snapshot())
- {
- pool.upkeep();
- }
-}
-
-//static
-void LLGLNamePool::cleanupPools()
-{
- for (auto& pool : instance_snapshot())
- {
- pool.cleanup();
- }
-}
-
LLGLDepthTest::LLGLDepthTest(GLboolean depth_enabled, GLboolean write_enabled, GLenum depth_func)
: mPrevDepthEnabled(sDepthEnabled), mPrevDepthFunc(sDepthFunc), mPrevWriteEnabled(sWriteEnabled)
{
@@ -2460,3 +2371,4 @@ extern "C"
}
#endif
+
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index ec97eb0faa..52338364e6 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -367,51 +367,6 @@ public:
};
/*
- Generic pooling scheme for things which use GL names (used for occlusion queries and vertex buffer objects).
- Prevents thrashing of GL name caches by avoiding calls to glGenFoo and glDeleteFoo.
-*/
-class LLGLNamePool : public LLInstanceTracker<LLGLNamePool>
-{
-public:
- typedef LLInstanceTracker<LLGLNamePool> tracker_t;
-
- struct NameEntry
- {
- GLuint name;
- BOOL used;
- };
-
- struct CompareUsed
- {
- bool operator()(const NameEntry& lhs, const NameEntry& rhs)
- {
- return lhs.used < rhs.used; //FALSE entries first
- }
- };
-
- typedef std::vector<NameEntry> name_list_t;
- name_list_t mNameList;
-
- LLGLNamePool();
- virtual ~LLGLNamePool();
-
- void upkeep();
- void cleanup();
-
- GLuint allocate();
- void release(GLuint name);
-
- static void upkeepPools();
- static void cleanupPools();
-
-protected:
- typedef std::vector<LLGLNamePool*> pool_list_t;
-
- virtual GLuint allocateName() = 0;
- virtual void releaseName(GLuint name) = 0;
-};
-
-/*
Interface for objects that need periodic GL updates applied to them.
Used to synchronize GL updates with GL thread.
*/
diff --git a/indra/llrender/llgltexture.cpp b/indra/llrender/llgltexture.cpp
index c7de8bc338..e012eb9a62 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 defer_copy)
+BOOL LLGLTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category, bool defer_copy, LLGLuint* tex_name)
{
- llassert(mGLTexturep.notNull()) ;
+ llassert(mGLTexturep.notNull());
- BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category, defer_copy) ;
+ BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category, defer_copy, tex_name) ;
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 use_new_name /* = false */)
+BOOL LLGLTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
llassert(mGLTexturep.notNull()) ;
- return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height, 0, use_new_name) ;
+ return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height, 0, use_name) ;
}
-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 */)
+BOOL LLGLTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
llassert(mGLTexturep.notNull()) ;
- return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height, 0, use_new_name) ;
+ return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height, 0, use_name) ;
}
void LLGLTexture::setGLTextureCreated (bool initialized)
diff --git a/indra/llrender/llgltexture.h b/indra/llrender/llgltexture.h
index 216e7f640d..8cfe7b62de 100644
--- a/indra/llrender/llgltexture.h
+++ b/indra/llrender/llgltexture.h
@@ -132,13 +132,14 @@ public:
// 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);
+ // tex_name - if not null, will be set to the GL name of the texture created
+ BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLGLTexture::OTHER, bool defer_copy = false, LLGLuint* tex_name = nullptr);
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 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);
+ BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name = 0);
+ BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, LLGLuint use_name = 0);
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 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;
+}
+
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 6c6e327e42..50706890f9 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -110,17 +110,17 @@ public:
BOOL createGLTexture() ;
BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE,
- 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);
+ S32 category = sMaxCategories-1, bool defer_copy = false, LLGLuint* tex_name = nullptr);
+ BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0, bool defer_copy = false, LLGLuint* tex_name = nullptr);
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 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 setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE, LLGLuint use_name = 0);
+ 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, LLGLuint use_name = 0);
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();
+ void syncToMainThread(LLGLuint new_tex_name);
// Read back a raw image for this discard level, if it exists
BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
@@ -224,7 +224,7 @@ private:
bool mGLTextureCreated ;
LLGLuint mTexName;
- LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread
+ //LLGLuint mNewTexName = 0; // tex name set by background thread to be applied in main thread
U16 mWidth;
U16 mHeight;
S8 mCurrentDiscardLevel;
@@ -324,6 +324,9 @@ public:
// follows gSavedSettings "RenderGLMultiThreaded"
static bool sEnabled;
+ // free video memory in megabytes
+ static std::atomic<S32> sFreeVRAMMegabytes;
+
LLImageGLThread(LLWindow* window);
// post a function to be executed on the LLImageGL background thread
@@ -335,6 +338,8 @@ public:
void run() override;
+ static S32 getFreeVRAMMegabytes();
+
private:
LLWindow* mWindow;
void* mContext = nullptr;
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 8c792daac0..5ce51bb43e 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -3564,6 +3564,7 @@ void LLWindowWin32::swapBuffers()
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32;
ASSERT_MAIN_THREAD();
+ glFlush(); //superstitious flush for maybe frame stall removal?
SwapBuffers(mhDC);
LL_PROFILER_GPU_COLLECT
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 471b0e2c48..20287a7777 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -54,6 +54,8 @@
// static
LLStandardBumpmap gStandardBumpmapList[TEM_BUMPMAP_COUNT];
+LL::WorkQueue::weak_t LLBumpImageList::sMainQueue;
+LL::WorkQueue::weak_t LLBumpImageList::sTexUpdateQueue;
// static
U32 LLStandardBumpmap::sStandardBumpmapCount = 0;
@@ -761,6 +763,8 @@ void LLBumpImageList::init()
LLStandardBumpmap::init();
LLStandardBumpmap::restoreGL();
+ sMainQueue = LL::WorkQueue::getInstance("mainloop");
+ sTexUpdateQueue = LL::WorkQueue::getInstance("LLImageGL"); // Share work queue with tex loader.
}
void LLBumpImageList::clear()
@@ -909,10 +913,7 @@ LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedText
}
else
{
- LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
- raw->clear(0x77, 0x77, 0xFF, 0xFF);
-
- (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
+ (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( TRUE );
bump = (*entries_list)[src_image->getID()]; // In case callback was called immediately and replaced the image
}
@@ -1043,10 +1044,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
iter->second->getWidth() != src->getWidth() ||
iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
{ //make sure an entry exists for this image
- LLPointer<LLImageRaw> raw = new LLImageRaw(1,1,1);
- raw->clear(0x77, 0x77, 0xFF, 0xFF);
-
- entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE);
+ entries_list[src_vi->getID()] = LLViewerTextureManager::getLocalTexture(TRUE);
iter = entries_list.find(src_vi->getID());
}
}
@@ -1166,108 +1164,161 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
}
//---------------------------------------------------
- // immediately assign bump to a global smart pointer in case some local smart pointer
+ // immediately assign bump to a smart pointer in case some local smart pointer
// accidentally releases it.
- LLPointer<LLViewerTexture> bump = LLViewerTextureManager::getLocalTexture( TRUE );
+ LLPointer<LLViewerTexture> bump = iter->second;
if (!LLPipeline::sRenderDeferred)
{
bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA);
- bump->createGLTexture(0, dst_image);
+
+ auto tex_queue = LLImageGLThread::sEnabled ? sTexUpdateQueue.lock() : nullptr;
+
+ if (tex_queue)
+ { //dispatch creation to background thread
+ LLImageRaw* dst_ptr = dst_image;
+ LLViewerTexture* bump_ptr = bump;
+ dst_ptr->ref();
+ bump_ptr->ref();
+ tex_queue->post(
+ [=]()
+ {
+ LL_PROFILE_ZONE_NAMED("bil - create texture");
+ bump_ptr->createGLTexture(0, dst_ptr);
+ bump_ptr->unref();
+ dst_ptr->unref();
+ });
+ }
+ else
+ {
+ bump->createGLTexture(0, dst_image);
+ }
}
else
{ //convert to normal map
//disable compression on normal maps to prevent errors below
bump->getGLTexture()->setAllowCompression(false);
+ bump->getGLTexture()->setUseMipMaps(TRUE);
- {
- bump->setExplicitFormat(GL_RGBA8, GL_ALPHA);
- bump->createGLTexture(0, dst_image);
- }
+ auto* bump_ptr = bump.get();
+ auto* dst_ptr = dst_image.get();
- {
- gPipeline.mScreen.bindTarget();
-
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable cull(GL_CULL_FACE);
- LLGLDisable blend(GL_BLEND);
- gGL.setColorMask(TRUE, TRUE);
- gNormalMapGenProgram.bind();
+ bump_ptr->ref();
+ dst_ptr->ref();
- static LLStaticHashedString sNormScale("norm_scale");
- static LLStaticHashedString sStepX("stepX");
- static LLStaticHashedString sStepY("stepY");
+ bump_ptr->setExplicitFormat(GL_RGBA8, GL_ALPHA);
- gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
- gNormalMapGenProgram.uniform1f(sStepX, 1.f/bump->getWidth());
- gNormalMapGenProgram.uniform1f(sStepY, 1.f/bump->getHeight());
+ auto create_texture = [bump_ptr, dst_ptr]()
+ {
+ LL_PROFILE_ZONE_NAMED("bil - create texture deferred");
+ bump_ptr->createGLTexture(0, dst_ptr);
+ };
- LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(),
- (F32) bump->getHeight()/gPipeline.mScreen.getHeight());
+ auto gen_normal_map = [bump_ptr, dst_ptr]()
+ {
+ LL_PROFILE_ZONE_NAMED("bil - generate normal map");
+ gPipeline.mScreen.bindTarget();
- gGL.getTexUnit(0)->bind(bump);
-
- S32 width = bump->getWidth();
- S32 height = bump->getHeight();
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+ LLGLDisable blend(GL_BLEND);
+ gGL.setColorMask(TRUE, TRUE);
+ gNormalMapGenProgram.bind();
- S32 screen_width = gPipeline.mScreen.getWidth();
- S32 screen_height = gPipeline.mScreen.getHeight();
+ static LLStaticHashedString sNormScale("norm_scale");
+ static LLStaticHashedString sStepX("stepX");
+ static LLStaticHashedString sStepY("stepY");
- glViewport(0, 0, screen_width, screen_height);
+ gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
+ gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth());
+ gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight());
- for (S32 left = 0; left < width; left += screen_width)
- {
- S32 right = left + screen_width;
- right = llmin(right, width);
-
- F32 left_tc = (F32) left/ width;
- F32 right_tc = (F32) right/width;
+ LLVector2 v((F32)bump_ptr->getWidth() / gPipeline.mScreen.getWidth(),
+ (F32)bump_ptr->getHeight() / gPipeline.mScreen.getHeight());
- for (S32 bottom = 0; bottom < height; bottom += screen_height)
- {
- S32 top = bottom+screen_height;
- top = llmin(top, height);
+ gGL.getTexUnit(0)->bind(bump_ptr);
- F32 bottom_tc = (F32) bottom/height;
- F32 top_tc = (F32)(bottom+screen_height)/height;
- top_tc = llmin(top_tc, 1.f);
+ S32 width = bump_ptr->getWidth();
+ S32 height = bump_ptr->getHeight();
- F32 screen_right = (F32) (right-left)/screen_width;
- F32 screen_top = (F32) (top-bottom)/screen_height;
+ S32 screen_width = gPipeline.mScreen.getWidth();
+ S32 screen_height = gPipeline.mScreen.getHeight();
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(left_tc, bottom_tc);
- gGL.vertex2f(0, 0);
+ glViewport(0, 0, screen_width, screen_height);
- gGL.texCoord2f(left_tc, top_tc);
- gGL.vertex2f(0, screen_top);
+ for (S32 left = 0; left < width; left += screen_width)
+ {
+ S32 right = left + screen_width;
+ right = llmin(right, width);
- gGL.texCoord2f(right_tc, bottom_tc);
- gGL.vertex2f(screen_right, 0);
+ F32 left_tc = (F32)left / width;
+ F32 right_tc = (F32)right / width;
- gGL.texCoord2f(right_tc, top_tc);
- gGL.vertex2f(screen_right, screen_top);
+ for (S32 bottom = 0; bottom < height; bottom += screen_height)
+ {
+ S32 top = bottom + screen_height;
+ top = llmin(top, height);
- gGL.end();
+ F32 bottom_tc = (F32)bottom / height;
+ F32 top_tc = (F32)(bottom + screen_height) / height;
+ top_tc = llmin(top_tc, 1.f);
- gGL.flush();
+ F32 screen_right = (F32)(right - left) / screen_width;
+ F32 screen_top = (F32)(top - bottom) / screen_height;
- S32 w = right-left;
- S32 h = top-bottom;
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(left_tc, bottom_tc);
+ gGL.vertex2f(0, 0);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h);
- }
- }
+ gGL.texCoord2f(left_tc, top_tc);
+ gGL.vertex2f(0, screen_top);
- glGenerateMipmap(GL_TEXTURE_2D);
+ gGL.texCoord2f(right_tc, bottom_tc);
+ gGL.vertex2f(screen_right, 0);
- gPipeline.mScreen.flush();
+ gGL.texCoord2f(right_tc, top_tc);
+ gGL.vertex2f(screen_right, screen_top);
- gNormalMapGenProgram.unbind();
-
- //generateNormalMapFromAlpha(dst_image, nrm_image);
- }
+ gGL.end();
+
+ gGL.flush();
+
+ S32 w = right - left;
+ S32 h = top - bottom;
+
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h);
+ }
+ }
+
+ glGenerateMipmap(GL_TEXTURE_2D);
+
+ gPipeline.mScreen.flush();
+
+ gNormalMapGenProgram.unbind();
+
+ //generateNormalMapFromAlpha(dst_image, nrm_image);
+
+ bump_ptr->unref();
+ dst_ptr->unref();
+ };
+
+ auto main_queue = LLImageGLThread::sEnabled ? sMainQueue.lock() : nullptr;
+
+ if (main_queue)
+ { //dispatch creation to background thread
+ LLImageRaw* dst_ptr = dst_image;
+ LLViewerTexture* bump_ptr = bump;
+ dst_ptr->ref();
+ bump_ptr->ref();
+
+ main_queue->postTo(sTexUpdateQueue, create_texture, gen_normal_map);
+ }
+ else
+ {
+ create_texture();
+ gen_normal_map();
+ }
}
iter->second = bump; // derefs (and deletes) old image
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 38744a7d98..6e21859738 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -161,6 +161,8 @@ private:
typedef std::unordered_map<LLUUID, LLPointer<LLViewerTexture> > bump_image_map_t;
bump_image_map_t mBrightnessEntries;
bump_image_map_t mDarknessEntries;
+ static LL::WorkQueue::weak_t sMainQueue;
+ static LL::WorkQueue::weak_t sTexUpdateQueue;
};
extern LLBumpImageList gBumpImageList;
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index b5d3dc5d30..4fc1bdbec3 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -649,9 +649,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD_PARTICLES);
}
- //upkeep gl name pools
- LLGLNamePool::upkeepPools();
-
stop_glerror();
display_update_camera();
stop_glerror();
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index bd60b9f1e2..42bd5d8367 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -2986,11 +2986,12 @@ void LLViewerMediaImpl::doMediaTexUpdate(LLViewerMediaTexture* media_tex, U8* da
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);
+ LLGLuint tex_name = 0;
+ media_tex->createGLTexture(0, raw, 0, TRUE, LLGLTexture::OTHER, true, &tex_name);
// 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();
+ media_tex->setSubImage(data, data_width, data_height, x_pos, y_pos, width, height, tex_name);
+ media_tex->getGLTexture()->syncToMainThread(tex_name);
// release the data pointer before freeing raw so LLImageRaw destructor doesn't
// free memory at data pointer
diff --git a/indra/newview/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 3cdef0ebff..65e9fa533d 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -787,42 +787,73 @@ void LLViewerOctreeGroup::checkStates()
//occulsion culling functions and classes
//-------------------------------------------------------------------------------------------
std::set<U32> LLOcclusionCullingGroup::sPendingQueries;
-class LLOcclusionQueryPool : public LLGLNamePool
+
+static std::queue<GLuint> sFreeQueries;
+
+U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName()
{
-public:
- LLOcclusionQueryPool()
- {
- }
+ LL_PROFILE_ZONE_SCOPED;
+ // TODO: refactor this to a general purpose name pool
+ static GLuint occlusion_queries[2][1024];
+ static std::atomic<S32> query_count[2];
+ static S32 query_page = -1;
+
+ //reuse any query names that have been freed
+ if (!sFreeQueries.empty())
+ {
+ GLuint ret = sFreeQueries.front();
+ sFreeQueries.pop();
+ return ret;
+ }
-protected:
+ // first call, immediately fill entire name pool
+ if (query_page == -1)
+ {
+ glGenQueriesARB(1024, occlusion_queries[0]);
+ glGenQueriesARB(1024, occlusion_queries[1]);
+ query_page = 0;
+ query_count[0] = 1024;
+ query_count[1] = 1024;
+ }
- virtual GLuint allocateName()
- {
- GLuint ret = 0;
+ if (query_count[query_page] == 0) //this page is empty
+ {
+ //check the other page
+ query_page = (query_page + 1) % 2;
- glGenQueriesARB(1, &ret);
-
- return ret;
- }
+ if (query_count[query_page] == 0)
+ {
+ //the other page is also empty, generate immediately and return
+ GLuint ret;
+ glGenQueriesARB(1, &ret);
+ return ret;
+ }
+ }
- virtual void releaseName(GLuint name)
- {
-#if LL_TRACK_PENDING_OCCLUSION_QUERIES
- LLOcclusionCullingGroup::sPendingQueries.erase(name);
-#endif
- glDeleteQueriesARB(1, &name);
- }
-};
+ GLuint ret = occlusion_queries[query_page][--query_count[query_page]];
-static LLOcclusionQueryPool sQueryPool;
-U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName()
-{
- return sQueryPool.allocate();
+ if (query_count[query_page] == 0)
+ { //exhausted this page, replenish on background thread
+ S32 page = query_page;
+ LL::WorkQueue::postMaybe(LL::WorkQueue::getInstance("LLImageGL"),
+ [=]()
+ {
+ LL_PROFILE_ZONE_NAMED("glGenQueries bg");
+ if (query_count[page] == 0) // <-- protect against redundant attempts to replenish
+ {
+ glGenQueriesARB(1024, occlusion_queries[page]);
+ query_count[page] = 1024;
+ glFlush();
+ }
+ });
+ }
+
+ return ret;
}
void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(GLuint name)
{
- sQueryPool.release(name);
+ sFreeQueries.push(name);
}
//=====================================
@@ -1243,7 +1274,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
//store which frame this query was issued on
mOcclusionIssued[LLViewerCamera::sCurCameraID] = gFrameCount;
- glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ {
+ LL_PROFILE_ZONE_NAMED("glBeginQuery");
+ glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ }
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
llassert(shader);
@@ -1282,7 +1316,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
}
}
- glEndQueryARB(mode);
+ {
+ LL_PROFILE_ZONE_NAMED("glEndQuery");
+ glEndQueryARB(mode);
+ }
}
}
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5fed46f437..fa2c070ea0 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -515,9 +515,10 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
static LLFrameTimer timer;
+
static S32Megabytes gpu_res = S32Megabytes(S32_MAX);
static S32Megabytes physical_res = S32Megabytes(S32_MAX);
-
+
if (timer.getElapsedTimeF32() < GPU_MEMORY_CHECK_WAIT_TIME) //call this once per second.
{
gpu = gpu_res;
@@ -527,22 +528,11 @@ void LLViewerTexture::getGPUMemoryForTextures(S32Megabytes &gpu, S32Megabytes &p
timer.reset();
{
- if (gGLManager.mHasATIMemInfo)
- {
- S32 meminfo[4];
- glGetIntegerv(GL_TEXTURE_FREE_MEMORY_ATI, meminfo);
- gpu_res = (S32Megabytes)meminfo[0];
-
- //check main memory, only works for windows.
- LLMemory::updateMemoryInfo();
- physical_res = LLMemory::getAvailableMemKB();
- }
- else if (gGLManager.mHasNVXMemInfo)
- {
- S32 free_memory;
- glGetIntegerv(GL_GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &free_memory);
- gpu_res = (S32Megabytes)(free_memory / 1024);
- }
+ gpu_res = (S32Megabytes) LLImageGLThread::getFreeVRAMMegabytes();
+
+ //check main memory, only works for windows.
+ LLMemory::updateMemoryInfo();
+ physical_res = LLMemory::getAvailableMemKB();
gpu = gpu_res;
physical = physical_res;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 8d45e64bf8..ac242c2bf7 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -7267,11 +7267,6 @@ void LLPipeline::doResetVertexBuffers(bool forced)
SUBSYSTEM_CLEANUP(LLVertexBuffer);
- //delete all name pool caches
- LLGLNamePool::cleanupPools();
-
-
-
if (LLVertexBuffer::sGLCount > 0)
{
LL_WARNS() << "VBO wipe failed -- " << LLVertexBuffer::sGLCount << " buffers remaining." << LL_ENDL;