summaryrefslogtreecommitdiff
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
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
-rw-r--r--indra/llcommon/llrefcount.cpp5
-rw-r--r--indra/llcommon/llrefcount.h16
-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.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
-rw-r--r--indra/llui/llcombobox.cpp47
-rw-r--r--indra/llui/llcombobox.h8
-rw-r--r--indra/llwindow/llwindowwin32.cpp1
-rw-r--r--indra/newview/CMakeLists.txt6
-rw-r--r--indra/newview/app_settings/settings.xml2
-rw-r--r--indra/newview/featuretable.txt6
-rw-r--r--indra/newview/featuretable_mac.txt2
-rw-r--r--indra/newview/llagentcamera.cpp19
-rw-r--r--indra/newview/llagentcamera.h6
-rw-r--r--indra/newview/llappviewer.cpp2
-rw-r--r--indra/newview/lldrawpool.h1
-rw-r--r--indra/newview/lldrawpoolalpha.cpp170
-rw-r--r--indra/newview/lldrawpoolalpha.h4
-rw-r--r--indra/newview/lldrawpoolbump.cpp226
-rw-r--r--indra/newview/lldrawpoolbump.h2
-rw-r--r--indra/newview/lldrawpoolwater.cpp11
-rw-r--r--indra/newview/llfloatermodelpreview.cpp9
-rw-r--r--indra/newview/llinventorybridge.cpp5
-rw-r--r--indra/newview/llinventorybridge.h1
-rw-r--r--indra/newview/llmodelpreview.cpp135
-rw-r--r--indra/newview/llnetmap.cpp4
-rw-r--r--indra/newview/llspatialpartition.cpp31
-rw-r--r--indra/newview/llspatialpartition.h13
-rw-r--r--indra/newview/lltoolmorph.cpp13
-rw-r--r--indra/newview/lltracker.cpp11
-rw-r--r--indra/newview/llviewercontrol.cpp3
-rw-r--r--indra/newview/llviewerdisplay.cpp5
-rw-r--r--indra/newview/llviewermedia.cpp408
-rw-r--r--indra/newview/llviewermedia.h13
-rw-r--r--indra/newview/llvieweroctree.cpp65
-rw-r--r--indra/newview/llviewerparcelmgr.cpp2
-rw-r--r--indra/newview/llviewertexture.cpp27
-rw-r--r--indra/newview/llviewerwindow.cpp6
-rw-r--r--indra/newview/llvoavatar.cpp39
-rw-r--r--indra/newview/llvoavatar.h7
-rw-r--r--indra/newview/llvovolume.cpp62
-rw-r--r--indra/newview/llvovolume.h1
-rw-r--r--indra/newview/pipeline.cpp192
-rw-r--r--indra/newview/pipeline.h3
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml7
52 files changed, 1335 insertions, 746 deletions
diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp
index 29a5ca6f24..5cbd346411 100644
--- a/indra/llcommon/llrefcount.cpp
+++ b/indra/llcommon/llrefcount.cpp
@@ -29,6 +29,9 @@
#include "llerror.h"
+// maximum reference count before sounding memory leak alarm
+const S32 gMaxRefCount = 65536;
+
LLRefCount::LLRefCount(const LLRefCount& other)
: mRef(0)
{
@@ -47,7 +50,7 @@ LLRefCount::LLRefCount() :
LLRefCount::~LLRefCount()
{
- if (mRef != 0)
+ if (mRef != LL_REFCOUNT_FREE && mRef != 0)
{
LL_ERRS() << "deleting non-zero reference" << LL_ENDL;
}
diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h
index 7e4af6ea66..2080da1565 100644
--- a/indra/llcommon/llrefcount.h
+++ b/indra/llcommon/llrefcount.h
@@ -37,6 +37,10 @@ class LLMutex;
// see llthread.h for LLThreadSafeRefCount
//----------------------------------------------------------------------------
+//nonsense but recognizable value for freed LLRefCount (aids in debugging)
+#define LL_REFCOUNT_FREE 1234567890
+extern const S32 gMaxRefCount;
+
class LL_COMMON_API LLRefCount
{
protected:
@@ -47,17 +51,25 @@ protected:
public:
LLRefCount();
+ inline void validateRefCount() const
+ {
+ llassert(mRef > 0); // ref count below 0, likely corrupted
+ llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak
+ }
+
inline void ref() const
{
mRef++;
+ validateRefCount();
}
inline S32 unref() const
{
- llassert(mRef >= 1);
+ validateRefCount();
if (0 == --mRef)
{
- delete this;
+ mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging
+ delete this;
return 0;
}
return mRef;
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 fd20024f7e..efa1a4076b 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 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);
diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp
index 5768686659..9ca05a16f3 100644
--- a/indra/llui/llcombobox.cpp
+++ b/indra/llui/llcombobox.cpp
@@ -78,7 +78,6 @@ LLComboBox::Params::Params()
combo_button("combo_button"),
combo_list("combo_list"),
combo_editor("combo_editor"),
- mouse_down_callback("mouse_down_callback"),
drop_down_button("drop_down_button")
{
addSynonym(items, "combo_item");
@@ -98,8 +97,7 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
mTextChangedCallback(p.text_changed_callback()),
mListPosition(p.list_position),
mLastSelectedIndex(-1),
- mLabel(p.label),
- mMouseDownSignal(NULL)
+ mLabel(p.label)
{
// Text label button
@@ -115,6 +113,10 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
}
mArrowImage = button_params.image_unselected;
+ if (mArrowImage.notNull())
+ {
+ mImageLoadedConnection = mArrowImage->addLoadedCallback(boost::bind(&LLComboBox::imageLoaded, this));
+ }
mButton = LLUICtrlFactory::create<LLButton>(button_params);
@@ -155,11 +157,6 @@ LLComboBox::LLComboBox(const LLComboBox::Params& p)
createLineEditor(p);
- if (p.mouse_down_callback.isProvided())
- {
- setMouseDownCallback(initCommitCallback(p.mouse_down_callback));
- }
-
mTopLostSignalConnection = setTopLostCallback(boost::bind(&LLComboBox::hideList, this));
}
@@ -190,7 +187,7 @@ LLComboBox::~LLComboBox()
// explicitly disconect this signal, since base class destructor might fire top lost
mTopLostSignalConnection.disconnect();
- delete mMouseDownSignal;
+ mImageLoadedConnection.disconnect();
}
@@ -717,9 +714,6 @@ void LLComboBox::hideList()
void LLComboBox::onButtonMouseDown()
{
- if (mMouseDownSignal)
- (*mMouseDownSignal)( this, 0 );
-
if (!mList->getVisible())
{
// this might change selection, so do it first
@@ -1085,6 +1079,30 @@ void LLComboBox::onSetHighlight() const
}
}
+void LLComboBox::imageLoaded()
+{
+ static LLUICachedControl<S32> drop_shadow_button("DropShadowButton", 0);
+
+ if (mAllowTextEntry)
+ {
+ LLRect rect = getLocalRect();
+ S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
+ S32 shadow_size = drop_shadow_button;
+ mButton->setRect(LLRect(getRect().getWidth() - llmax(8, arrow_width) - 2 * shadow_size,
+ rect.mTop, rect.mRight, rect.mBottom));
+ if (mButton->getVisible())
+ {
+ // recalculate field size
+ if (mTextEntry)
+ {
+ LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
+ text_entry_rect.mRight -= llmax(8, arrow_width) + 2 * drop_shadow_button;
+ mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE);
+ }
+ }
+ }
+}
+
//============================================================================
// LLCtrlListInterface functions
@@ -1194,11 +1212,6 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last )
return mList->selectItemRange(first, last);
}
-boost::signals2::connection LLComboBox::setMouseDownCallback( const commit_signal_t::slot_type& cb )
-{
- if (!mMouseDownSignal) mMouseDownSignal = new commit_signal_t();
- return mMouseDownSignal->connect(cb);
-}
static LLDefaultChildRegistry::Register<LLIconsComboBox> register_icons_combo_box("icons_combo_box");
diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h
index 49a55c98a3..cac8850a25 100644
--- a/indra/llui/llcombobox.h
+++ b/indra/llui/llcombobox.h
@@ -78,8 +78,6 @@ public:
text_entry_callback,
text_changed_callback;
- Optional<CommitCallbackParam> mouse_down_callback;
-
Optional<EPreferredPosition, PreferredPositionValues> list_position;
// components
@@ -107,6 +105,8 @@ protected:
virtual std::string _getSearchText() const;
virtual void onSetHighlight() const;
+ void imageLoaded();
+
public:
// LLView interface
virtual void onFocusLost();
@@ -209,8 +209,6 @@ public:
void setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; }
void setTextChangedCallback( commit_callback_t cb ) { mTextChangedCallback = cb; }
- boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb );
-
/**
* Connects callback to signal called when Return key is pressed.
*/
@@ -248,7 +246,7 @@ private:
commit_callback_t mTextChangedCallback;
commit_callback_t mSelectionCallback;
boost::signals2::connection mTopLostSignalConnection;
- commit_signal_t* mMouseDownSignal;
+ boost::signals2::connection mImageLoadedConnection;
commit_signal_t mOnReturnSignal;
S32 mLastSelectedIndex;
};
diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp
index 09e2896392..f26e3a84d2 100644
--- a/indra/llwindow/llwindowwin32.cpp
+++ b/indra/llwindow/llwindowwin32.cpp
@@ -3566,6 +3566,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/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 73b234eb75..e7f0af84ef 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1697,6 +1697,8 @@ set(viewer_APPSETTINGS_FILES
${CMAKE_SOURCE_DIR}/../etc/message.xml
${CMAKE_SOURCE_DIR}/../scripts/messages/message_template.msg
packages-info.txt
+ featuretable.txt
+ featuretable_mac.txt
)
source_group("App Settings" FILES ${viewer_APPSETTINGS_FILES})
@@ -1751,10 +1753,6 @@ endif (HAVOK OR HAVOK_TPV)
# progress view disables/enables icons based on available packages
set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
-if (GLODLIB)
- set_source_files_properties(llfloatermodelpreview.cpp PROPERTIES COMPILE_FLAGS "-DLL_GLOD")
-endif (GLODLIB)
-
list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES})
set_source_files_properties(${viewer_HEADER_FILES}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index bb83824628..bfc47d2c65 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -9886,7 +9886,7 @@
<key>Value</key>
<real>2.2</real>
</map>
- <key>RenderGLCoreProfile</key>
+ <key>RenderGLContextCoreProfile</key>
<map>
<key>Comment</key>
<string>Don't use a compatibility profile OpenGL context. Requires restart. Basic shaders MUST be enabled.</string>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index a5e0e395de..ff7ac84803 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -70,7 +70,7 @@ RenderShadowDetail 1 2
RenderUseStreamVBO 1 1
RenderFSAASamples 1 16
RenderMaxTextureIndex 1 16
-RenderGLCoreProfile 1 1
+RenderGLContextCoreProfile 1 1
RenderGLMultiThreaded 1 1
@@ -320,12 +320,12 @@ list Intel
RenderAnisotropic 1 0
RenderFSAASamples 1 0
RenderGLMultiThreaded 1 0
-RenderGLCoreProfile 1 0
+RenderGLContextCoreProfile 1 0
// AMD cards generally perform better when not using VBOs for streaming data
// AMD cards also prefer an OpenGL Compatibility Profile Context
list AMD
RenderUseStreamVBO 1 0
-RenderGLCoreProfile 1 0
+RenderGLContextCoreProfile 1 0
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 5140614bab..248eb68ee9 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -70,7 +70,7 @@ RenderShadowDetail 1 2
RenderUseStreamVBO 1 1
RenderFSAASamples 1 16
RenderMaxTextureIndex 1 16
-RenderGLCoreProfile 1 0
+RenderGLContextCoreProfile 1 0
RenderGLMultiThreaded 1 0
//
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index ed6c3c307f..84a41113be 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -210,9 +210,6 @@ void LLAgentCamera::init()
mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPresetType");
- mCameraOffsetInitial = gSavedSettings.getControl("CameraOffsetRearView");
- mFocusOffsetInitial = gSavedSettings.getControl("FocusOffsetRearView");
-
mCameraCollidePlane.clearVec();
mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale");
mTargetCameraDistance = mCurrentCameraDistance;
@@ -1672,8 +1669,8 @@ LLVector3d LLAgentCamera::calcThirdPersonFocusOffset()
agent_rot *= ((LLViewerObject*)(gAgentAvatarp->getParent()))->getRenderRotation();
}
- focus_offset = convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, "");
- return focus_offset * agent_rot;
+ static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d());
+ return focus_offset_initial * agent_rot;
}
void LLAgentCamera::setupSitCamera()
@@ -1810,8 +1807,9 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
}
else
{
- local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale");
-
+ static LLCachedControl<F32> camera_offset_scale(gSavedSettings, "CameraOffsetScale");
+ local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * camera_offset_scale;
+
// are we sitting down?
if (isAgentAvatarValid() && gAgentAvatarp->getParent())
{
@@ -2028,12 +2026,15 @@ bool LLAgentCamera::isJoystickCameraUsed()
LLVector3 LLAgentCamera::getCameraOffsetInitial()
{
- return convert_from_llsd<LLVector3>(mCameraOffsetInitial->get(), TYPE_VEC3, "");
+ // getCameraOffsetInitial and getFocusOffsetInitial can be called on update from idle before init()
+ static LLCachedControl<LLVector3> camera_offset_initial (gSavedSettings, "CameraOffsetRearView", LLVector3());
+ return camera_offset_initial;
}
LLVector3d LLAgentCamera::getFocusOffsetInitial()
{
- return convert_from_llsd<LLVector3d>(mFocusOffsetInitial->get(), TYPE_VEC3D, "");
+ static LLCachedControl<LLVector3d> focus_offset_initial(gSavedSettings, "FocusOffsetRearView", LLVector3d());
+ return focus_offset_initial;
}
F32 LLAgentCamera::getCameraMaxZoomDistance()
diff --git a/indra/newview/llagentcamera.h b/indra/newview/llagentcamera.h
index ec1ed433d7..89680f95dc 100644
--- a/indra/newview/llagentcamera.h
+++ b/indra/newview/llagentcamera.h
@@ -131,12 +131,6 @@ private:
/** Camera preset in Third Person Mode */
ECameraPreset mCameraPreset;
- /** Initial camera offset */
- LLPointer<LLControlVariable> mCameraOffsetInitial;
-
- /** Initial focus offset */
- LLPointer<LLControlVariable> mFocusOffsetInitial;
-
LLQuaternion mInitSitRot;
//--------------------------------------------------------------------
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 73d0eac0ac..66c44ef6a6 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -532,7 +532,7 @@ static void settings_to_globals()
LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
- LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile");
+ LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLContextCoreProfile");
LLRender::sNsightDebugSupport = gSavedSettings.getBOOL("RenderNsightDebugSupport");
LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index d4f30fc51a..fd1b022e5b 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -183,6 +183,7 @@ public:
PASS_GLOW,
PASS_GLOW_RIGGED,
PASS_ALPHA,
+ PASS_ALPHA_RIGGED,
PASS_ALPHA_MASK,
PASS_ALPHA_MASK_RIGGED,
PASS_FULLBRIGHT_ALPHA_MASK, // Diffuse texture used as alpha mask and fullbright
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 9da20cc375..2bf8e9b911 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -129,23 +129,26 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass)
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
deferred_render = TRUE;
- // first pass, regular forward alpha rendering
- {
- emissive_shader = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
- prepare_alpha_shader(emissive_shader, true, false);
-
- fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram :
- (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
- prepare_alpha_shader(fullbright_shader, true, false);
-
- simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
- (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
- prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms)
-
- forwardRender();
- }
+ // prepare shaders
+ emissive_shader = (LLPipeline::sUnderWaterRender) ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
+ prepare_alpha_shader(emissive_shader, true, false);
+
+ fullbright_shader = (LLPipeline::sImpostorRender) ? &gDeferredFullbrightProgram :
+ (LLPipeline::sUnderWaterRender) ? &gDeferredFullbrightWaterProgram : &gDeferredFullbrightProgram;
+ prepare_alpha_shader(fullbright_shader, true, false);
+
+ simple_shader = (LLPipeline::sImpostorRender) ? &gDeferredAlphaImpostorProgram :
+ (LLPipeline::sUnderWaterRender) ? &gDeferredAlphaWaterProgram : &gDeferredAlphaProgram;
+ prepare_alpha_shader(simple_shader, false, true); //prime simple shader (loads shadow relevant uniforms)
+
- // second pass, render to depth for depth of field effects
+ // first pass, render rigged objects only and render to depth buffer
+ forwardRender(true);
+
+ // second pass, regular forward alpha rendering
+ forwardRender();
+
+ // final pass, render to depth for depth of field effects
if (!LLPipeline::sImpostorRender && gSavedSettings.getBOOL("RenderDepthOfField"))
{
//update depth buffer sampler
@@ -209,10 +212,14 @@ void LLDrawPoolAlpha::render(S32 pass)
prepare_forward_shader(fullbright_shader, minimum_alpha);
prepare_forward_shader(simple_shader, minimum_alpha);
+ //first pass -- rigged only and drawn to depth buffer
+ forwardRender(true);
+
+ //second pass -- non-rigged, no depth buffer writes
forwardRender();
}
-void LLDrawPoolAlpha::forwardRender()
+void LLDrawPoolAlpha::forwardRender(bool rigged)
{
gPipeline.enableLightsDynamic();
@@ -221,7 +228,8 @@ void LLDrawPoolAlpha::forwardRender()
//enable writing to alpha for emissive effects
gGL.setColorMask(true, true);
- bool write_depth = LLDrawPoolWater::sSkipScreenCopy
+ bool write_depth = rigged
+ || LLDrawPoolWater::sSkipScreenCopy
// we want depth written so that rendered alpha will
// contribute to the alpha mask used for impostors
|| LLPipeline::sImpostorRenderAlphaDepthPass;
@@ -236,11 +244,17 @@ void LLDrawPoolAlpha::forwardRender()
// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
// We don't want the nearly invisible objects to cause of DoF effects
- renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
+ renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, false, rigged);
gGL.setColorMask(true, false);
- renderDebugAlpha();
+ if (!rigged)
+ { //render "highlight alpha" on final non-rigged pass
+ // NOTE -- hacky call here protected by !rigged instead of alongside "forwardRender"
+ // so renderDebugAlpha is executed while gls_pipeline_alpha and depth GL state
+ // variables above are still in scope
+ renderDebugAlpha();
+ }
}
void LLDrawPoolAlpha::renderDebugAlpha()
@@ -291,54 +305,60 @@ void LLDrawPoolAlpha::renderDebugAlpha()
void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
{
- LLVOAvatar* lastAvatar = nullptr;
- U64 lastMeshId = 0;
+ for (int pass = 0; pass < 2; ++pass)
+ { //two passes, one rigged and one not
+ LLVOAvatar* lastAvatar = nullptr;
+ U64 lastMeshId = 0;
- for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (group->getSpatialPartition()->mRenderByGroup &&
- !group->isDead())
- {
- LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
+ LLCullResult::sg_iterator begin = pass == 0 ? gPipeline.beginAlphaGroups() : gPipeline.beginRiggedAlphaGroups();
+ LLCullResult::sg_iterator end = pass == 0 ? gPipeline.endAlphaGroups() : gPipeline.endRiggedAlphaGroups();
- for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
- {
- LLDrawInfo& params = **k;
-
- if (params.mParticle)
- {
- continue;
- }
-
- bool rigged = (params.mAvatar != nullptr);
- gHighlightProgram.bind(rigged);
- gGL.diffuseColor4f(1, 0, 0, 1);
+ for (LLCullResult::sg_iterator i = begin; i != end; ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (group->getSpatialPartition()->mRenderByGroup &&
+ !group->isDead())
+ {
+ LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA+pass]; // <-- hacky + pass to use PASS_ALPHA_RIGGED on second pass
- if (rigged)
+ for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
{
- if (lastAvatar != params.mAvatar ||
- lastMeshId != params.mSkinInfo->mHash)
+ LLDrawInfo& params = **k;
+
+ if (params.mParticle)
{
- if (!uploadMatrixPalette(params))
+ continue;
+ }
+
+ bool rigged = (params.mAvatar != nullptr);
+ gHighlightProgram.bind(rigged);
+ gGL.diffuseColor4f(1, 0, 0, 1);
+
+ if (rigged)
+ {
+ if (lastAvatar != params.mAvatar ||
+ lastMeshId != params.mSkinInfo->mHash)
{
- continue;
+ if (!uploadMatrixPalette(params))
+ {
+ continue;
+ }
+ lastAvatar = params.mAvatar;
+ lastMeshId = params.mSkinInfo->mHash;
}
- lastAvatar = params.mAvatar;
- lastMeshId = params.mSkinInfo->mHash;
}
- }
- LLRenderPass::applyModelMatrix(params);
- if (params.mGroup)
- {
- params.mGroup->rebuildMesh();
- }
- params.mVertexBuffer->setBufferFast(rigged ? mask | LLVertexBuffer::MAP_WEIGHT4 : mask);
- params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
- }
- }
- }
+ LLRenderPass::applyModelMatrix(params);
+ if (params.mGroup)
+ {
+ params.mGroup->rebuildMesh();
+ }
+ params.mVertexBuffer->setBufferFast(rigged ? mask | LLVertexBuffer::MAP_WEIGHT4 : mask);
+ params.mVertexBuffer->drawRangeFast(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+ }
+ }
+ }
+ }
// make sure static version of highlight shader is bound before returning
gHighlightProgram.bind();
@@ -471,6 +491,8 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&
LLVOAvatar* lastAvatar = nullptr;
U64 lastMeshId = 0;
+ mask |= LLVertexBuffer::MAP_WEIGHT4;
+
for (LLDrawInfo* draw : emissives)
{
bool tex_setup = TexSetup(draw, false);
@@ -488,7 +510,7 @@ void LLDrawPoolAlpha::renderRiggedEmissives(U32 mask, std::vector<LLDrawInfo*>&
}
}
-void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
+void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL;
BOOL initialized_lighting = FALSE;
@@ -498,7 +520,21 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
U64 lastMeshId = 0;
LLGLSLShader* lastAvatarShader = nullptr;
- for (LLCullResult::sg_iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
+ LLCullResult::sg_iterator begin;
+ LLCullResult::sg_iterator end;
+
+ if (rigged)
+ {
+ begin = gPipeline.beginRiggedAlphaGroups();
+ end = gPipeline.endRiggedAlphaGroups();
+ }
+ else
+ {
+ begin = gPipeline.beginAlphaGroups();
+ end = gPipeline.endAlphaGroups();
+ }
+
+ for (LLCullResult::sg_iterator i = begin; i != end; ++i)
{
LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("renderAlpha - group");
LLSpatialGroup* group = *i;
@@ -521,12 +557,18 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
bool disable_cull = is_particle_or_hud_particle;
LLGLDisable cull(disable_cull ? GL_CULL_FACE : 0);
- LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
+ LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA];
for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)
{
- LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch")
LLDrawInfo& params = **k;
+ if ((bool)params.mAvatar != rigged)
+ {
+ continue;
+ }
+
+ LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("ra - push batch")
+
U32 have_mask = params.mVertexBuffer->getTypeMask() & mask;
if (have_mask != mask)
{ //FIXME!
@@ -753,7 +795,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only)
bool LLDrawPoolAlpha::uploadMatrixPalette(const LLDrawInfo& params)
{
- const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar->updateSkinInfoMatrixPalette(params.mSkinInfo);
+ const LLVOAvatar::MatrixPaletteCache& mpc = params.mAvatar.get()->updateSkinInfoMatrixPalette(params.mSkinInfo);
U32 count = mpc.mMatrixPalette.size();
if (count == 0)
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index 1f6909e282..fa8ef0f227 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -55,13 +55,13 @@ public:
/*virtual*/ S32 getNumPasses() { return 1; }
virtual void render(S32 pass = 0);
- void forwardRender();
+ void forwardRender(bool write_depth = false);
/*virtual*/ void prerender();
void renderDebugAlpha();
void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
- void renderAlpha(U32 mask, bool depth_only = false);
+ void renderAlpha(U32 mask, bool depth_only = false, bool rigged = false);
void renderAlphaHighlight(U32 mask);
bool uploadMatrixPalette(const LLDrawInfo& params);
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 471b0e2c48..1d5419b515 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;
@@ -74,6 +76,8 @@ static S32 cube_channel = -1;
static S32 diffuse_channel = -1;
static S32 bump_channel = -1;
+#define LL_BUMPLIST_MULTITHREADED 0
+
// static
void LLStandardBumpmap::init()
{
@@ -761,6 +765,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 +915,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,16 +1046,13 @@ 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());
}
}
- //if (iter->second->getWidth() != src->getWidth() ||
- // iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
+ if (iter->second->getWidth() != src->getWidth() ||
+ iter->second->getHeight() != src->getHeight()) // bump not cached yet or has changed resolution
{
LLPointer<LLImageRaw> dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1);
U8* dst_data = dst_image->getData();
@@ -1166,108 +1166,178 @@ 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);
+
+#if LL_BUMPLIST_MULTITHREADED
+ 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
+#endif
+ {
+ 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();
+#if LL_BUMPLIST_MULTITHREADED
+ bump_ptr->ref();
+ dst_ptr->ref();
+#endif
- 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 = [=]()
+ {
+#if LL_IMAGEGL_THREAD_CHECK
+ bump_ptr->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+ LL_PROFILE_ZONE_NAMED("bil - create texture deferred");
+ bump_ptr->createGLTexture(0, dst_ptr);
+ };
+
+ auto gen_normal_map = [=]()
+ {
+#if LL_IMAGEGL_THREAD_CHECK
+ bump_ptr->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+ LL_PROFILE_ZONE_NAMED("bil - generate normal map");
+ if (gNormalMapGenProgram.mProgramObject == 0)
+ {
+#if LL_BUMPLIST_MULTITHREADED
+ bump_ptr->unref();
+ dst_ptr->unref();
+#endif
+ return;
+ }
+ gPipeline.mScreen.bindTarget();
- LLVector2 v((F32) bump->getWidth()/gPipeline.mScreen.getWidth(),
- (F32) bump->getHeight()/gPipeline.mScreen.getHeight());
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+ LLGLDisable blend(GL_BLEND);
+ gGL.setColorMask(TRUE, TRUE);
+ gNormalMapGenProgram.bind();
- gGL.getTexUnit(0)->bind(bump);
-
- S32 width = bump->getWidth();
- S32 height = bump->getHeight();
+ static LLStaticHashedString sNormScale("norm_scale");
+ static LLStaticHashedString sStepX("stepX");
+ static LLStaticHashedString sStepY("stepY");
- S32 screen_width = gPipeline.mScreen.getWidth();
- S32 screen_height = gPipeline.mScreen.getHeight();
+ gNormalMapGenProgram.uniform1f(sNormScale, gSavedSettings.getF32("RenderNormalMapScale"));
+ gNormalMapGenProgram.uniform1f(sStepX, 1.f / bump_ptr->getWidth());
+ gNormalMapGenProgram.uniform1f(sStepY, 1.f / bump_ptr->getHeight());
- glViewport(0, 0, screen_width, screen_height);
+ LLVector2 v((F32)bump_ptr->getWidth() / gPipeline.mScreen.getWidth(),
+ (F32)bump_ptr->getHeight() / gPipeline.mScreen.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;
+ gGL.getTexUnit(0)->bind(bump_ptr);
- for (S32 bottom = 0; bottom < height; bottom += screen_height)
- {
- S32 top = bottom+screen_height;
- top = llmin(top, height);
+ S32 width = bump_ptr->getWidth();
+ S32 height = bump_ptr->getHeight();
- F32 bottom_tc = (F32) bottom/height;
- F32 top_tc = (F32)(bottom+screen_height)/height;
- top_tc = llmin(top_tc, 1.f);
+ S32 screen_width = gPipeline.mScreen.getWidth();
+ S32 screen_height = gPipeline.mScreen.getHeight();
- F32 screen_right = (F32) (right-left)/screen_width;
- F32 screen_top = (F32) (top-bottom)/screen_height;
+ glViewport(0, 0, screen_width, screen_height);
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(left_tc, bottom_tc);
- gGL.vertex2f(0, 0);
+ for (S32 left = 0; left < width; left += screen_width)
+ {
+ S32 right = left + screen_width;
+ right = llmin(right, width);
- gGL.texCoord2f(left_tc, top_tc);
- gGL.vertex2f(0, screen_top);
+ F32 left_tc = (F32)left / width;
+ F32 right_tc = (F32)right / width;
- gGL.texCoord2f(right_tc, bottom_tc);
- gGL.vertex2f(screen_right, 0);
+ for (S32 bottom = 0; bottom < height; bottom += screen_height)
+ {
+ S32 top = bottom + screen_height;
+ top = llmin(top, height);
- gGL.texCoord2f(right_tc, top_tc);
- gGL.vertex2f(screen_right, screen_top);
+ F32 bottom_tc = (F32)bottom / height;
+ F32 top_tc = (F32)(bottom + screen_height) / height;
+ top_tc = llmin(top_tc, 1.f);
- gGL.end();
+ F32 screen_right = (F32)(right - left) / screen_width;
+ F32 screen_top = (F32)(top - bottom) / screen_height;
- gGL.flush();
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(left_tc, bottom_tc);
+ gGL.vertex2f(0, 0);
- S32 w = right-left;
- S32 h = top-bottom;
+ gGL.texCoord2f(left_tc, top_tc);
+ gGL.vertex2f(0, screen_top);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, left, bottom, 0, 0, w, h);
- }
- }
+ gGL.texCoord2f(right_tc, bottom_tc);
+ gGL.vertex2f(screen_right, 0);
- glGenerateMipmap(GL_TEXTURE_2D);
+ gGL.texCoord2f(right_tc, top_tc);
+ gGL.vertex2f(screen_right, screen_top);
- gPipeline.mScreen.flush();
+ gGL.end();
- gNormalMapGenProgram.unbind();
-
- //generateNormalMapFromAlpha(dst_image, nrm_image);
- }
+ 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);
+#if LL_BUMPLIST_MULTITHREADED
+ bump_ptr->unref();
+ dst_ptr->unref();
+#endif
+ };
+
+#if LL_BUMPLIST_MULTITHREADED
+ auto main_queue = sMainQueue.lock();
+
+ if (LLImageGLThread::sEnabled)
+ { //dispatch creation to background thread
+ main_queue->postTo(sTexUpdateQueue, create_texture, gen_normal_map);
+ }
+ else
+#endif
+ {
+ 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/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 0f2bcf4708..6762b38c39 100644
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -520,9 +520,10 @@ void LLDrawPoolWater::renderWater()
LLColor4 specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor());
F32 phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f;
- bool edge = false;
LLGLSLShader *shader = nullptr;
- do // twice through, once with normal shader bound & once with edge shader bound
+
+ // two passes, first with standard water shader bound, second with edge water shader bound
+ for( int edge = 0 ; edge < 2; edge++ )
{
// select shader
if (underwater && LLPipeline::sWaterReflections)
@@ -675,7 +676,7 @@ void LLDrawPoolWater::renderWater()
gGL.getTexUnit(diffTex)->bind(face->getTexture());
- if (edge == (bool) water->getIsEdgePatch())
+ if ((bool)edge == (bool) water->getIsEdgePatch())
{
face->renderIndexed();
@@ -699,9 +700,7 @@ void LLDrawPoolWater::renderWater()
shader->unbind();
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
-
- edge = !edge;
- } while (!edge);
+ }
gGL.getTexUnit(0)->activate();
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 6135c4f13e..fe5120376c 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -351,15 +351,6 @@ void LLFloaterModelPreview::initModelPreview()
//static
bool LLFloaterModelPreview::showModelPreview()
{
-#ifdef LL_GLOD
- if (LLRender::sGLCoreProfile)
- {
- // GLOD is incompatible with RenderGLCoreProfile, will crash on init
- LLNotificationsUtil::add("MeshUploadProfilerError");
- return false;
- }
-#endif
-
LLFloaterModelPreview* fmp = (LLFloaterModelPreview*)LLFloaterReg::getInstance("upload_model");
if (fmp && !fmp->isModelLoading())
{
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 06c8f66c1e..a0de3a2af1 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -5777,12 +5777,13 @@ LLCallingCardBridge::LLCallingCardBridge(LLInventoryPanel* inventory,
LLItemBridge(inventory, root, uuid)
{
mObserver = new LLCallingCardObserver(this);
- LLAvatarTracker::instance().addParticularFriendObserver(getItem()->getCreatorUUID(), mObserver);
+ mCreatorUUID = getItem()->getCreatorUUID();
+ LLAvatarTracker::instance().addParticularFriendObserver(mCreatorUUID, mObserver);
}
LLCallingCardBridge::~LLCallingCardBridge()
{
- LLAvatarTracker::instance().removeParticularFriendObserver(getItem()->getCreatorUUID(), mObserver);
+ LLAvatarTracker::instance().removeParticularFriendObserver(mCreatorUUID, mObserver);
delete mObserver;
}
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index c21bfbd02d..0b0ef273e1 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -457,6 +457,7 @@ public:
void checkSearchBySuffixChanges();
protected:
LLCallingCardObserver* mObserver;
+ LLUUID mCreatorUUID;
};
class LLNotecardBridge : public LLItemBridge
diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp
index c9bf0b0a12..d3eb2dd4d4 100644
--- a/indra/newview/llmodelpreview.cpp
+++ b/indra/newview/llmodelpreview.cpp
@@ -1235,6 +1235,11 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
size_vertices += face.mNumVertices;
}
+ if (size_indices < 3)
+ {
+ return -1;
+ }
+
// Allocate buffers, note that we are using U32 buffer instead of U16
U32* combined_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
U32* output_indices = (U32*)ll_aligned_malloc_32(size_indices * sizeof(U32));
@@ -1279,10 +1284,10 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
// Now that we have buffers, optimize
S32 target_indices = 0;
- F32 result_code = 0; // how far from original the model is, 1 == 100%
+ F32 result_error = 0; // how far from original the model is, 1 == 100%
S32 new_indices = 0;
- target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
+ target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle
new_indices = LLMeshOptimizer::simplifyU32(
output_indices,
combined_indices,
@@ -1293,17 +1298,27 @@ F32 LLModelPreview::genMeshOptimizerPerModel(LLModel *base_model, LLModel *targe
target_indices,
error_threshold,
sloppy,
- &result_code);
+ &result_error);
- if (result_code < 0)
+ if (result_error < 0)
{
- LL_WARNS() << "Negative result code from meshoptimizer for model " << target_model->mLabel
+ LL_WARNS() << "Negative result error from meshoptimizer for model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
<< " original count: " << size_indices << LL_ENDL;
}
+ if (new_indices < 3)
+ {
+ // Model should have at least one visible triangle
+ ll_aligned_free<64>(combined_positions);
+ ll_aligned_free_32(output_indices);
+ ll_aligned_free_32(combined_indices);
+
+ return -1;
+ }
+
// repack back into individual faces
LLVector4a* buffer_positions = (LLVector4a*)ll_aligned_malloc<64>(sizeof(LLVector4a) * 2 * size_vertices + tc_bytes_size);
@@ -1456,16 +1471,20 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
{
const LLVolumeFace &face = base_model->getVolumeFace(face_idx);
S32 size_indices = face.mNumIndices;
+ if (size_indices < 3)
+ {
+ return -1;
+ }
// todo: do not allocate per each face, add one large buffer somewhere
// faces have limited amount of indices
S32 size = (size_indices * sizeof(U16) + 0xF) & ~0xF;
U16* output = (U16*)ll_aligned_malloc_16(size);
S32 target_indices = 0;
- F32 result_code = 0; // how far from original the model is, 1 == 100%
+ F32 result_error = 0; // how far from original the model is, 1 == 100%
S32 new_indices = 0;
- target_indices = llmax(3, llfloor(size_indices / indices_decimator)); // leave at least one triangle
+ target_indices = llclamp(llfloor(size_indices / indices_decimator), 3, (S32)size_indices); // leave at least one triangle
new_indices = LLMeshOptimizer::simplify(
output,
face.mIndices,
@@ -1476,12 +1495,12 @@ F32 LLModelPreview::genMeshOptimizerPerFace(LLModel *base_model, LLModel *target
target_indices,
error_threshold,
sloppy,
- &result_code);
+ &result_error);
- if (result_code < 0)
+ if (result_error < 0)
{
- LL_WARNS() << "Negative result code from meshoptimizer for face " << face_idx
+ LL_WARNS() << "Negative result error from meshoptimizer for face " << face_idx
<< " of model " << target_model->mLabel
<< " target Indices: " << target_indices
<< " new Indices: " << new_indices
@@ -1693,21 +1712,21 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
// Run meshoptimizer for each face
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
{
- genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true);
+ if (genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, true) < 0)
+ {
+ // Sloppy failed and returned an invalid model
+ genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
+ }
}
-
- LL_INFOS() << "Model " << target_model->getName()
- << " lod " << which_lod
- << " simplified using per face method." << LL_ENDL;
}
if (model_meshopt_mode == MESH_OPTIMIZER_AUTO)
{
- // Switches between 'combine' method and 'per model sloppy' based on combine's result.
+ // Switches between 'combine' method and 'sloppy' based on combine's result.
F32 allowed_ratio_drift = 2.f;
- F32 res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
-
- if (res_ratio < 0)
+ F32 precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+
+ if (precise_ratio < 0)
{
// U16 vertices overflow, shouldn't happen, but just in case
for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
@@ -1715,42 +1734,101 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
genMeshOptimizerPerFace(base, target_model, face_idx, indices_decimator, lod_error_threshold, false);
}
}
- else if (res_ratio * allowed_ratio_drift < indices_decimator)
+ else if (precise_ratio * allowed_ratio_drift < indices_decimator)
{
// Try sloppy variant if normal one failed to simplify model enough.
- res_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+ // Sloppy variant can fail entirely and has issues with precision,
+ // so code needs to do multiple attempts with different decimators.
+ // Todo: this is a bit of a mess, needs to be refined and improved
+ F32 last_working_decimator = 0.f;
+ F32 last_working_ratio = F32_MAX;
+
+ F32 sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
+
+ if (sloppy_ratio > 0)
+ {
+ // Would be better to do a copy of target_model here, but if
+ // we need to use sloppy decimation, model should be cheap
+ // and fast to generate and it won't affect end result
+ last_working_decimator = indices_decimator;
+ last_working_ratio = sloppy_ratio;
+ }
// Sloppy has a tendecy to error into lower side, so a request for 100
// triangles turns into ~70, so check for significant difference from target decimation
F32 sloppy_ratio_drift = 1.4f;
if (lod_mode == LIMIT_TRIANGLES
- && (res_ratio > indices_decimator * sloppy_ratio_drift || res_ratio < 0))
+ && (sloppy_ratio > indices_decimator * sloppy_ratio_drift || sloppy_ratio < 0))
{
// Apply a correction to compensate.
// (indices_decimator / res_ratio) by itself is likely to overshoot to a differend
// side due to overal lack of precision, and we don't need an ideal result, which
// likely does not exist, just a better one, so a partial correction is enough.
- F32 sloppy_decimator = indices_decimator * (indices_decimator / res_ratio + 1) / 2;
- res_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+ F32 sloppy_decimator = indices_decimator * (indices_decimator / sloppy_ratio + 1) / 2;
+ sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+ }
+
+ if (last_working_decimator > 0 && sloppy_ratio < last_working_ratio)
+ {
+ // Compensation didn't work, return back to previous decimator
+ sloppy_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, true);
}
+ if (sloppy_ratio < 0)
+ {
+ // Sloppy method didn't work, try with smaller decimation values
+ S32 size_vertices = 0;
+
+ for (U32 face_idx = 0; face_idx < base->getNumVolumeFaces(); ++face_idx)
+ {
+ const LLVolumeFace &face = base->getVolumeFace(face_idx);
+ size_vertices += face.mNumVertices;
+ }
+
+ // Complex models aren't supposed to get here, they are supposed
+ // to work on a first try of sloppy due to having more viggle room.
+ // If they didn't, something is likely wrong, no point locking the
+ // thread in a long calculation that will fail.
+ const U32 too_many_vertices = 27000;
+ if (size_vertices > too_many_vertices)
+ {
+ LL_WARNS() << "Sloppy optimization method failed for a complex model " << target_model->getName() << LL_ENDL;
+ }
+ else
+ {
+ // Find a decimator that does work
+ F32 sloppy_decimation_step = sqrt((F32)decimation); // example: 27->15->9->5->3
+ F32 sloppy_decimator = indices_decimator / sloppy_decimation_step;
+
+ while (sloppy_ratio < 0
+ && sloppy_decimator > precise_ratio
+ && sloppy_decimator > 1)// precise_ratio isn't supposed to be below 1, but check just in case
+ {
+ sloppy_ratio = genMeshOptimizerPerModel(base, target_model, sloppy_decimator, lod_error_threshold, true);
+ sloppy_decimator = sloppy_decimator / sloppy_decimation_step;
+ }
+ }
+ }
- if (res_ratio < 0)
+ if (sloppy_ratio < 0 || sloppy_ratio < precise_ratio)
{
- // Sloppy variant failed to generate triangles.
+ // Sloppy variant failed to generate triangles or is worse.
// Can happen with models that are too simple as is.
- // Fallback to normal method or use lower decimator.
- genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
+ // Fallback to normal method
+
+ precise_ratio = genMeshOptimizerPerModel(base, target_model, indices_decimator, lod_error_threshold, false);
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
+ << " resulting ratio " << precise_ratio
<< " simplified using per model method." << LL_ENDL;
}
else
{
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
+ << " resulting ratio " << sloppy_ratio
<< " sloppily simplified using per model method." << LL_ENDL;
}
}
@@ -1758,6 +1836,7 @@ void LLModelPreview::genMeshOptimizerLODs(S32 which_lod, S32 meshopt_mode, U32 d
{
LL_INFOS() << "Model " << target_model->getName()
<< " lod " << which_lod
+ << " resulting ratio " << precise_ratio
<< " simplified using per model method." << LL_ENDL;
}
}
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 937f36b6fc..1240ce7c0f 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -147,6 +147,10 @@ void LLNetMap::setScale( F32 scale )
void LLNetMap::draw()
{
+ if (!LLWorld::instanceExists())
+ {
+ return;
+ }
LL_PROFILE_ZONE_SCOPED;
static LLFrameTimer map_timer;
static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index eaf6186dae..5c648c11e1 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -4022,6 +4022,7 @@ LLCullResult::LLCullResult()
{
mVisibleGroupsAllocated = 0;
mAlphaGroupsAllocated = 0;
+ mRiggedAlphaGroupsAllocated = 0;
mOcclusionGroupsAllocated = 0;
mDrawableGroupsAllocated = 0;
mVisibleListAllocated = 0;
@@ -4033,6 +4034,9 @@ LLCullResult::LLCullResult()
mAlphaGroups.clear();
mAlphaGroups.push_back(NULL);
mAlphaGroupsEnd = &mAlphaGroups[0];
+ mRiggedAlphaGroups.clear();
+ mRiggedAlphaGroups.push_back(NULL);
+ mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0];
mOcclusionGroups.clear();
mOcclusionGroups.push_back(NULL);
mOcclusionGroupsEnd = &mOcclusionGroups[0];
@@ -4073,6 +4077,9 @@ void LLCullResult::clear()
mAlphaGroupsSize = 0;
mAlphaGroupsEnd = &mAlphaGroups[0];
+ mRiggedAlphaGroupsSize = 0;
+ mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[0];
+
mOcclusionGroupsSize = 0;
mOcclusionGroupsEnd = &mOcclusionGroups[0];
@@ -4117,6 +4124,16 @@ LLCullResult::sg_iterator LLCullResult::endAlphaGroups()
return mAlphaGroupsEnd;
}
+LLCullResult::sg_iterator LLCullResult::beginRiggedAlphaGroups()
+{
+ return &mRiggedAlphaGroups[0];
+}
+
+LLCullResult::sg_iterator LLCullResult::endRiggedAlphaGroups()
+{
+ return mRiggedAlphaGroupsEnd;
+}
+
LLCullResult::sg_iterator LLCullResult::beginOcclusionGroups()
{
return &mOcclusionGroups[0];
@@ -4195,6 +4212,20 @@ void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
mAlphaGroupsEnd = &mAlphaGroups[mAlphaGroupsSize];
}
+void LLCullResult::pushRiggedAlphaGroup(LLSpatialGroup* group)
+{
+ if (mRiggedAlphaGroupsSize < mRiggedAlphaGroupsAllocated)
+ {
+ mRiggedAlphaGroups[mRiggedAlphaGroupsSize] = group;
+ }
+ else
+ {
+ pushBack(mRiggedAlphaGroups, mRiggedAlphaGroupsAllocated, group);
+ }
+ ++mRiggedAlphaGroupsSize;
+ mRiggedAlphaGroupsEnd = &mRiggedAlphaGroups[mRiggedAlphaGroupsSize];
+}
+
void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
{
if (mOcclusionGroupsSize < mOcclusionGroupsAllocated)
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index afe24d7d1f..acfcd63686 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -40,6 +40,8 @@
#include "llface.h"
#include "llviewercamera.h"
#include "llvector4a.h"
+#include "llvoavatar.h"
+
#include <queue>
#include <unordered_map>
@@ -125,7 +127,7 @@ public:
F32 mAlphaMaskCutoff;
U8 mDiffuseAlphaMode;
bool mSelected;
- LLVOAvatar* mAvatar = nullptr;
+ LLPointer<LLVOAvatar> mAvatar = nullptr;
LLMeshSkinInfo* mSkinInfo = nullptr;
@@ -470,6 +472,9 @@ public:
sg_iterator beginAlphaGroups();
sg_iterator endAlphaGroups();
+ sg_iterator beginRiggedAlphaGroups();
+ sg_iterator endRiggedAlphaGroups();
+
bool hasOcclusionGroups() { return mOcclusionGroupsSize > 0; }
sg_iterator beginOcclusionGroups();
sg_iterator endOcclusionGroups();
@@ -488,6 +493,7 @@ public:
void pushVisibleGroup(LLSpatialGroup* group);
void pushAlphaGroup(LLSpatialGroup* group);
+ void pushRiggedAlphaGroup(LLSpatialGroup* group);
void pushOcclusionGroup(LLSpatialGroup* group);
void pushDrawableGroup(LLSpatialGroup* group);
void pushDrawable(LLDrawable* drawable);
@@ -496,6 +502,7 @@ public:
U32 getVisibleGroupsSize() { return mVisibleGroupsSize; }
U32 getAlphaGroupsSize() { return mAlphaGroupsSize; }
+ U32 getRiggedAlphaGroupsSize() { return mRiggedAlphaGroupsSize; }
U32 getDrawableGroupsSize() { return mDrawableGroupsSize; }
U32 getVisibleListSize() { return mVisibleListSize; }
U32 getVisibleBridgeSize() { return mVisibleBridgeSize; }
@@ -509,6 +516,7 @@ private:
U32 mVisibleGroupsSize;
U32 mAlphaGroupsSize;
+ U32 mRiggedAlphaGroupsSize;
U32 mOcclusionGroupsSize;
U32 mDrawableGroupsSize;
U32 mVisibleListSize;
@@ -516,6 +524,7 @@ private:
U32 mVisibleGroupsAllocated;
U32 mAlphaGroupsAllocated;
+ U32 mRiggedAlphaGroupsAllocated;
U32 mOcclusionGroupsAllocated;
U32 mDrawableGroupsAllocated;
U32 mVisibleListAllocated;
@@ -527,6 +536,8 @@ private:
sg_iterator mVisibleGroupsEnd;
sg_list_t mAlphaGroups;
sg_iterator mAlphaGroupsEnd;
+ sg_list_t mRiggedAlphaGroups;
+ sg_iterator mRiggedAlphaGroupsEnd;
sg_list_t mOcclusionGroups;
sg_iterator mOcclusionGroupsEnd;
sg_list_t mDrawableGroups;
diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp
index b2e8348ffd..b5eb2880ae 100644
--- a/indra/newview/lltoolmorph.cpp
+++ b/indra/newview/lltoolmorph.cpp
@@ -239,17 +239,8 @@ BOOL LLVisualParamHint::render()
LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
- if (gAgentAvatarp->mDrawable.notNull() &&
- gAgentAvatarp->mDrawable->getFace(0))
- {
- LLDrawPoolAvatar *avatarPoolp = (LLDrawPoolAvatar *)gAgentAvatarp->mDrawable->getFace(0)->getPool();
- LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_REPLACE);
- avatarPoolp->renderAvatars(gAgentAvatarp); // renders only one avatar
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- gGL.flush();
- }
+ gPipeline.previewAvatar(gAgentAvatarp);
+
gAgentAvatarp->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
mWearablePtr->setVisualParamWeight(mVisualParam->getID(), mLastParamWeight);
LLViewerWearable* wearable = (LLViewerWearable*)mWearablePtr;
diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp
index 728d0c9417..ab4ad5817b 100644
--- a/indra/newview/lltracker.cpp
+++ b/indra/newview/lltracker.cpp
@@ -109,7 +109,16 @@ void LLTracker::stopTracking(bool clear_ui)
// static virtual
void LLTracker::drawHUDArrow()
{
- if (!gSavedSettings.getBOOL("RenderTrackerBeacon")) return;
+ if (!LLWorld::instanceExists())
+ {
+ return;
+ }
+
+ static LLCachedControl<bool> render_beacon(gSavedSettings, "RenderTrackerBeacon", true);
+ if (!render_beacon)
+ {
+ return;
+ }
if (gViewerWindow->getProgressView()->getVisible()) return;
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 4d86da5f78..40a7f0a941 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -266,9 +266,8 @@ static bool handleAnisotropicChanged(const LLSD& newvalue)
static bool handleVSyncChanged(const LLSD& newvalue)
{
-#if LL_WINDOWS
gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean());
-#endif
+
return true;
}
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index a26331251c..bc8171b2fc 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();
@@ -791,6 +788,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
LLViewerTexture::updateClass();
}
+ LLImageGLThread::updateClass();
+
{
LL_RECORD_BLOCK_TIME(FTM_IMAGE_UPDATE_BUMP);
gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first.
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 2bc0eeed92..27d8df28c3 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"
@@ -606,6 +607,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");
@@ -625,6 +627,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.
@@ -1561,6 +1570,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.
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -1647,11 +1658,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();
}
//////////////////////////////////////////////////////////////////////////////////////////
@@ -2060,6 +2073,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
@@ -2772,199 +2786,271 @@ 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
+ {
+#if LL_IMAGEGL_THREAD_CHECK
+ media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+ doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, true);
+ },
+ [=]() // callback to main thread
+ {
+#if LL_IMAGEGL_THREAD_CHECK
+ media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
+#endif
+ 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
+ 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, tex_name);
+
+ if (sync)
+ {
+ media_tex->getGLTexture()->syncToMainThread(tex_name);
+ }
+ else
+ {
+ media_tex->getGLTexture()->syncTexName(tex_name);
+ }
+
+ // 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/llvieweroctree.cpp b/indra/newview/llvieweroctree.cpp
index 3cdef0ebff..5eda75753e 100644
--- a/indra/newview/llvieweroctree.cpp
+++ b/indra/newview/llvieweroctree.cpp
@@ -787,42 +787,39 @@ void LLViewerOctreeGroup::checkStates()
//occulsion culling functions and classes
//-------------------------------------------------------------------------------------------
std::set<U32> LLOcclusionCullingGroup::sPendingQueries;
-class LLOcclusionQueryPool : public LLGLNamePool
-{
-public:
- LLOcclusionQueryPool()
- {
- }
-
-protected:
- virtual GLuint allocateName()
- {
- GLuint ret = 0;
+static std::queue<GLuint> sFreeQueries;
- glGenQueriesARB(1, &ret);
-
- return ret;
- }
+#define QUERY_POOL_SIZE 1024
- virtual void releaseName(GLuint name)
- {
-#if LL_TRACK_PENDING_OCCLUSION_QUERIES
- LLOcclusionCullingGroup::sPendingQueries.erase(name);
-#endif
- glDeleteQueriesARB(1, &name);
- }
-};
-
-static LLOcclusionQueryPool sQueryPool;
U32 LLOcclusionCullingGroup::getNewOcclusionQueryObjectName()
{
- return sQueryPool.allocate();
+ LL_PROFILE_ZONE_SCOPED;
+
+ if (sFreeQueries.empty())
+ {
+ //seed 1024 query names into the free query pool
+ GLuint queries[1024];
+ glGenQueriesARB(1024, queries);
+ for (int i = 0; i < 1024; ++i)
+ {
+ sFreeQueries.push(queries[i]);
+ }
+ }
+
+ // pull from pool
+ GLuint ret = sFreeQueries.front();
+ sFreeQueries.pop();
+ return ret;
}
void LLOcclusionCullingGroup::releaseOcclusionQueryObjectName(GLuint name)
{
- sQueryPool.release(name);
+ if (name != 0)
+ {
+ LL_PROFILE_ZONE_SCOPED;
+ sFreeQueries.push(name);
+ }
}
//=====================================
@@ -1243,7 +1240,14 @@ 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");
+
+ //get an occlusion query that hasn't been used in awhile
+ releaseOcclusionQueryObjectName(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ mOcclusionQuery[LLViewerCamera::sCurCameraID] = getNewOcclusionQueryObjectName();
+ glBeginQueryARB(mode, mOcclusionQuery[LLViewerCamera::sCurCameraID]);
+ }
LLGLSLShader* shader = LLGLSLShader::sCurBoundShaderPtr;
llassert(shader);
@@ -1282,7 +1286,10 @@ void LLOcclusionCullingGroup::doOcclusion(LLCamera* camera, const LLVector4a* sh
}
}
- glEndQueryARB(mode);
+ {
+ LL_PROFILE_ZONE_NAMED("glEndQuery");
+ glEndQueryARB(mode);
+ }
}
}
diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp
index 56370df751..e69b0347f8 100644
--- a/indra/newview/llviewerparcelmgr.cpp
+++ b/indra/newview/llviewerparcelmgr.cpp
@@ -878,7 +878,7 @@ LLParcel* LLViewerParcelMgr::getCollisionParcel() const
void LLViewerParcelMgr::render()
{
- if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection"))
+ if (mSelected && mRenderSelection && gSavedSettings.getBOOL("RenderParcelSelection") && !gDisconnected)
{
// Rendering is done in agent-coordinates, so need to supply
// an appropriate offset to the render code.
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 5fed46f437..e3ac56d0d3 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;
@@ -1629,7 +1619,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
mNeedsCreateTexture = TRUE;
if (preCreateTexture())
{
- ref();
#if LL_IMAGEGL_THREAD_CHECK
//grab a copy of the raw image data to make sure it isn't modified pending texture creation
U8* data = mRawImage->getData();
@@ -1645,6 +1634,7 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
auto mainq = LLImageGLThread::sEnabled ? mMainQueue.lock() : nullptr;
if (mainq)
{
+ ref();
mainq->postTo(
mImageQueue,
// work to be done on LLImageGL worker thread
@@ -1691,7 +1681,6 @@ void LLViewerFetchedTexture::scheduleCreateTexture()
else
{
gTextureList.mCreateTextureList.insert(this);
- unref();
}
}
}
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5487f0851e..a54c29a404 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -2024,12 +2024,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);
@@ -2417,7 +2417,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;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 548dadddb4..6a5cd6eabc 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -127,6 +127,9 @@ const F32 MIN_HOVER_Z = -2.0;
const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f;
const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f;
+// Unlike with 'self' avatar, server doesn't inform viewer about
+// expected attachments so viewer has to wait to see if anything
+// else will arrive
const F32 FIRST_APPEARANCE_CLOUD_MIN_DELAY = 3.f; // seconds
const F32 FIRST_APPEARANCE_CLOUD_MAX_DELAY = 45.f;
@@ -616,6 +619,7 @@ F32 LLVOAvatar::sUnbakedTime = 0.f;
F32 LLVOAvatar::sUnbakedUpdateTime = 0.f;
F32 LLVOAvatar::sGreyTime = 0.f;
F32 LLVOAvatar::sGreyUpdateTime = 0.f;
+LLPointer<LLViewerTexture> LLVOAvatar::sCloudTexture = NULL;
//-----------------------------------------------------------------------------
// Helper functions
@@ -746,7 +750,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
mCurrentGesticulationLevel = 0;
- mFirstSeenTimer.reset();
+ mFirstAppearanceMessageTimer.reset();
mRuthTimer.reset();
mRuthDebugTimer.reset();
mDebugExistenceTimer.reset();
@@ -1133,6 +1137,7 @@ void LLVOAvatar::initClass()
LLControlAvatar::sRegionChangedSlot = gAgent.addRegionChangedCallback(&LLControlAvatar::onRegionChanged);
+ sCloudTexture = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");
}
@@ -2826,7 +2831,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
//override rigged attachments' octree spatial extents with this avatar's bounding box
LLSpatialBridge* bridge = attached_object->mDrawable->getSpatialBridge();
bool rigged = false;
- if (bridge)
+ if (bridge && !bridge->isDead())
{
//transform avatar bounding box into attachment's coordinate frame
LLVector4a extents[2];
@@ -2843,13 +2848,21 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
attached_object->mDrawable->makeActive();
attached_object->mDrawable->updateXform(TRUE);
- if (!rigged)
+ if (bridge && !bridge->isDead())
{
- if (bridge)
+ if (!rigged)
{
gPipeline.updateMoveNormalAsync(bridge);
}
+ else
+ {
+ //specialized impl of updateMoveNormalAsync just for rigged attachment SpatialBridge
+ bridge->setState(LLDrawable::MOVE_UNDAMPED);
+ bridge->updateMove();
+ bridge->setState(LLDrawable::EARLY_MOVE);
+ }
}
+
attached_object->updateText();
}
}
@@ -3073,8 +3086,7 @@ void LLVOAvatar::idleUpdateLoadingEffect()
particle_parameters.mPartData.mStartColor = LLColor4(1, 1, 1, 0.5f);
particle_parameters.mPartData.mEndColor = LLColor4(1, 1, 1, 0.0f);
particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f;
- LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c");
- particle_parameters.mPartImageID = cloud->getID();
+ particle_parameters.mPartImageID = sCloudTexture->getID();
particle_parameters.mMaxAge = 0.f;
particle_parameters.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE;
particle_parameters.mInnerAngle = F_PI;
@@ -6428,6 +6440,16 @@ void LLVOAvatar::updateAttachmentOverrides()
#endif
}
+void LLVOAvatar::notifyAttachmentMeshLoaded()
+{
+ if (!isFullyLoaded())
+ {
+ // We just received mesh or skin info
+ // Reset timer to wait for more potential meshes or changes
+ mFullyLoadedTimer.reset();
+ }
+}
+
//-----------------------------------------------------------------------------
// addAttachmentOverridesForObject
//-----------------------------------------------------------------------------
@@ -8150,7 +8172,7 @@ BOOL LLVOAvatar::processFullyLoadedChange(bool loading)
// Note that textures can causes 60s delay on thier own
// so this delay might end up on top of textures' delay
mFirstUseDelaySeconds = llclamp(
- mFirstSeenTimer.getElapsedTimeF32(),
+ mFirstAppearanceMessageTimer.getElapsedTimeF32(),
FIRST_APPEARANCE_CLOUD_MIN_DELAY,
FIRST_APPEARANCE_CLOUD_MAX_DELAY);
@@ -8920,6 +8942,9 @@ void LLVOAvatar::onFirstTEMessageReceived()
mMeshTexturesDirty = TRUE;
gPipeline.markGLRebuild(this);
+
+ mFirstAppearanceMessageTimer.reset();
+ mFullyLoadedTimer.reset();
}
}
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 282d0f6cdd..acebbc1074 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -206,7 +206,7 @@ public:
inline LLJoint* getSkeletonJoint(S32 joint_num) { return mSkeleton[joint_num]; }
inline size_t getSkeletonJointCount() const { return mSkeleton.size(); }
-
+ void notifyAttachmentMeshLoaded();
void addAttachmentOverridesForObject(LLViewerObject *vo, std::set<LLUUID>* meshes_seen = NULL, bool recursive = true);
void removeAttachmentOverridesForObject(const LLUUID& mesh_id);
void removeAttachmentOverridesForObject(LLViewerObject *vo);
@@ -337,7 +337,8 @@ public:
static F32 sLODFactor; // user-settable LOD factor
static F32 sPhysicsLODFactor; // user-settable physics LOD factor
static BOOL sJointDebug; // output total number of joints being touched for each avatar
- static BOOL sDebugAvatarRotation;
+
+ static LLPointer<LLViewerTexture> sCloudTexture;
//--------------------------------------------------------------------
// Region state
@@ -380,7 +381,7 @@ protected:
private:
BOOL mFirstFullyVisible;
F32 mFirstUseDelaySeconds;
- LLFrameTimer mFirstSeenTimer;
+ LLFrameTimer mFirstAppearanceMessageTimer;
BOOL mFullyLoaded;
BOOL mPreviousFullyLoaded;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 4d72dc8776..1625dd5276 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -225,6 +225,7 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
mNumFaces = 0;
mLODChanged = FALSE;
mSculptChanged = FALSE;
+ mColorChanged = FALSE;
mSpotLightPriority = 0.f;
mMediaImplList.resize(getNumTEs());
@@ -1170,13 +1171,17 @@ void LLVOVolume::notifyMeshLoaded()
mSculptChanged = TRUE;
gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
- if (getAvatar() && !isAnimatedObject())
+ LLVOAvatar *av = getAvatar();
+ if (av && !isAnimatedObject())
{
- getAvatar()->addAttachmentOverridesForObject(this);
+ av->addAttachmentOverridesForObject(this);
+ av->notifyAttachmentMeshLoaded();
}
- if (getControlAvatar() && isAnimatedObject())
+ LLControlAvatar *cav = getControlAvatar();
+ if (cav && isAnimatedObject())
{
- getControlAvatar()->addAttachmentOverridesForObject(this);
+ cav->addAttachmentOverridesForObject(this);
+ cav->notifyAttachmentMeshLoaded();
}
updateVisualComplexity();
}
@@ -2027,7 +2032,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
was_regen_faces = lodOrSculptChanged(drawable, compiled);
drawable->setState(LLDrawable::REBUILD_VOLUME);
}
- else if (mSculptChanged || mLODChanged)
+ else if (mSculptChanged || mLODChanged || mColorChanged)
{
compiled = TRUE;
was_regen_faces = lodOrSculptChanged(drawable, compiled);
@@ -2039,7 +2044,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
genBBoxes(FALSE);
}
- else if (mLODChanged || mSculptChanged)
+ else if (mLODChanged || mSculptChanged || mColorChanged)
{
dirtySpatialGroup(drawable->isState(LLDrawable::IN_REBUILD_Q1));
compiled = TRUE;
@@ -2071,6 +2076,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
mLODChanged = FALSE;
mSculptChanged = FALSE;
mFaceMappingChanged = FALSE;
+ mColorChanged = FALSE;
return LLViewerObject::updateGeometry(drawable);
}
@@ -2209,6 +2215,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
if (mDrawable.notNull() && retval)
{
// These should only happen on updates which are not the initial update.
+ mColorChanged = TRUE;
mDrawable->setState(LLDrawable::REBUILD_COLOR);
dirtyMesh();
}
@@ -5139,7 +5146,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
bool rigged = facep->isState(LLFace::RIGGED);
- if (rigged && type != LLRenderPass::PASS_ALPHA)
+ if (rigged)
{
// hacky, should probably clean up -- if this face is rigged, put it in "type + 1"
// See LLRenderPass PASS_foo enum
@@ -5903,23 +5910,25 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
U32 geometryBytes = 0;
+ // generate render batches for static geometry
U32 extra_mask = LLVertexBuffer::MAP_TEXTURE_INDEX;
- geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[0], simple_count[0], FALSE, batch_textures);
- geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[0], fullbright_count[0], FALSE, batch_textures);
- geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[0], alpha_count[0], TRUE, batch_textures);
- geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[0], bump_count[0], FALSE, FALSE);
- geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[0], norm_count[0], FALSE, FALSE);
- geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[0], spec_count[0], FALSE, FALSE);
- geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[0], normspec_count[0], FALSE, FALSE);
-
- extra_mask |= LLVertexBuffer::MAP_WEIGHT4;
- geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[1], simple_count[1], FALSE, batch_textures, TRUE);
- geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[1], fullbright_count[1], FALSE, batch_textures, TRUE);
- geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[1], alpha_count[1], TRUE, batch_textures, TRUE);
- geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[1], bump_count[1], FALSE, TRUE);
- geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[1], norm_count[1], FALSE, TRUE);
- geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[1], spec_count[1], FALSE, TRUE);
- geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[1], normspec_count[1], FALSE, TRUE);
+ BOOL alpha_sort = TRUE;
+ BOOL rigged = FALSE;
+ for (int i = 0; i < 2; ++i) //two sets, static and rigged)
+ {
+ geometryBytes += genDrawInfo(group, simple_mask | extra_mask, sSimpleFaces[i], simple_count[i], FALSE, batch_textures, rigged);
+ geometryBytes += genDrawInfo(group, fullbright_mask | extra_mask, sFullbrightFaces[i], fullbright_count[i], FALSE, batch_textures, rigged);
+ geometryBytes += genDrawInfo(group, alpha_mask | extra_mask, sAlphaFaces[i], alpha_count[i], alpha_sort, batch_textures, rigged);
+ geometryBytes += genDrawInfo(group, bump_mask | extra_mask, sBumpFaces[i], bump_count[i], FALSE, FALSE, rigged);
+ geometryBytes += genDrawInfo(group, norm_mask | extra_mask, sNormFaces[i], norm_count[i], FALSE, FALSE, rigged);
+ geometryBytes += genDrawInfo(group, spec_mask | extra_mask, sSpecFaces[i], spec_count[i], FALSE, FALSE, rigged);
+ geometryBytes += genDrawInfo(group, normspec_mask | extra_mask, sNormSpecFaces[i], normspec_count[i], FALSE, FALSE, rigged);
+
+ // for rigged set, add weights and disable alpha sorting (rigged items use depth buffer)
+ extra_mask |= LLVertexBuffer::MAP_WEIGHT4;
+ alpha_sort = FALSE;
+ rigged = TRUE;
+ }
group->mGeometryBytes = geometryBytes;
@@ -5972,8 +5981,9 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
if (drawablep && !drawablep->isDead() && drawablep->isState(LLDrawable::REBUILD_ALL) && !drawablep->isState(LLDrawable::RIGGED) )
{
LLVOVolume* vobj = drawablep->getVOVolume();
- if (!vobj) continue;
-
+
+ if (!vobj) continue;
+
if (debugLoggingEnabled("AnimatedObjectsLinkset"))
{
if (vobj->isAnimatedObject() && vobj->isRiggedMesh())
@@ -5993,7 +6003,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
}
LLVolume* volume = vobj->getVolume();
- if (!volume) continue;
+ if (!volume) continue;
for (S32 i = 0; i < drawablep->getNumFaces(); ++i)
{
LLFace* face = drawablep->getFace(i);
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index d158044f5d..4cb7a5481c 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -413,6 +413,7 @@ private:
S32 mLOD;
BOOL mLODChanged;
BOOL mSculptChanged;
+ BOOL mColorChanged;
F32 mSpotLightPriority;
LLMatrix4 mRelativeXform;
LLMatrix3 mRelativeXformInvTrans;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index a6fa58f476..a3c971153c 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -3828,6 +3828,16 @@ void LLPipeline::postSort(LLCamera& camera)
sCull->pushAlphaGroup(group);
}
}
+
+ LLSpatialGroup::draw_map_t::iterator rigged_alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA_RIGGED);
+
+ if (rigged_alpha != group->mDrawMap.end())
+ { //store rigged alpha groups for LLDrawPoolAlpha prepass (skip distance update, rigged attachments use depth buffer)
+ if (hasRenderType(LLDrawPool::POOL_ALPHA))
+ {
+ sCull->pushRiggedAlphaGroup(group);
+ }
+ }
}
}
@@ -7264,11 +7274,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;
@@ -9332,7 +9337,11 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
LLColor3 col = LLEnvironment::instance().getCurrentWater()->getWaterFogColor();
glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+ // HACK FIX -- pretend underwater camera is the world camera to fix weird visibility artifacts
+ // during distortion render (doesn't break main render because the camera is the same perspective
+ // as world camera and occlusion culling is disabled for this pass)
+ //LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
mWaterDis.bindTarget();
mWaterDis.getViewport(gGLViewport);
@@ -11125,6 +11134,167 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
LLGLState::checkTextureChannels();
}
+static LLTrace::BlockTimerStatHandle FTM_PREVIEW_AVATAR("Preview Avatar");
+
+void LLPipeline::previewAvatar(LLVOAvatar* avatar)
+{
+ LL_RECORD_BLOCK_TIME(FTM_PREVIEW_AVATAR);
+
+ LLGLDepthTest gls_depth(GL_TRUE, GL_TRUE);
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_REPLACE);
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ static LLCullResult result;
+ result.clear();
+ grabReferences(result);
+
+ if (!avatar || !avatar->mDrawable)
+ {
+ LL_WARNS_ONCE("AvatarRenderPipeline") << "Avatar is " << (avatar ? "not drawable" : "null") << LL_ENDL;
+ return;
+ }
+ LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " is drawable" << LL_ENDL;
+
+ assertInitialized();
+
+ pushRenderTypeMask();
+
+ {
+ //hide world geometry
+ clearRenderTypeMask(
+ RENDER_TYPE_SKY,
+ RENDER_TYPE_WL_SKY,
+ RENDER_TYPE_GROUND,
+ RENDER_TYPE_TERRAIN,
+ RENDER_TYPE_GRASS,
+ RENDER_TYPE_CONTROL_AV, // Animesh
+ RENDER_TYPE_TREE,
+ RENDER_TYPE_VOIDWATER,
+ RENDER_TYPE_WATER,
+ RENDER_TYPE_PASS_GRASS,
+ RENDER_TYPE_HUD,
+ RENDER_TYPE_PARTICLES,
+ RENDER_TYPE_CLOUDS,
+ RENDER_TYPE_HUD_PARTICLES,
+ END_RENDER_TYPES
+ );
+ }
+
+ S32 occlusion = sUseOcclusion;
+ sUseOcclusion = 0;
+
+ sReflectionRender = !sRenderDeferred;
+
+ sShadowRender = true;
+ sImpostorRender = true; // Likely not needed for previews
+
+ LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
+
+ {
+ markVisible(avatar->mDrawable, *viewer_camera);
+
+ LLVOAvatar::attachment_map_t::iterator iter;
+ for (iter = avatar->mAttachmentPoints.begin();
+ iter != avatar->mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment *attachment = iter->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ if (LLViewerObject* attached_object = attachment_iter->get())
+ {
+ markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+ }
+ }
+ }
+ }
+
+ stateSort(*LLViewerCamera::getInstance(), result);
+
+ LLCamera camera = *viewer_camera;
+
+ F32 old_alpha = LLDrawPoolAvatar::sMinimumAlpha;
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ renderGeomDeferred(camera);
+
+ renderGeomPostDeferred(camera);
+ }
+ else
+ {
+ renderGeom(camera);
+ }
+
+ LLDrawPoolAvatar::sMinimumAlpha = old_alpha;
+
+ { //create alpha mask based on depth buffer
+ if (LLPipeline::sRenderDeferred)
+ {
+ GLuint buff = GL_COLOR_ATTACHMENT0;
+ LL_PROFILER_GPU_ZONEC("gl.DrawBuffersARB", 0x8000FF);
+ glDrawBuffersARB(1, &buff);
+ }
+
+ LLGLDisable blend(GL_BLEND);
+
+ gGL.setColorMask(false, true);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER);
+
+ gGL.flush();
+
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.pushMatrix();
+ gGL.loadIdentity();
+
+ static const F32 clip_plane = 0.99999f;
+
+ gDebugProgram.bind();
+
+ gGL.begin(LLRender::QUADS);
+ gGL.vertex3f(-1, -1, clip_plane);
+ gGL.vertex3f(1, -1, clip_plane);
+ gGL.vertex3f(1, 1, clip_plane);
+ gGL.vertex3f(-1, 1, clip_plane);
+ gGL.end();
+ gGL.flush();
+
+ gDebugProgram.unbind();
+
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+ }
+
+ sUseOcclusion = occlusion;
+ sReflectionRender = false;
+ sImpostorRender = false;
+ sShadowRender = false;
+ popRenderTypeMask();
+
+ gGL.matrixMode(LLRender::MM_PROJECTION);
+ gGL.popMatrix();
+ gGL.matrixMode(LLRender::MM_MODELVIEW);
+ gGL.popMatrix();
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ gGL.flush();
+}
+
bool LLPipeline::hasRenderBatches(const U32 type) const
{
return sCull->getRenderMapSize(type) > 0;
@@ -11150,6 +11320,16 @@ LLCullResult::sg_iterator LLPipeline::endAlphaGroups()
return sCull->endAlphaGroups();
}
+LLCullResult::sg_iterator LLPipeline::beginRiggedAlphaGroups()
+{
+ return sCull->beginRiggedAlphaGroups();
+}
+
+LLCullResult::sg_iterator LLPipeline::endRiggedAlphaGroups()
+{
+ return sCull->endRiggedAlphaGroups();
+}
+
bool LLPipeline::hasRenderType(const U32 type) const
{
// STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index b86b68b09d..4946bac701 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -135,6 +135,7 @@ public:
void resetVertexBuffers(LLDrawable* drawable);
void generateImpostor(LLVOAvatar* avatar);
+ void previewAvatar(LLVOAvatar* avatar);
void bindScreenToTexture();
void renderFinalize();
@@ -338,6 +339,8 @@ public:
LLCullResult::drawinfo_iterator endRenderMap(U32 type);
LLCullResult::sg_iterator beginAlphaGroups();
LLCullResult::sg_iterator endAlphaGroups();
+ LLCullResult::sg_iterator beginRiggedAlphaGroups();
+ LLCullResult::sg_iterator endRiggedAlphaGroups();
void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES);
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 7be0e0ad85..98f74d321b 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -8821,13 +8821,6 @@ See SecondLife.log for details
type="alert">
Error while requesting mesh upload permissons.
</notification>
-
- <notification
- name="MeshUploadProfilerError"
- icon="alert.tga"
- type="alert">
-Mesh uploader is incompatible with RenderGLCoreProfile, please turn RenderGLCoreProfile off in debug settings and restart the viewer.
- </notification>
<notification
name="RegionCapabilityRequestError"