summaryrefslogtreecommitdiff
path: root/indra/llrender
diff options
context:
space:
mode:
authorMnikolenko Productengine <mnikolenko@productengine.com>2022-03-02 19:46:48 +0200
committerMnikolenko Productengine <mnikolenko@productengine.com>2022-03-02 19:46:48 +0200
commitf90d17905899d01db76b82b6d647bbecf1c47f23 (patch)
treedba8f9a514a02a9d86fe25c5d0ffccf30a6b754f /indra/llrender
parent064f28b290026be0e77cd38de78b06477a9c0876 (diff)
parent97a103255e433629f13e2156aa307ca329cdcfc6 (diff)
Merge branch 'DRTVWR-546' into DRTVWR-539
# Conflicts: # indra/llcommon/tests/llprocess_test.cpp # indra/llui/llcombobox.cpp # indra/llui/llcombobox.h # indra/newview/VIEWER_VERSION.txt # indra/newview/llviewertexturelist.cpp # indra/newview/llvovolume.cpp
Diffstat (limited to 'indra/llrender')
-rw-r--r--indra/llrender/llgl.cpp105
-rw-r--r--indra/llrender/llgl.h45
-rw-r--r--indra/llrender/llgltexture.cpp14
-rw-r--r--indra/llrender/llgltexture.h15
-rw-r--r--indra/llrender/llimagegl.cpp245
-rw-r--r--indra/llrender/llimagegl.h27
-rw-r--r--indra/llrender/llrender.cpp20
7 files changed, 248 insertions, 223 deletions
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 12da961cef..639d1fba32 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
@@ -1029,7 +1018,9 @@ void LLGLManager::initExtensions()
mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
- mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
+ // NOTE: Using extensions breaks reflections when Shadows are set to projector. See: SL-16727
+ //mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
+ mHasDepthClamp = FALSE;
// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
#ifdef GL_ARB_framebuffer_object
mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts);
@@ -2159,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)
{
@@ -2469,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 b6a02f1c0a..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 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) ;
+ 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 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) ;
+ 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 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) ;
+ 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 028457c510..8cfe7b62de 100644
--- a/indra/llrender/llgltexture.h
+++ b/indra/llrender/llgltexture.h
@@ -124,13 +124,22 @@ 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
+ // 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 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, 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 1e9b9f642e..f43671dee5 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()
@@ -436,7 +437,7 @@ LLImageGL::LLImageGL(
LLImageGL::~LLImageGL()
{
- if (!mExternalTexture)
+ if (!mExternalTexture && gGLManager.mInited)
{
LLImageGL::cleanup();
sImageList.erase(this);
@@ -550,7 +551,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 +675,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 +710,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 +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)
+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 (mTexName == 0)
+ 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;
@@ -1092,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);
+ setImage(datap, FALSE, tex_name);
}
else
{
@@ -1144,12 +1152,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, tex_name);
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 +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)
+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);
+ 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
@@ -1356,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 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();
@@ -1386,6 +1393,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 +1476,26 @@ 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, tex_name);
}
-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, LLGLuint* tex_name)
+// Call with void data, vmem is allocated but unitialized
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_TEXTURE;
checkActiveThread();
- llassert(data_in);
+ bool main_thread = on_main_thread();
+
+ if (defer_copy)
+ {
+ data_in = nullptr;
+ }
+ else
+ {
+ llassert(data_in);
+ }
+
stop_glerror();
if (discard_level < 0)
@@ -1486,28 +1505,41 @@ 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 (main_thread // <--- always force creation of new_texname when not on main thread ...
+ && !defer_copy // <--- ... or defer copy is set
+ && 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;
@@ -1515,9 +1547,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.
@@ -1534,47 +1569,23 @@ 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 (!defer_copy)
{
+ if (!main_thread)
{
- 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(new_texname);
}
-
- 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
- {
- //not on background thread, immediately set mTexName
- if (old_texname != 0)
+ else
{
- LLImageGL::deleteTextures(1, &old_texname);
+ //not on background thread, immediately set mTexName
+ if (old_texname != 0 && old_texname != new_texname)
+ {
+ LLImageGL::deleteTextures(1, &old_texname);
+ }
+ mTexName = new_texname;
}
- mTexName = mNewTexName;
- mNewTexName = 0;
}
+
mTextureMemory = (S32Bytes)getMipBytes(mCurrentDiscardLevel);
sGlobalTextureMemory += mTextureMemory;
@@ -1587,6 +1598,110 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
return TRUE;
}
+void LLImageGLThread::updateClass()
+{
+ LL_PROFILE_ZONE_SCOPED;
+
+ // update available vram one per second
+ static LLFrameTimer sTimer;
+
+ if (sTimer.getElapsedSeconds() < 1.f)
+ {
+ return;
+ }
+
+ sTimer.reset();
+
+ auto func = []()
+ {
+ 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;
+ }
+ };
+
+
+ // post update to background thread if available, otherwise execute immediately
+ auto queue = LL::WorkQueue::getInstance("LLImageGL");
+ if (sEnabled)
+ {
+ queue->post(func);
+ }
+ else
+ {
+ llassert(queue == nullptr);
+ func();
+ }
+}
+
+void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
+{
+ LL_PROFILE_ZONE_SCOPED;
+ llassert(!on_main_thread());
+
+ {
+ 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(
+ 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");
+ syncTexName(new_tex_name);
+ unref();
+ });
+}
+
+void LLImageGL::syncTexName(LLGLuint texname)
+{
+ if (texname != 0)
+ {
+ if (mTexName != 0 && mTexName != texname)
+ {
+ LLImageGL::deleteTextures(1, &mTexName);
+ }
+ mTexName = texname;
+ }
+}
+
BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
{
llassert_always(sAllowReadBackRaw) ;
@@ -1714,7 +1829,7 @@ void LLImageGL::destroyGLTexture()
mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
mTexName = 0;
mGLTextureCreated = FALSE ;
- }
+ }
}
//force to invalidate the gl texture, most likely a sculpty texture
@@ -2257,6 +2372,8 @@ void LLImageGL::checkActiveThread()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, nummips);
*/
+std::atomic<S32> LLImageGLThread::sFreeVRAMMegabytes(4096); //if free vram is unknown, default to 4GB
+
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()
@@ -2283,3 +2400,9 @@ void LLImageGLThread::run()
gGL.shutdown();
mWindow->destroySharedContext(mContext);
}
+
+S32 LLImageGLThread::getFreeVRAMMegabytes()
+{
+ return sFreeVRAMMegabytes;
+}
+
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index d6f4b13a51..4d5b60d6bc 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, 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 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, 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(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;
void destroyGLTexture();
@@ -220,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;
@@ -300,6 +304,9 @@ public:
void setTexName(GLuint texName) { mTexName = texName; }
+ //similar to setTexName, but will call deleteTextures on mTexName if mTexName is not 0 or texname
+ void syncTexName(LLGLuint texname);
+
//for debug use: show texture size distribution
//----------------------------------------
static S32 sCurTexSizeBar ;
@@ -319,6 +326,12 @@ class LLImageGLThread : public LLSimpleton<LLImageGLThread>, LL::ThreadPool
public:
// follows gSavedSettings "RenderGLMultiThreaded"
static bool sEnabled;
+
+ // app should call this function periodically
+ static void updateClass();
+
+ // free video memory in megabytes
+ static std::atomic<S32> sFreeVRAMMegabytes;
LLImageGLThread(LLWindow* window);
@@ -331,6 +344,8 @@ public:
void run() override;
+ static S32 getFreeVRAMMegabytes();
+
private:
LLWindow* mWindow;
void* mContext = nullptr;
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);