diff options
| author | Dave Parks <davep@lindenlab.com> | 2023-01-10 18:42:09 -0600 | 
|---|---|---|
| committer | Dave Parks <davep@lindenlab.com> | 2023-01-10 18:42:09 -0600 | 
| commit | 68da705f3ba284928c7e23acd4164d56dea17af9 (patch) | |
| tree | 955b9396ec1219f0dd52c7149c5e5ce461a15e37 | |
| parent | fdc0ea64f050ad09a84442f40396bb9e6497ce52 (diff) | |
SL-18869 Optimizations -- Quiet command buffer -- VBO cache for UI et al and remove many unneeded VBO binds.
| -rw-r--r-- | indra/llrender/llrender.cpp | 108 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 22 | ||||
| -rw-r--r-- | indra/llrender/llvertexbuffer.h | 4 | 
3 files changed, 122 insertions, 12 deletions
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 8ab8d3151b..7c974934ae 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 "llmd5.h"  #if LL_WINDOWS  extern void APIENTRY gl_debug_callback(GLenum source, @@ -66,6 +67,14 @@ 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<std::size_t, LLVBCache> sVBCache; +  static const GLenum sGLTextureType[] =  {  	GL_TEXTURE_2D, @@ -1635,24 +1644,105 @@ 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); + +            LLMD5 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(); +            } +             +            size_t vhash[2]; +            hash.raw_digest((unsigned char*) vhash); + +            // 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 +            auto& cache = sVBCache.find(vhash[0]); + +            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, GL_STATIC_DRAW); +                vb->allocateBuffer(count, 0, true); +                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[0]] = { 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 (auto& 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(immediate_mask);              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 diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 20261dcb8a..57be21cf6e 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -1180,7 +1180,6 @@ bool expand_region(LLVertexBuffer::MappedRegion& region, S32 start, S32 end)  U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_range)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; -	bindGLBuffer(true);  	if (mFinal)  	{  		LL_ERRS() << "LLVertexBuffer::mapVeretxBuffer() called on a finalized buffer." << LL_ENDL; @@ -1256,7 +1255,6 @@ U8* LLVertexBuffer::mapVertexBuffer(S32 type, S32 index, S32 count, bool map_ran  U8* LLVertexBuffer::mapIndexBuffer(S32 index, S32 count, bool map_range)  {      LL_PROFILE_ZONE_SCOPED_CATEGORY_VERTEX; -	bindGLIndices(true);  	if (mFinal)  	{  		LL_ERRS() << "LLVertexBuffer::mapIndexBuffer() called on a finalized buffer." << LL_ENDL; @@ -2070,6 +2068,24 @@ void LLVertexBuffer::setupVertexBufferFast(U32 data_mask)          void* ptr = (void*)(base + mOffsets[TYPE_VERTEX]);          glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_VERTEX], ptr);      } -	} +} + +void LLVertexBuffer::setPositionData(const LLVector4a* data) +{ +    bindGLBuffer(); +    flush_vbo(GL_ARRAY_BUFFER, 0, sizeof(LLVector4a) * getNumVerts(), (U8*) data); +} + +void LLVertexBuffer::setTexCoordData(const LLVector2* data) +{ +    bindGLBuffer(); +    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_TEXCOORD0], mOffsets[TYPE_TEXCOORD0] + sTypeSize[TYPE_TEXCOORD0] * getNumVerts(), (U8*)data); +} + +void LLVertexBuffer::setColorData(const LLColor4U* data) +{ +    bindGLBuffer(); +    flush_vbo(GL_ARRAY_BUFFER, mOffsets[TYPE_COLOR], mOffsets[TYPE_COLOR] + sTypeSize[TYPE_COLOR] * getNumVerts(), (U8*) data); +} diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 74b951884d..926d37b052 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -212,6 +212,10 @@ public:      bool getMetallicRoughnessTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);      bool getEmissiveTexcoordStrider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false); +    void setPositionData(const LLVector4a* data); +    void setTexCoordData(const LLVector2* data); +    void setColorData(const LLColor4U* data); +  	bool useVBOs() const;  	bool isEmpty() const					{ return mEmpty; }  | 
