diff options
Diffstat (limited to 'indra/llrender/llrender.cpp')
-rw-r--r-- | indra/llrender/llrender.cpp | 264 |
1 files changed, 157 insertions, 107 deletions
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 1301d325a0..828a509971 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -77,6 +77,7 @@ struct LLVBCache }; static std::unordered_map<U64, LLVBCache> sVBCache; +static thread_local std::list<LLVertexBufferData> *sBufferDataList = nullptr; static const GLenum sGLTextureType[] = { @@ -115,7 +116,7 @@ static const GLenum sGLBlendFactor[] = LLTexUnit::LLTexUnit(S32 index) : mCurrTexType(TT_NONE), - mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mTexColorSpace(TCS_LINEAR), + mCurrColorScale(1), mCurrAlphaScale(1), mCurrTexture(0), mHasMipMaps(false), mIndex(index) { @@ -145,8 +146,6 @@ void LLTexUnit::refreshState(void) { glBindTexture(GL_TEXTURE_2D, 0); } - - setTextureColorSpace(mTexColorSpace); } void LLTexUnit::activate(void) @@ -241,7 +240,6 @@ bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind) setTextureAddressMode(gl_tex->mAddressMode); setTextureFilteringOption(gl_tex->mFilterOption); } - setTextureColorSpace(mTexColorSpace); } } else @@ -318,7 +316,6 @@ bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind, S32 setTextureFilteringOption(texture->mFilterOption); stop_glerror(); } - setTextureColorSpace(mTexColorSpace); } stop_glerror(); @@ -354,7 +351,6 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) setTextureAddressMode(cubeMap->mImages[0]->mAddressMode); setTextureFilteringOption(cubeMap->mImages[0]->mFilterOption); } - setTextureColorSpace(mTexColorSpace); return true; } else @@ -403,7 +399,6 @@ bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) mCurrTexture = texture; glBindTexture(sGLTextureType[type], texture); mHasMipMaps = hasMips; - setTextureColorSpace(mTexColorSpace); } return true; } @@ -424,8 +419,6 @@ void LLTexUnit::unbind(eTextureType type) { mCurrTexture = 0; - // Always make sure our texture color space is reset to linear. SRGB sampling should be opt-in in the vast majority of cases. Also prevents color space "popping". - mTexColorSpace = TCS_LINEAR; if (type == LLTexUnit::TT_TEXTURE) { glBindTexture(sGLTextureType[type], sWhiteTexture); @@ -447,8 +440,6 @@ void LLTexUnit::unbindFast(eTextureType type) { mCurrTexture = 0; - // Always make sure our texture color space is reset to linear. SRGB sampling should be opt-in in the vast majority of cases. Also prevents color space "popping". - mTexColorSpace = TCS_LINEAR; if (type == LLTexUnit::TT_TEXTURE) { glBindTexture(sGLTextureType[type], sWhiteTexture); @@ -642,11 +633,6 @@ void LLTexUnit::debugTextureUnit(void) } } -void LLTexUnit::setTextureColorSpace(eTextureColorSpace space) -{ - mTexColorSpace = space; -} - LLLightState::LLLightState(S32 index) : mIndex(index), mEnabled(false), @@ -1543,6 +1529,30 @@ void LLRender::clearErrors() } } +void LLRender::beginList(std::list<LLVertexBufferData> *list) +{ + if (sBufferDataList) + { + LL_ERRS() << "beginList called while another list is open." << LL_ENDL; + } + llassert(LLGLSLShader::sCurBoundShaderPtr == &gUIProgram); + flush(); + sBufferDataList = list; +} + +void LLRender::endList() +{ + if (sBufferDataList) + { + flush(); + sBufferDataList = nullptr; + } + else + { + llassert(false); // endList called without an open list + } +} + void LLRender::begin(const GLuint& mode) { if (mode != mMode) @@ -1585,6 +1595,7 @@ void LLRender::end() flush(); } } + void LLRender::flush() { STOP_GLERROR; @@ -1633,127 +1644,166 @@ void LLRender::flush() if (mBuffer) { - HBXXH64 hash; + LLVertexBuffer *vb; + U32 attribute_mask = LLGLSLShader::sCurBoundShaderPtr->mAttributeMask; + if (sBufferDataList) + { + vb = genBuffer(attribute_mask, count); + sBufferDataList->emplace_back( + vb, + mMode, + count, + gGL.getTexUnit(0)->mCurrTexture, + mMatrix[MM_MODELVIEW][mMatIdx[MM_MODELVIEW]], + mMatrix[MM_PROJECTION][mMatIdx[MM_PROJECTION]], + mMatrix[MM_TEXTURE0][mMatIdx[MM_TEXTURE0]] + ); + } + else { - LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hash"); + vb = bufferfromCache(attribute_mask, count); + } - hash.update((U8*)mVerticesp.get(), count * sizeof(LLVector4a)); - if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0) - { - hash.update((U8*)mTexcoordsp.get(), count * sizeof(LLVector2)); - } + drawBuffer(vb, mMode, count); + } + else + { + // mBuffer is present in main thread and not present in an image thread + LL_ERRS() << "A flush call from outside main rendering thread" << LL_ENDL; + } - if (attribute_mask & LLVertexBuffer::MAP_COLOR) - { - hash.update((U8*)mColorsp.get(), count * sizeof(LLColor4U)); - } + resetStriders(count); + } +} - hash.finalize(); - } +LLVertexBuffer* LLRender::bufferfromCache(U32 attribute_mask, U32 count) +{ + LLVertexBuffer *vb = nullptr; + HBXXH64 hash; + { + LL_PROFILE_ZONE_NAMED_CATEGORY_VERTEX("vb cache hash"); - U64 vhash = hash.digest(); + hash.update((U8*)mVerticesp.get(), count * sizeof(LLVector4a)); + if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0) + { + hash.update((U8*)mTexcoordsp.get(), count * sizeof(LLVector2)); + } - // 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); + if (attribute_mask & LLVertexBuffer::MAP_COLOR) + { + hash.update((U8*)mColorsp.get(), count * sizeof(LLColor4U)); + } - LLPointer<LLVertexBuffer> vb; + hash.finalize(); + } - 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); + U64 vhash = hash.digest(); - vb->setBuffer(); + // 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); - vb->setPositionData((LLVector4a*) mVerticesp.get()); + 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 = genBuffer(attribute_mask, count); + + 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(); - if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0) + 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) { - vb->setTexCoord0Data(mTexcoordsp.get()); + iter = sVBCache.erase(iter); } - - if (attribute_mask & LLVertexBuffer::MAP_COLOR) + else { - vb->setColorData(mColorsp.get()); + ++iter; } + } + } + } + return vb; +} -#if LL_DARWIN - vb->unmapBuffer(); -#endif - vb->unbind(); +LLVertexBuffer* LLRender::genBuffer(U32 attribute_mask, S32 count) +{ + LLVertexBuffer * vb = new LLVertexBuffer(attribute_mask); + vb->allocateBuffer(count, 0); - sVBCache[vhash] = { vb , std::chrono::steady_clock::now() }; + vb->setBuffer(); - 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(); + vb->setPositionData((LLVector4a*)mVerticesp.get()); - 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; - } - } - } - } + if (attribute_mask & LLVertexBuffer::MAP_TEXCOORD0) + { + vb->setTexCoord0Data(mTexcoordsp.get()); + } - vb->setBuffer(); + if (attribute_mask & LLVertexBuffer::MAP_COLOR) + { + vb->setColorData(mColorsp.get()); + } - if (mMode == LLRender::QUADS && sGLCoreProfile) - { - vb->drawArrays(LLRender::TRIANGLES, 0, count); - mQuadCycle = 1; - } - else - { - vb->drawArrays(mMode, 0, count); - } - } - else - { - // mBuffer is present in main thread and not present in an image thread - LL_ERRS() << "A flush call from outside main rendering thread" << LL_ENDL; - } +#if LL_DARWIN + vb->unmapBuffer(); +#endif + vb->unbind(); + return vb; +} - mVerticesp[0] = mVerticesp[count]; - mTexcoordsp[0] = mTexcoordsp[count]; - mColorsp[0] = mColorsp[count]; +void LLRender::drawBuffer(LLVertexBuffer* vb, U32 mode, S32 count) +{ + vb->setBuffer(); - mCount = 0; + if (mode == LLRender::QUADS && sGLCoreProfile) + { + vb->drawArrays(LLRender::TRIANGLES, 0, count); + mQuadCycle = 1; + } + else + { + vb->drawArrays(mode, 0, count); } } +void LLRender::resetStriders(S32 count) +{ + mVerticesp[0] = mVerticesp[count]; + mTexcoordsp[0] = mTexcoordsp[count]; + mColorsp[0] = mColorsp[count]; + + mCount = 0; +} + void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z) { //the range of mVerticesp, mColorsp and mTexcoordsp is [0, 4095] |