diff options
Diffstat (limited to 'indra/llrender')
-rw-r--r-- | indra/llrender/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llrender/llfontgl.cpp | 10 | ||||
-rw-r--r-- | indra/llrender/llfontvertexbuffer.cpp | 209 | ||||
-rw-r--r-- | indra/llrender/llfontvertexbuffer.h | 119 | ||||
-rw-r--r-- | indra/llrender/llglslshader.cpp | 14 | ||||
-rw-r--r-- | indra/llrender/llglslshader.h | 12 | ||||
-rw-r--r-- | indra/llrender/llimagegl.cpp | 10 | ||||
-rw-r--r-- | indra/llrender/llrender.cpp | 264 | ||||
-rw-r--r-- | indra/llrender/llrender.h | 22 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.cpp | 1 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.cpp | 14 | ||||
-rw-r--r-- | indra/llrender/llshadermgr.h | 5 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.cpp | 48 | ||||
-rw-r--r-- | indra/llrender/llvertexbuffer.h | 31 |
14 files changed, 626 insertions, 135 deletions
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 7f881c8bb3..ccff7c7a8c 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -17,6 +17,7 @@ set(llrender_SOURCE_FILES llfontfreetype.cpp llfontfreetypesvg.cpp llfontgl.cpp + llfontvertexbuffer.cpp llfontregistry.cpp llgl.cpp llglslshader.cpp @@ -43,6 +44,7 @@ set(llrender_HEADER_FILES llcubemap.h llcubemaparray.h llfontgl.h + llfontvertexbuffer.h llfontfreetype.h llfontfreetypesvg.h llfontbitmapcache.h diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index b6cdb81b33..9721b020c7 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -270,10 +270,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons const LLFontGlyphInfo* next_glyph = NULL; - const S32 GLYPH_BATCH_SIZE = 30; - LLVector3 vertices[GLYPH_BATCH_SIZE * 4]; - LLVector2 uvs[GLYPH_BATCH_SIZE * 4]; - LLColor4U colors[GLYPH_BATCH_SIZE * 4]; + static constexpr S32 GLYPH_BATCH_SIZE = 30; + static thread_local LLVector3 vertices[GLYPH_BATCH_SIZE * 4]; + static thread_local LLVector2 uvs[GLYPH_BATCH_SIZE * 4]; + static thread_local LLColor4U colors[GLYPH_BATCH_SIZE * 4]; LLColor4U text_color(color); // Preserve the transparency to render fading emojis in fading text (e.g. @@ -402,7 +402,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons if (draw_ellipses) { - // recursively render ellipses at end of string // we've already reserved enough room gGL.pushUIMatrix(); @@ -504,6 +503,7 @@ F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars, bool no_padding) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; F32 cur_x = 0; diff --git a/indra/llrender/llfontvertexbuffer.cpp b/indra/llrender/llfontvertexbuffer.cpp new file mode 100644 index 0000000000..96ec94fe0f --- /dev/null +++ b/indra/llrender/llfontvertexbuffer.cpp @@ -0,0 +1,209 @@ +/** + * @file llfontvertexbuffer.cpp + * @brief Buffer storage for font rendering. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llfontvertexbuffer.h" + +#include "llvertexbuffer.h" + + +LLFontVertexBuffer::LLFontVertexBuffer() +{ +} + +LLFontVertexBuffer::~LLFontVertexBuffer() +{ + reset(); +} + +void LLFontVertexBuffer::reset() +{ + mBufferList.clear(); +} + +S32 LLFontVertexBuffer::render( + const LLFontGL* fontp, + const LLWString& text, + S32 begin_offset, + LLRect rect, + const LLColor4& color, + LLFontGL::HAlign halign, LLFontGL::VAlign valign, + U8 style, + LLFontGL::ShadowType shadow, + S32 max_chars, S32 max_pixels, + F32* right_x, + bool use_ellipses, + bool use_color) +{ + LLRectf rect_float((F32)rect.mLeft, (F32)rect.mTop, (F32)rect.mRight, (F32)rect.mBottom); + return render(fontp, text, begin_offset, rect_float, color, halign, valign, style, shadow, max_chars, right_x, use_ellipses, use_color); +} + +S32 LLFontVertexBuffer::render( + const LLFontGL* fontp, + const LLWString& text, + S32 begin_offset, + LLRectf rect, + const LLColor4& color, + LLFontGL::HAlign halign, LLFontGL::VAlign valign, + U8 style, + LLFontGL::ShadowType shadow, + S32 max_chars, + F32* right_x, + bool use_ellipses, + bool use_color) +{ + F32 x = rect.mLeft; + F32 y = 0.f; + + switch (valign) + { + case LLFontGL::TOP: + y = rect.mTop; + break; + case LLFontGL::VCENTER: + y = rect.getCenterY(); + break; + case LLFontGL::BASELINE: + case LLFontGL::BOTTOM: + y = rect.mBottom; + break; + default: + y = rect.mBottom; + break; + } + return render(fontp, text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, (S32)rect.getWidth(), right_x, use_ellipses, use_color); +} + +S32 LLFontVertexBuffer::render( + const LLFontGL* fontp, + const LLWString& text, + S32 begin_offset, + F32 x, F32 y, + const LLColor4& color, + LLFontGL::HAlign halign, LLFontGL::VAlign valign, + U8 style, + LLFontGL::ShadowType shadow, + S32 max_chars , S32 max_pixels, + F32* right_x, + bool use_ellipses, + bool use_color ) +{ + if (!LLFontGL::sDisplayFont) //do not display texts + { + return static_cast<S32>(text.length()); + } + if (mBufferList.empty()) + { + genBuffers(fontp, text, begin_offset, x, y, color, halign, valign, + style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color); + } + else if (mLastX != x + || mLastY != y + || mLastFont != fontp + || mLastColor != color // alphas change often + || mLastHalign != halign + || mLastValign != valign + || mLastOffset != begin_offset + || mLastMaxChars != max_chars + || mLastMaxPixels != max_pixels + || mLastStyle != style + || mLastShadow != shadow // ex: buttons change shadow state + || mLastScaleX != LLFontGL::sScaleX + || mLastScaleY != LLFontGL::sScaleY + || mLastOrigin != LLFontGL::sCurOrigin) + { + genBuffers(fontp, text, begin_offset, x, y, color, halign, valign, + style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color); + } + else + { + renderBuffers(); + + if (right_x) + { + *right_x = mLastRightX; + } + } + return mChars; +} + +void LLFontVertexBuffer::genBuffers( + const LLFontGL* fontp, + const LLWString& text, + S32 begin_offset, + F32 x, F32 y, + const LLColor4& color, + LLFontGL::HAlign halign, LLFontGL::VAlign valign, + U8 style, LLFontGL::ShadowType shadow, + S32 max_chars, S32 max_pixels, + F32* right_x, + bool use_ellipses, + bool use_color) +{ + // todo: add a debug build assert if this triggers too often for to long? + mBufferList.clear(); + + gGL.beginList(&mBufferList); + mChars = fontp->render(text, begin_offset, x, y, color, halign, valign, + style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color); + gGL.endList(); + + mLastFont = fontp; + mLastOffset = begin_offset; + mLastMaxChars = max_chars; + mLastMaxPixels = max_pixels; + mLastX = x; + mLastY = y; + mLastColor = color; + mLastHalign = halign; + mLastValign = valign; + mLastStyle = style; + mLastShadow = shadow; + + mLastScaleX = LLFontGL::sScaleX; + mLastScaleY = LLFontGL::sScaleY; + mLastOrigin = LLFontGL::sCurOrigin; + + if (right_x) + { + mLastRightX = *right_x; + } +} + +void LLFontVertexBuffer::renderBuffers() +{ + gGL.flush(); // deliberately empty pending verts + gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); + gGL.pushUIMatrix(); + for (LLVertexBufferData& buffer : mBufferList) + { + buffer.draw(); + } + gGL.popUIMatrix(); +} + diff --git a/indra/llrender/llfontvertexbuffer.h b/indra/llrender/llfontvertexbuffer.h new file mode 100644 index 0000000000..67cf2ca13c --- /dev/null +++ b/indra/llrender/llfontvertexbuffer.h @@ -0,0 +1,119 @@ +/** + * @file llfontgl.h + * @author Andrii Kleshchev + * @brief Buffer storage for font rendering. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLFONTVERTEXBUFFER_H +#define LL_LLFONTVERTEXBUFFER_H + +#include "llfontgl.h" + +class LLVertexBufferData; + +class LLFontVertexBuffer +{ +public: + LLFontVertexBuffer(); + ~LLFontVertexBuffer(); + + void reset(); + + S32 render(const LLFontGL* fontp, + const LLWString& text, + S32 begin_offset, + LLRect rect, + const LLColor4& color, + LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE, + U8 style = LLFontGL::NORMAL, + LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW, + S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, + F32* right_x = NULL, + bool use_ellipses = false, + bool use_color = true); + + S32 render(const LLFontGL* fontp, + const LLWString& text, + S32 begin_offset, + LLRectf rect, + const LLColor4& color, + LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE, + U8 style = LLFontGL::NORMAL, + LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW, + S32 max_chars = S32_MAX, + F32* right_x = NULL, + bool use_ellipses = false, + bool use_color = true); + + S32 render(const LLFontGL* fontp, + const LLWString& text, + S32 begin_offset, + F32 x, F32 y, + const LLColor4& color, + LLFontGL::HAlign halign = LLFontGL::LEFT, LLFontGL::VAlign valign = LLFontGL::BASELINE, + U8 style = LLFontGL::NORMAL, + LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW, + S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, + F32* right_x = NULL, + bool use_ellipses = false, + bool use_color = true); +private: + + void genBuffers(const LLFontGL* fontp, + const LLWString& text, + S32 begin_offset, + F32 x, F32 y, + const LLColor4& color, + LLFontGL::HAlign halign, LLFontGL::VAlign valign, + U8 style, + LLFontGL::ShadowType shadow, + S32 max_chars, S32 max_pixels, + F32* right_x, + bool use_ellipses, + bool use_color); + + void renderBuffers(); + + std::list<LLVertexBufferData> mBufferList; + S32 mChars = 0; + const LLFontGL *mLastFont = nullptr; + S32 mLastOffset = 0; + S32 mLastMaxChars = 0; + S32 mLastMaxPixels = 0; + F32 mLastX = 0.f; + F32 mLastY = 0.f; + LLColor4 mLastColor; + LLFontGL::HAlign mLastHalign = LLFontGL::LEFT; + LLFontGL::VAlign mLastValign = LLFontGL::BASELINE; + U8 mLastStyle = LLFontGL::NORMAL; + LLFontGL::ShadowType mLastShadow = LLFontGL::NO_SHADOW; + F32 mLastRightX = 0.f; + + // LLFontGL's statics + F32 mLastScaleX = 1.f; + F32 mLastScaleY = 1.f; + LLCoordGL mLastOrigin; +}; + +#endif diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index daa768e8ab..a157bfee21 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -1087,17 +1087,17 @@ void LLGLSLShader::unbind(void) sCurBoundShaderPtr = NULL; } -S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace) +S32 LLGLSLShader::bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; S32 channel = 0; channel = getUniformLocation(uniform); - return bindTexture(channel, texture, mode, colorspace); + return bindTexture(channel, texture, mode); } -S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace colorspace) +S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; @@ -1113,7 +1113,6 @@ S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextu if (uniform > -1) { gGL.getTexUnit(uniform)->bindFast(texture); - gGL.getTexUnit(uniform)->setTextureColorSpace(colorspace); } return uniform; @@ -1194,7 +1193,7 @@ S32 LLGLSLShader::getTextureChannel(S32 uniform) const return mTexture[uniform]; } -S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) +S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; @@ -1211,12 +1210,11 @@ S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTex { gGL.getTexUnit(index)->activate(); gGL.getTexUnit(index)->enable(mode); - gGL.getTexUnit(index)->setTextureColorSpace(space); } return index; } -S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTexUnit::eTextureColorSpace space) +S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode) { LL_PROFILE_ZONE_SCOPED_CATEGORY_SHADER; @@ -1229,7 +1227,7 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode, LLTe S32 index = mTexture[uniform]; if (index != -1 && gGL.getTexUnit(index)->getCurrType() != LLTexUnit::TT_NONE) { - if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode && gGL.getTexUnit(index)->getCurrColorSpace() != space) + if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode) { if (gDebugSession) { diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index f3c41cd819..27c8f0b7d0 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -241,6 +241,10 @@ public: void clearPermutations(); void addPermutation(std::string name, std::string value); + void addPermutations(const std::map<std::string, std::string>& defines) + { + mDefines.insert(defines.begin(), defines.end()); + } void removePermutation(std::string name); void addConstant(const LLGLSLShader::eShaderConsts shader_const); @@ -249,16 +253,16 @@ public: //if given texture uniform is active in the shader, //the corresponding channel will be active upon return //returns channel texture is enabled in from [0-MAX) - S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); - S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); + S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); // get the texture channel of the given uniform, or -1 if uniform is not used as a texture S32 getTextureChannel(S32 uniform) const; // bindTexture returns the texture unit we've bound the texture to. // You can reuse the return value to unbind a texture when required. - S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); - S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE, LLTexUnit::eTextureColorSpace space = LLTexUnit::TCS_LINEAR); + S32 bindTexture(const std::string& uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); + S32 bindTexture(S32 uniform, LLTexture* texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); S32 bindTexture(const std::string& uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR); S32 bindTexture(S32 uniform, LLRenderTarget* texture, bool depth = false, LLTexUnit::eTextureFilterOptions mode = LLTexUnit::TFO_BILINEAR, U32 index = 0); S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index 03ac10c00a..68c20048ec 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -70,6 +70,7 @@ static U64 sTextureBytes = 0; void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 intformat, U32 count) { U32 texUnit = gGL.getCurrentTexUnitIndex(); + llassert(texUnit == 0); // allocations should always be done on tex unit 0 U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture(); U64 size = LLImageGL::dataFormatBytes(intformat, width, height); size *= count; @@ -77,6 +78,8 @@ void LLImageGLMemory::alloc_tex_image(U32 width, U32 height, U32 intformat, U32 llassert(size >= 0); sTexMemMutex.lock(); + + // it is a precondition that no existing allocation exists for this texture llassert(sTextureAllocs.find(texName) == sTextureAllocs.end()); sTextureAllocs[texName] = size; @@ -90,7 +93,7 @@ void LLImageGLMemory::free_tex_image(U32 texName) { sTexMemMutex.lock(); auto iter = sTextureAllocs.find(texName); - if (iter != sTextureAllocs.end()) + if (iter != sTextureAllocs.end()) // sometimes a texName will be "freed" before allocated (e.g. first call to setManualImage for a given texName) { llassert(iter->second <= sTextureBytes); // sTextureBytes MUST NOT go below zero @@ -115,6 +118,7 @@ void LLImageGLMemory::free_tex_images(U32 count, const U32* texNames) void LLImageGLMemory::free_cur_tex_image() { U32 texUnit = gGL.getCurrentTexUnitIndex(); + llassert(texUnit == 0); // frees should always be done on tex unit 0 U32 texName = gGL.getTexUnit(texUnit)->getCurrTexture(); free_tex_image(texName); } @@ -1240,8 +1244,8 @@ void LLImageGL::deleteTextures(S32 numTextures, const U32 *textures) if (!sFreeList[idx].empty()) { - glDeleteTextures((GLsizei) sFreeList[idx].size(), sFreeList[idx].data()); free_tex_images((GLsizei) sFreeList[idx].size(), sFreeList[idx].data()); + glDeleteTextures((GLsizei)sFreeList[idx].size(), sFreeList[idx].data()); sFreeList[idx].resize(0); } } @@ -2461,7 +2465,7 @@ bool LLImageGL::scaleDown(S32 desired_discard) { // use a PBO to downscale the texture U64 size = getBytes(desired_discard); llassert(size <= 2048 * 2048 * 4); // we shouldn't be using this method to downscale huge textures, but it'll work - gGL.getTexUnit(0)->bind(this); + gGL.getTexUnit(0)->bind(this, false, true); if (sScratchPBO == 0) { 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] diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 010ab122b6..39c13e328a 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -45,12 +45,14 @@ #include "glh/glh_linear.h" #include <array> +#include <list> class LLVertexBuffer; class LLCubeMap; class LLImageGL; class LLRenderTarget; -class LLTexture ; +class LLTexture; +class LLVertexBufferData; #define LL_MATRIX_STACK_DEPTH 32 @@ -219,17 +221,12 @@ public: void setHasMipMaps(bool hasMips) { mHasMipMaps = hasMips; } - void setTextureColorSpace(eTextureColorSpace space); - - eTextureColorSpace getCurrColorSpace() { return mTexColorSpace; } - protected: friend class LLRender; S32 mIndex; U32 mCurrTexture; eTextureType mCurrTexType; - eTextureColorSpace mTexColorSpace; S32 mCurrColorScale; S32 mCurrAlphaScale; bool mHasMipMaps; @@ -420,8 +417,15 @@ public: void flush(); + // if list is set, will store buffers in list for later use, if list isn't set, will use cache + void beginList(std::list<LLVertexBufferData> *list); + void endList(); + void begin(const GLuint& mode); void end(); + + U8 getMode() const { return mMode; } + void vertex2i(const GLint& x, const GLint& y); void vertex2f(const GLfloat& x, const GLfloat& y); void vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z); @@ -490,6 +494,11 @@ public: private: friend class LLLightState; + LLVertexBuffer* bufferfromCache(U32 attribute_mask, U32 count); + LLVertexBuffer* genBuffer(U32 attribute_mask, S32 count); + void drawBuffer(LLVertexBuffer* vb, U32 mode, S32 count); + void resetStriders(S32 count); + eMatrixMode mMatrixMode; U32 mMatIdx[NUM_MATRIX_MODES]; U32 mMatHash[NUM_MATRIX_MODES]; @@ -520,7 +529,6 @@ private: std::vector<LLVector3> mUIOffset; std::vector<LLVector3> mUIScale; - }; extern F32 gGLModelView[16]; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 21a0820d32..38bc5ff331 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -509,7 +509,6 @@ void LLRenderTarget::bindTexture(U32 index, S32 channel, LLTexUnit::eTextureFilt } gGL.getTexUnit(channel)->setTextureFilteringOption(filter_options); - gGL.getTexUnit(channel)->setTextureColorSpace(isSRGB ? LLTexUnit::TCS_SRGB : LLTexUnit::TCS_LINEAR); } void LLRenderTarget::flush() diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index e9608491a4..150277c8df 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -597,6 +597,15 @@ GLuint LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_lev } } + if (type == GL_FRAGMENT_SHADER) + { + extra_code_text[extra_code_count++] = strdup("#define FRAGMENT_SHADER 1\n"); + } + else + { + extra_code_text[extra_code_count++] = strdup("#define VERTEX_SHADER 1\n"); + } + // Use alpha float to store bit flags // See: C++: addDeferredAttachment(), shader: frag_data[2] extra_code_text[extra_code_count++] = strdup("#define GBUFFER_FLAG_SKIP_ATMOS 0.0 \n"); // atmo kill @@ -1468,6 +1477,11 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("debug_normal_draw_length"); + mReservedUniforms.push_back("edgesTex"); + mReservedUniforms.push_back("areaTex"); + mReservedUniforms.push_back("searchTex"); + mReservedUniforms.push_back("blendTex"); + llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS); std::set<std::string> dupe_check; diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 2b76ef664b..0eb9db6715 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -332,6 +332,11 @@ public: DEBUG_NORMAL_DRAW_LENGTH, // "debug_normal_draw_length" + SMAA_EDGE_TEX, // "edgesTex" + SMAA_AREA_TEX, // "areaTex" + SMAA_SEARCH_TEX, // "searchTex" + SMAA_BLEND_TEX, // "blendTex" + END_RESERVED_UNIFORMS } eGLSLReservedUniforms; // clang-format on diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 02afcf12c6..156e300853 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -570,6 +570,54 @@ public: static LLVBOPool* sVBOPool = nullptr; +void LLVertexBufferData::draw() +{ + if (!mVB) + { + llassert(false); + // Not supposed to happen, check buffer generation + return; + } + + if (mTexName) + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTexName); + } + else + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.pushMatrix(); + gGL.loadMatrix(mModelView.m); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.pushMatrix(); + gGL.loadMatrix(mProjection.m); + gGL.matrixMode(LLRender::MM_TEXTURE0); + gGL.pushMatrix(); + gGL.loadMatrix(mTexture0.m); + + mVB->setBuffer(); + + if (mMode == LLRender::QUADS && LLRender::sGLCoreProfile) + { + mVB->drawArrays(LLRender::TRIANGLES, 0, mCount); + } + else + { + mVB->drawArrays(mMode, 0, mCount); + } + + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_PROJECTION); + gGL.popMatrix(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + gGL.popMatrix(); +} + +//============================================================================ + //static U64 LLVertexBuffer::getBytesAllocated() { diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index 4ada0c335b..2a4affdc60 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -53,6 +53,37 @@ //============================================================================ // base class class LLPrivateMemoryPool; +class LLVertexBuffer; + +class LLVertexBufferData +{ +public: + LLVertexBufferData() + : mVB(nullptr) + , mMode(0) + , mCount(0) + , mTexName(0) + {} + LLVertexBufferData(LLVertexBuffer* buffer, U8 mode, U32 count, U32 tex_name, glh::matrix4f model_view, glh::matrix4f projection, glh::matrix4f texture0) + : mVB(buffer) + , mMode(mode) + , mCount(count) + , mTexName(tex_name) + , mProjection(model_view) + , mModelView(projection) + , mTexture0(texture0) + {} + void draw(); + LLPointer<LLVertexBuffer> mVB; + U8 mMode; + U32 mCount; + U32 mTexName; + glh::matrix4f mProjection; + glh::matrix4f mModelView; + glh::matrix4f mTexture0; +}; +typedef std::list<LLVertexBufferData> buffer_data_list_t; + class LLVertexBuffer final : public LLRefCount { public: |