summaryrefslogtreecommitdiff
path: root/indra/llrender/llrender.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llrender/llrender.cpp')
-rw-r--r--indra/llrender/llrender.cpp331
1 files changed, 198 insertions, 133 deletions
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index 72cca1f2a2..8430d13093 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -35,6 +35,7 @@
#include "llrendertarget.h"
#include "lltexture.h"
#include "llshadermgr.h"
+#include "hbxxh.h"
#if LL_WINDOWS
extern void APIENTRY gl_debug_callback(GLenum source,
@@ -54,8 +55,14 @@ F32 gGLModelView[16];
F32 gGLLastModelView[16];
F32 gGLLastProjection[16];
F32 gGLProjection[16];
+
+// transform from last frame's camera space to this frame's camera space (and inverse)
+F32 gGLDeltaModelView[16];
+F32 gGLInverseDeltaModelView[16];
+
S32 gGLViewport[4];
+
U32 LLRender::sUICalls = 0;
U32 LLRender::sUIVerts = 0;
U32 LLTexUnit::sWhiteTexture = 0;
@@ -63,14 +70,20 @@ bool LLRender::sGLCoreProfile = false;
bool LLRender::sNsightDebugSupport = false;
LLVector2 LLRender::sUIGLScaleFactor = LLVector2(1.f, 1.f);
-static const U32 LL_NUM_TEXTURE_LAYERS = 32;
-static const U32 LL_NUM_LIGHT_UNITS = 8;
+struct LLVBCache
+{
+ LLPointer<LLVertexBuffer> vb;
+ std::chrono::steady_clock::time_point touched;
+};
+
+static std::unordered_map<U64, LLVBCache> sVBCache;
static const GLenum sGLTextureType[] =
{
GL_TEXTURE_2D,
- GL_TEXTURE_RECTANGLE_ARB,
- GL_TEXTURE_CUBE_MAP_ARB,
+ GL_TEXTURE_RECTANGLE,
+ GL_TEXTURE_CUBE_MAP,
+ GL_TEXTURE_CUBE_MAP_ARRAY,
GL_TEXTURE_2D_MULTISAMPLE,
GL_TEXTURE_3D
};
@@ -122,7 +135,7 @@ void LLTexUnit::refreshState(void)
gGL.flush();
- glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
+ glActiveTexture(GL_TEXTURE0 + mIndex);
if (mCurrTexType != TT_NONE)
{
@@ -143,7 +156,7 @@ void LLTexUnit::activate(void)
if ((S32)gGL.mCurrTextureUnitIndex != mIndex || gGL.mDirty)
{
gGL.flush();
- glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
+ glActiveTexture(GL_TEXTURE0 + mIndex);
gGL.mCurrTextureUnitIndex = mIndex;
}
}
@@ -154,13 +167,10 @@ void LLTexUnit::enable(eTextureType type)
if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) )
{
- stop_glerror();
activate();
- stop_glerror();
if (mCurrTexType != TT_NONE && !gGL.mDirty)
{
disable(); // Force a disable of a previous texture type if it's enabled.
- stop_glerror();
}
mCurrTexType = type;
@@ -174,11 +184,7 @@ void LLTexUnit::disable(void)
if (mCurrTexType != TT_NONE)
{
- activate();
unbind(mCurrTexType);
- gGL.flush();
- setTextureColorSpace(TCS_LINEAR);
-
mCurrTexType = TT_NONE;
}
}
@@ -186,8 +192,8 @@ void LLTexUnit::disable(void)
void LLTexUnit::bindFast(LLTexture* texture)
{
LLImageGL* gl_tex = texture->getGLTexture();
-
- glActiveTextureARB(GL_TEXTURE0_ARB + mIndex);
+ texture->setActive();
+ glActiveTexture(GL_TEXTURE0 + mIndex);
gGL.mCurrTextureUnitIndex = mIndex;
mCurrTexture = gl_tex->getTexName();
if (!mCurrTexture)
@@ -223,7 +229,7 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
enable(gl_tex->getTarget());
mCurrTexture = gl_tex->getTexName();
glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture);
- if(gl_tex->updateBindStats(gl_tex->mTextureMemory))
+ if(gl_tex->updateBindStats())
{
texture->setActive() ;
texture->updateBindStatsForTester() ;
@@ -302,7 +308,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32
mCurrTexture = texname;
glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture);
stop_glerror();
- texture->updateBindStats(texture->mTextureMemory);
+ texture->updateBindStats();
mHasMipMaps = texture->mHasMipMaps;
if (texture->mTexOptionsDirty)
{
@@ -334,14 +340,14 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap)
if (mCurrTexture != cubeMap->mImages[0]->getTexName())
{
- if (gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps)
+ if (LLCubeMap::sUseCubeMaps)
{
activate();
enable(LLTexUnit::TT_CUBE_MAP);
mCurrTexture = cubeMap->mImages[0]->getTexName();
- glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mCurrTexture);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, mCurrTexture);
mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps;
- cubeMap->mImages[0]->updateBindStats(cubeMap->mImages[0]->mTextureMemory);
+ cubeMap->mImages[0]->updateBindStats();
if (cubeMap->mImages[0]->mTexOptionsDirty)
{
cubeMap->mImages[0]->mTexOptionsDirty = false;
@@ -369,10 +375,7 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth)
if (bindDepth)
{
- if (renderTarget->hasStencil())
- {
- LL_ERRS() << "Cannot bind a render buffer for sampling. Allocate render target without a stencil buffer if sampling of depth buffer is required." << LL_ENDL;
- }
+ llassert(renderTarget->getDepth()); // target MUST have a depth buffer attachment
bindManual(renderTarget->getUsage(), renderTarget->getDepth());
}
@@ -469,7 +472,7 @@ void LLTexUnit::setTextureAddressMode(eTextureAddressMode mode)
glTexParameteri (sGLTextureType[mCurrTexType], GL_TEXTURE_WRAP_T, sGLAddressMode[mode]);
if (mCurrTexType == TT_CUBE_MAP)
{
- glTexParameteri (GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]);
+ glTexParameteri (GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, sGLAddressMode[mode]);
}
}
@@ -515,22 +518,15 @@ void LLTexUnit::setTextureFilteringOption(LLTexUnit::eTextureFilterOptions optio
}
}
- if (gGLManager.mHasAnisotropic)
+ if (gGLManager.mGLVersion >= 4.59f)
{
if (LLImageGL::sGlobalUseAnisotropic && option == TFO_ANISOTROPIC)
{
- if (gGL.mMaxAnisotropy < 1.f)
- {
- glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gGL.mMaxAnisotropy);
-
- LL_INFOS() << "gGL.mMaxAnisotropy: " << gGL.mMaxAnisotropy << LL_ENDL ;
- gGL.mMaxAnisotropy = llmax(1.f, gGL.mMaxAnisotropy) ;
- }
- glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, gGL.mMaxAnisotropy);
+ glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY, gGLManager.mMaxAnisotropy);
}
else
{
- glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
+ glTexParameterf(sGLTextureType[mCurrTexType], GL_TEXTURE_MAX_ANISOTROPY, 1.f);
}
}
}
@@ -544,7 +540,7 @@ GLint LLTexUnit::getTextureSource(eTextureBlendSrc src)
case TBS_PREV_ALPHA:
case TBS_ONE_MINUS_PREV_COLOR:
case TBS_ONE_MINUS_PREV_ALPHA:
- return GL_PREVIOUS_ARB;
+ return GL_PREVIOUS;
// All four cases should return the same value.
case TBS_TEX_COLOR:
@@ -558,18 +554,18 @@ GLint LLTexUnit::getTextureSource(eTextureBlendSrc src)
case TBS_VERT_ALPHA:
case TBS_ONE_MINUS_VERT_COLOR:
case TBS_ONE_MINUS_VERT_ALPHA:
- return GL_PRIMARY_COLOR_ARB;
+ return GL_PRIMARY_COLOR;
// All four cases should return the same value.
case TBS_CONST_COLOR:
case TBS_CONST_ALPHA:
case TBS_ONE_MINUS_CONST_COLOR:
case TBS_ONE_MINUS_CONST_ALPHA:
- return GL_CONSTANT_ARB;
+ return GL_CONSTANT;
default:
LL_WARNS() << "Unknown eTextureBlendSrc: " << src << ". Using Vertex Color instead." << LL_ENDL;
- return GL_PRIMARY_COLOR_ARB;
+ return GL_PRIMARY_COLOR;
}
}
@@ -638,10 +634,10 @@ void LLTexUnit::debugTextureUnit(void)
if (mIndex < 0) return;
GLint activeTexture;
- glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture);
- if ((GL_TEXTURE0_ARB + mIndex) != activeTexture)
+ glGetIntegerv(GL_ACTIVE_TEXTURE, &activeTexture);
+ if ((GL_TEXTURE0 + mIndex) != activeTexture)
{
- U32 set_unit = (activeTexture - GL_TEXTURE0_ARB);
+ U32 set_unit = (activeTexture - GL_TEXTURE0);
LL_WARNS() << "Incorrect Texture Unit! Expected: " << set_unit << " Actual: " << mIndex << LL_ENDL;
}
}
@@ -649,29 +645,6 @@ void LLTexUnit::debugTextureUnit(void)
void LLTexUnit::setTextureColorSpace(eTextureColorSpace space)
{
mTexColorSpace = space;
-
-#if USE_SRGB_DECODE
- if (gGLManager.mHasTexturesRGBDecode)
- {
- if (space == TCS_SRGB)
- {
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_SRGB_DECODE_EXT, GL_DECODE_EXT);
- }
- else
- {
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
- }
-
- if (gDebugGL)
- {
- assert_glerror();
- }
- }
- else
- {
- glTexParameteri(sGLTextureType[mCurrTexType], GL_TEXTURE_SRGB_DECODE_EXT, GL_SKIP_DECODE_EXT);
- }
-#endif
}
LLLightState::LLLightState(S32 index)
@@ -734,6 +707,24 @@ void LLLightState::setSunPrimary(bool v)
}
}
+void LLLightState::setSize(F32 v)
+{
+ if (mSize != v)
+ {
+ ++gGL.mLightHash;
+ mSize = v;
+ }
+}
+
+void LLLightState::setFalloff(F32 v)
+{
+ if (mFalloff != v)
+ {
+ ++gGL.mLightHash;
+ mFalloff = v;
+ }
+}
+
void LLLightState::setAmbient(const LLColor4& ambient)
{
if (mAmbient != ambient)
@@ -827,19 +818,16 @@ LLRender::LLRender()
mCount(0),
mQuadCycle(0),
mMode(LLRender::TRIANGLES),
- mCurrTextureUnitIndex(0),
- mMaxAnisotropy(0.f)
+ mCurrTextureUnitIndex(0)
{
- mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS);
for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++)
{
- mTexUnits.push_back(new LLTexUnit(i));
+ mTexUnits[i].mIndex = i;
}
- mDummyTexUnit = new LLTexUnit(-1);
for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; ++i)
{
- mLightState.push_back(new LLLightState(i));
+ mLightState[i].mIndex = i;
}
for (U32 i = 0; i < 4; i++)
@@ -874,9 +862,9 @@ void LLRender::init(bool needs_vertex_buffer)
#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);
+ //glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW_ARB, 0, NULL, GL_TRUE);
+ glDebugMessageCallback((GLDEBUGPROC) gl_debug_callback, NULL);
+ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
#endif
@@ -888,14 +876,14 @@ void LLRender::init(bool needs_vertex_buffer)
glCullFace(GL_BACK);
- if (sGLCoreProfile && !LLVertexBuffer::sUseVAO)
- { //bind a dummy vertex array object so we're core profile compliant
-#ifdef GL_ARB_vertex_array_object
- U32 ret;
- glGenVertexArrays(1, &ret);
- glBindVertexArray(ret);
-#endif
- }
+ // necessary for reflection maps
+ glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
+ { //bind a dummy vertex array object so we're core profile compliant
+ U32 ret;
+ glGenVertexArrays(1, &ret);
+ glBindVertexArray(ret);
+ }
if (needs_vertex_buffer)
{
@@ -907,8 +895,8 @@ void LLRender::initVertexBuffer()
{
llassert_always(mBuffer.isNull());
stop_glerror();
- mBuffer = new LLVertexBuffer(immediate_mask, 0);
- mBuffer->allocateBuffer(4096, 0, TRUE);
+ mBuffer = new LLVertexBuffer(immediate_mask);
+ mBuffer->allocateBuffer(4096, 0);
mBuffer->getVertexStrider(mVerticesp);
mBuffer->getTexCoord0Strider(mTexcoordsp);
mBuffer->getColorStrider(mColorsp);
@@ -922,19 +910,6 @@ void LLRender::resetVertexBuffer()
void LLRender::shutdown()
{
- for (U32 i = 0; i < mTexUnits.size(); i++)
- {
- delete mTexUnits[i];
- }
- mTexUnits.clear();
- delete mDummyTexUnit;
- mDummyTexUnit = NULL;
-
- for (U32 i = 0; i < mLightState.size(); ++i)
- {
- delete mLightState[i];
- }
- mLightState.clear();
resetVertexBuffer();
}
@@ -946,10 +921,10 @@ void LLRender::refreshState(void)
for (U32 i = 0; i < mTexUnits.size(); i++)
{
- mTexUnits[i]->refreshState();
+ mTexUnits[i].refreshState();
}
- mTexUnits[active_unit]->activate();
+ mTexUnits[active_unit].activate();
setColorMask(mCurrColorMask[0], mCurrColorMask[1], mCurrColorMask[2], mCurrColorMask[3]);
@@ -977,10 +952,11 @@ void LLRender::syncLightState()
LLVector3 diffuse[LL_NUM_LIGHT_UNITS];
LLVector3 diffuse_b[LL_NUM_LIGHT_UNITS];
bool sun_primary[LL_NUM_LIGHT_UNITS];
+ LLVector2 size[LL_NUM_LIGHT_UNITS];
for (U32 i = 0; i < LL_NUM_LIGHT_UNITS; i++)
{
- LLLightState *light = mLightState[i];
+ LLLightState *light = &mLightState[i];
position[i] = light->mPosition;
direction[i] = light->mSpotDirection;
@@ -988,17 +964,19 @@ void LLRender::syncLightState()
diffuse[i].set(light->mDiffuse.mV);
diffuse_b[i].set(light->mDiffuseB.mV);
sun_primary[i] = light->mSunIsPrimary;
+ size[i].set(light->mSize, light->mFalloff);
}
shader->uniform4fv(LLShaderMgr::LIGHT_POSITION, LL_NUM_LIGHT_UNITS, position[0].mV);
shader->uniform3fv(LLShaderMgr::LIGHT_DIRECTION, LL_NUM_LIGHT_UNITS, direction[0].mV);
shader->uniform4fv(LLShaderMgr::LIGHT_ATTENUATION, LL_NUM_LIGHT_UNITS, attenuation[0].mV);
+ shader->uniform2fv(LLShaderMgr::LIGHT_DEFERRED_ATTENUATION, LL_NUM_LIGHT_UNITS, size[0].mV);
shader->uniform3fv(LLShaderMgr::LIGHT_DIFFUSE, LL_NUM_LIGHT_UNITS, diffuse[0].mV);
- shader->uniform4fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV);
+ shader->uniform3fv(LLShaderMgr::LIGHT_AMBIENT, 1, mAmbientLightColor.mV);
shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_primary[0] ? 1 : 0);
- shader->uniform4fv(LLShaderMgr::AMBIENT, 1, mAmbientLightColor.mV);
- shader->uniform4fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
- shader->uniform4fv(LLShaderMgr::MOONLIGHT_COLOR, 1, diffuse_b[0].mV);
+ //shader->uniform3fv(LLShaderMgr::AMBIENT, 1, mAmbientLightColor.mV);
+ shader->uniform3fv(LLShaderMgr::SUNLIGHT_COLOR, 1, diffuse[0].mV);
+ shader->uniform3fv(LLShaderMgr::MOONLIGHT_COLOR, 1, diffuse_b[0].mV);
}
}
@@ -1095,13 +1073,20 @@ void LLRender::syncMatrices()
{ //update projection matrix, normal, and MVP
glh::matrix4f& mat = mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]];
- // it would be nice to have this automatically track the state of the proj matrix
- // but certain render paths (deferred lighting) require it to be mismatched *sigh*
- //if (shader->getUniformLocation(LLShaderMgr::INVERSE_PROJECTION_MATRIX))
- //{
- // glh::matrix4f inv_proj = mat.inverse();
- // shader->uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m);
- //}
+ // GZ: This was previously disabled seemingly due to a bug involving the deferred renderer's regular pushing and popping of mats.
+ // We're reenabling this and cleaning up the code around that - that would've been the appropriate course initially.
+ // Anything beyond the standard proj and inv proj mats are special cases. Please setup special uniforms accordingly in the future.
+ if (shader->getUniformLocation(LLShaderMgr::INVERSE_PROJECTION_MATRIX))
+ {
+ glh::matrix4f inv_proj = mat.inverse();
+ shader->uniformMatrix4fv(LLShaderMgr::INVERSE_PROJECTION_MATRIX, 1, FALSE, inv_proj.m);
+ }
+
+ // Used by some full screen effects - such as full screen lights, glow, etc.
+ if (shader->getUniformLocation(LLShaderMgr::IDENTITY_MATRIX))
+ {
+ shader->uniformMatrix4fv(LLShaderMgr::IDENTITY_MATRIX, 1, GL_FALSE, glh::matrix4f::identity().m);
+ }
shader->uniformMatrix4fv(name[MM_PROJECTION], 1, GL_FALSE, mat.m);
shader->mMatHash[MM_PROJECTION] = mMatHash[MM_PROJECTION];
@@ -1479,12 +1464,7 @@ void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
llassert(color_dfactor < BF_UNDEF);
llassert(alpha_sfactor < BF_UNDEF);
llassert(alpha_dfactor < BF_UNDEF);
- if (!gGLManager.mHasBlendFuncSeparate)
- {
- LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << LL_ENDL;
- blendFunc(color_sfactor, color_dfactor);
- return;
- }
+
if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor ||
mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor)
{
@@ -1493,8 +1473,9 @@ void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
mCurrBlendColorDFactor = color_dfactor;
mCurrBlendAlphaDFactor = alpha_dfactor;
flush();
- glBlendFuncSeparateEXT(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor],
- sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]);
+
+ glBlendFuncSeparate(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor],
+ sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]);
}
}
@@ -1502,12 +1483,12 @@ LLTexUnit* LLRender::getTexUnit(U32 index)
{
if (index < mTexUnits.size())
{
- return mTexUnits[index];
+ return &mTexUnits[index];
}
else
{
LL_DEBUGS() << "Non-existing texture unit layer requested: " << index << LL_ENDL;
- return mDummyTexUnit;
+ return &mDummyTexUnit;
}
}
@@ -1515,7 +1496,7 @@ LLLightState* LLRender::getLight(U32 index)
{
if (index < mLightState.size())
{
- return mLightState[index];
+ return &mLightState[index];
}
return NULL;
@@ -1599,6 +1580,7 @@ void LLRender::flush()
if (mCount > 0)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE;
+ llassert(LLGLSLShader::sCurBoundShaderPtr != nullptr);
if (!mUIOffset.empty())
{
sUICalls++;
@@ -1639,24 +1621,108 @@ void LLRender::flush()
if (mBuffer)
{
- if (mBuffer->useVBOs() && !mBuffer->isLocked())
- { //hack to only flush the part of the buffer that was updated (relies on stream draw using buffersubdata)
- mBuffer->getVertexStrider(mVerticesp, 0, count);
- mBuffer->getTexCoord0Strider(mTexcoordsp, 0, count);
- mBuffer->getColorStrider(mColorsp, 0, count);
+
+ HBXXH64 hash;
+ U32 attribute_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask;
+
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hash");
+
+ hash.update((U8*)mVerticesp.get(), count * sizeof(LLVector4a));
+ if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
+ {
+ hash.update((U8*)mTexcoordsp.get(), count * sizeof(LLVector2));
+ }
+
+ if (attribute_mask & LLVertexBuffer::MAP_COLOR)
+ {
+ hash.update((U8*)mColorsp.get(), count * sizeof(LLColor4U));
+ }
+
+ hash.finalize();
+ }
+
+
+ U64 vhash = hash.digest();
+
+ // check the VB cache before making a new vertex buffer
+ // This is a giant hack to deal with (mostly) our terrible UI rendering code
+ // that was built on top of OpenGL immediate mode. Huge performance wins
+ // can be had by not uploading geometry to VRAM unless absolutely necessary.
+ // Most of our usage of the "immediate mode" style draw calls is actually
+ // sending the same geometry over and over again.
+ // To leverage this, we maintain a running hash of the vertex stream being
+ // built up before a flush, and then check that hash against a VB
+ // cache just before creating a vertex buffer in VRAM
+ std::unordered_map<U64, LLVBCache>::iterator cache = sVBCache.find(vhash);
+
+ LLPointer<LLVertexBuffer> vb;
+
+ if (cache != sVBCache.end())
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hit");
+ // cache hit, just use the cached buffer
+ vb = cache->second.vb;
+ cache->second.touched = std::chrono::steady_clock::now();
+ }
+ else
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache miss");
+ vb = new LLVertexBuffer(attribute_mask);
+ vb->allocateBuffer(count, 0);
+
+ vb->setBuffer();
+
+ vb->setPositionData((LLVector4a*) mVerticesp.get());
+
+ if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0)
+ {
+ vb->setTexCoordData(mTexcoordsp.get());
+ }
+
+ if (attribute_mask & LLVertexBuffer::MAP_COLOR)
+ {
+ vb->setColorData(mColorsp.get());
+ }
+
+ vb->unbind();
+
+ sVBCache[vhash] = { vb , std::chrono::steady_clock::now() };
+
+ static U32 miss_count = 0;
+ miss_count++;
+ if (miss_count > 1024)
+ {
+ LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache clean");
+ miss_count = 0;
+ auto now = std::chrono::steady_clock::now();
+
+ using namespace std::chrono_literals;
+ // every 1024 misses, clean the cache of any VBs that haven't been touched in the last second
+ for (std::unordered_map<U64, LLVBCache>::iterator iter = sVBCache.begin(); iter != sVBCache.end(); )
+ {
+ if (now - iter->second.touched > 1s)
+ {
+ iter = sVBCache.erase(iter);
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+ }
}
- mBuffer->flush();
- mBuffer->setBuffer(immediate_mask);
+ vb->setBuffer();
if (mMode == LLRender::QUADS && sGLCoreProfile)
{
- mBuffer->drawArrays(LLRender::TRIANGLES, 0, count);
+ vb->drawArrays(LLRender::TRIANGLES, 0, count);
mQuadCycle = 1;
}
else
{
- mBuffer->drawArrays(mMode, 0, count);
+ vb->drawArrays(mMode, 0, count);
}
}
else
@@ -1948,8 +2014,7 @@ void LLRender::texCoord2fv(const GLfloat* tc)
void LLRender::color4ub(const GLubyte& r, const GLubyte& g, const GLubyte& b, const GLubyte& a)
{
- if (!LLGLSLShader::sCurBoundShaderPtr ||
- LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR)
+ if (!LLGLSLShader::sCurBoundShaderPtr || LLGLSLShader::sCurBoundShaderPtr->mAttributeMask & LLVertexBuffer::MAP_COLOR)
{
mColorsp[mCount] = LLColor4U(r,g,b,a);
}