From a638d9610d9f369eca6dff74e8860ca466c253c7 Mon Sep 17 00:00:00 2001
From: Andrey Kleshchev <andreykproductengine@lindenlab.com>
Date: Thu, 29 Aug 2024 18:49:10 +0300
Subject: viewer#2411 LLFontGL::render optimizations #2

---
 indra/llrender/llfontgl.cpp           |   3 +
 indra/llrender/llfontvertexbuffer.cpp | 119 ++++++++++++++++++++++------------
 indra/llrender/llfontvertexbuffer.h   |  15 ++++-
 indra/llui/llbutton.cpp               |  64 ++++++++++++++++--
 indra/llui/llbutton.h                 |  49 +++++++-------
 indra/newview/llhudnametag.cpp        |  19 ++++++
 indra/newview/llhudnametag.h          |   1 +
 7 files changed, 195 insertions(+), 75 deletions(-)

(limited to 'indra')

diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index 481e35c16a..701ab4d060 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -490,6 +490,9 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 
     if (draw_ellipses)
     {
+        // signal a separate context
+        buffer_list->emplace_back(nullptr, nullptr, 0, 0);
+
         // recursively render ellipses at end of string
         // we've already reserved enough room
         gGL.pushUIMatrix();
diff --git a/indra/llrender/llfontvertexbuffer.cpp b/indra/llrender/llfontvertexbuffer.cpp
index 3ff0771795..c4b68c4a6c 100644
--- a/indra/llrender/llfontvertexbuffer.cpp
+++ b/indra/llrender/llfontvertexbuffer.cpp
@@ -53,7 +53,8 @@ S32 LLFontVertexBuffer::render(
     F32 x, F32 y,
     const LLColor4& color,
     LLFontGL::HAlign halign, LLFontGL::VAlign valign,
-    U8 style, LLFontGL::ShadowType shadow,
+    U8 style,
+    LLFontGL::ShadowType shadow,
     S32 max_chars , S32 max_pixels,
     F32* right_x,
     bool use_ellipses,
@@ -64,62 +65,33 @@ S32 LLFontVertexBuffer::render(
         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 || mLastColor != color) // always track position and alphs
+    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
     {
         genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
             style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
     }
-    else if (true //mTrackStringChanges
-             && (mLastOffset != begin_offset
-                 || mLastMaxChars != max_chars
-                 || mLastMaxPixels != max_pixels
-                 || mLastStringHash != sStringHasher._Do_hash(text))) // todo, track all parameters?
+    else if (mTrackStringChanges && mLastStringHash != sStringHasher._Do_hash(text))
     {
         genBuffers(fontp, text, begin_offset, x, y, color, halign, valign,
             style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color);
     }
     else
     {
+        renderBuffers();
 
-        gGL.flush(); // deliberately empty pending verts
-        gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-        gGL.pushUIMatrix();
-
-        gGL.loadUIIdentity();
-
-        // Depth translation, so that floating text appears 'in-world'
-        // and is correctly occluded.
-        gGL.translatef(0.f, 0.f, LLFontGL::sCurDepth);
-
-        gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
-        for (auto &buf_data : mBufferList)
-        {
-            if (buf_data.mImage)
-            {
-                gGL.getTexUnit(0)->bind(buf_data.mImage);
-            }
-            else
-            {
-                gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-            }
-            buf_data.mBuffer->setBuffer();
-
-            if (LLRender::sGLCoreProfile && buf_data.mMode == LLRender::QUADS)
-            {
-                buf_data.mBuffer->drawArrays(LLRender::TRIANGLES, 0, buf_data.mCount);
-            }
-            else
-            {
-                buf_data.mBuffer->drawArrays(buf_data.mMode, 0, buf_data.mCount);
-            }
-        }
         if (right_x)
         {
             *right_x = mLastRightX;
         }
-
-        gGL.popUIMatrix();
     }
     return mChars;
 }
@@ -141,6 +113,7 @@ void LLFontVertexBuffer::genBuffers(
     mChars = fontp->render(text, begin_offset, x, y, color, halign, valign,
         style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color, &mBufferList);
 
+    mLastFont = fontp;
     mLastOffset = begin_offset;
     mLastMaxChars = max_chars;
     mLastMaxPixels = max_pixels;
@@ -148,6 +121,10 @@ void LLFontVertexBuffer::genBuffers(
     mLastX = x;
     mLastY = y;
     mLastColor = color;
+    mLastHalign = halign;
+    mLastValign = valign;
+    mLastStyle = style;
+    mLastShadow = shadow;
 
     if (right_x)
     {
@@ -155,3 +132,61 @@ void LLFontVertexBuffer::genBuffers(
     }
 }
 
+void render_buffers(LLFontVertexBuffer::buffer_list_t::iterator iter, LLFontVertexBuffer::buffer_list_t::iterator end)
+{
+    gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+    gGL.pushUIMatrix();
+
+    gGL.loadUIIdentity();
+
+    // Depth translation, so that floating text appears 'in-world'
+    // and is correctly occluded.
+    gGL.translatef(0.f, 0.f, LLFontGL::sCurDepth);
+
+    gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+    while (iter != end)
+    {
+        if (iter->mBuffer == nullptr)
+        {
+            // elipses indicator
+            iter++;
+            break;
+        }
+        if (iter->mImage)
+        {
+            gGL.getTexUnit(0)->bind(iter->mImage);
+        }
+        else
+        {
+            gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+        }
+        iter->mBuffer->setBuffer();
+
+        if (LLRender::sGLCoreProfile && iter->mMode == LLRender::QUADS)
+        {
+            iter->mBuffer->drawArrays(LLRender::TRIANGLES, 0, iter->mCount);
+        }
+        else
+        {
+            iter->mBuffer->drawArrays(iter->mMode, 0, iter->mCount);
+        }
+        iter++;
+    }
+
+    if (iter != end)
+    {
+        gGL.pushUIMatrix();
+        render_buffers(iter, end);
+        gGL.popUIMatrix();
+    }
+
+    gGL.popUIMatrix();
+}
+
+void LLFontVertexBuffer::renderBuffers()
+{
+    gGL.flush(); // deliberately empty pending verts
+    render_buffers(mBufferList.begin(), mBufferList.end());
+}
+
diff --git a/indra/llrender/llfontvertexbuffer.h b/indra/llrender/llfontvertexbuffer.h
index bd42cf6c2d..458b0a91bb 100644
--- a/indra/llrender/llfontvertexbuffer.h
+++ b/indra/llrender/llfontvertexbuffer.h
@@ -46,12 +46,14 @@ public:
         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,
+        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);
 
+    typedef std::list<LLFontGL::LLVertexBufferData> buffer_list_t;
 private:
 
     void genBuffers(const LLFontGL* fontp,
@@ -60,15 +62,18 @@ private:
          F32 x, F32 y,
          const LLColor4& color,
          LLFontGL::HAlign halign, LLFontGL::VAlign valign,
-         U8 style, LLFontGL::ShadowType shadow,
+         U8 style,
+        LLFontGL::ShadowType shadow,
          S32 max_chars, S32 max_pixels,
          F32* right_x,
          bool use_ellipses,
          bool use_color);
 
+    void renderBuffers();
 
-    std::list<LLFontGL::LLVertexBufferData> mBufferList;
+    buffer_list_t mBufferList;
     S32 mChars = 0;
+    const LLFontGL *mLastFont = nullptr;
     S32 mLastOffset = 0;
     S32 mLastMaxChars = 0;
     S32 mLastMaxPixels = 0;
@@ -76,6 +81,10 @@ private:
     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;
     bool mTrackStringChanges = true;
 
diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp
index 3df7f83d49..a9f1c10256 100644
--- a/indra/llui/llbutton.cpp
+++ b/indra/llui/llbutton.cpp
@@ -125,7 +125,6 @@ LLButton::LLButton(const LLButton::Params& p)
     mFontBuffer(false),
     mMouseDownFrame(0),
     mMouseHeldDownCount(0),
-    mBorderEnabled( false ),
     mFlashing( false ),
     mCurGlowStrength(0.f),
     mNeedsHighlight(false),
@@ -423,11 +422,38 @@ bool LLButton::postBuild()
 
 void LLButton::onVisibilityChange(bool new_visibility)
 {
-    if (!new_visibility)
+    mFontBuffer.reset();
+    return LLUICtrl::onVisibilityChange(new_visibility);
+}
+
+void LLButton::reshape(S32 width, S32 height, bool called_from_parent)
+{
+    S32 delta_width = width - getRect().getWidth();
+    S32 delta_height = height - getRect().getHeight();
+
+    if (delta_width || delta_height || sForceReshape)
     {
+        LLUICtrl::reshape(width, height, called_from_parent);
         mFontBuffer.reset();
     }
-    return LLUICtrl::onVisibilityChange(new_visibility);
+}
+
+void LLButton::translate(S32 x, S32 y)
+{
+    LLUICtrl::translate(x, y);
+    mFontBuffer.reset();
+}
+
+void LLButton::setRect(const LLRect& rect)
+{
+    LLUICtrl::setRect(rect);
+    mFontBuffer.reset();
+}
+
+void LLButton::dirtyRect()
+{
+    LLUICtrl::dirtyRect();
+    mFontBuffer.reset();
 }
 
 bool LLButton::handleUnicodeCharHere(llwchar uni_char)
@@ -616,19 +642,25 @@ void LLButton::onMouseLeave(S32 x, S32 y, MASK mask)
 {
     LLUICtrl::onMouseLeave(x, y, mask);
 
-    mNeedsHighlight = false;
+    setHighlight(false);
 }
 
 void LLButton::setHighlight(bool b)
 {
-    mNeedsHighlight = b;
+    if (mNeedsHighlight != b)
+    {
+        mNeedsHighlight = b;
+        mFontBuffer.reset();
+    }
 }
 
 bool LLButton::handleHover(S32 x, S32 y, MASK mask)
 {
     if (isInEnabledChain()
         && (!gFocusMgr.getMouseCapture() || gFocusMgr.getMouseCapture() == this))
-        mNeedsHighlight = true;
+    {
+        setHighlight(true);
+    }
 
     if (!childrenHandleHover(x, y, mask))
     {
@@ -1096,6 +1128,18 @@ void LLButton::setLabelSelected( const LLStringExplicit& label )
     mFontBuffer.reset();
 }
 
+void LLButton::setDisabledLabelColor(const LLUIColor& c)
+{
+    mDisabledLabelColor = c;
+    mFontBuffer.reset();
+}
+
+void LLButton::setFont(const LLFontGL* font)
+{
+    mGLFont = (font ? font : LLFontGL::getFontSansSerif());
+    mFontBuffer.reset();
+}
+
 bool LLButton::labelIsTruncated() const
 {
     return getCurrentLabel().getString().size() > mLastDrawCharsCount;
@@ -1106,6 +1150,12 @@ const LLUIString& LLButton::getCurrentLabel() const
     return getToggleState() ? mSelectedLabel : mUnselectedLabel;
 }
 
+void LLButton::setDropShadowedText(bool b)
+{
+    mDropShadowedText = b;
+    mFontBuffer.reset();
+}
+
 void LLButton::setImageUnselected(LLPointer<LLUIImage> image)
 {
     mImageUnselected = image;
@@ -1153,7 +1203,6 @@ void LLButton::resize(const LLUIString& label)
         if (btn_width < min_width)
         {
             reshape(min_width, getRect().getHeight());
-            mFontBuffer.reset();
         }
     }
 }
@@ -1190,6 +1239,7 @@ void LLButton::setImageDisabledSelected(LLPointer<LLUIImage> image)
     mImageDisabledSelected = image;
     mDisabledImageColor = mImageColor;
     mFadeWhenDisabled = true;
+    mFontBuffer.reset();
 }
 
 void LLButton::setImagePressed(LLPointer<LLUIImage> image)
diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h
index c8e2b941c9..74ed922510 100644
--- a/indra/llui/llbutton.h
+++ b/indra/llui/llbutton.h
@@ -157,23 +157,27 @@ public:
 
     void            addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName,
                                         const LLUUID&   imageID,const std::string&  xmlTagName) const;
-    virtual bool    handleUnicodeCharHere(llwchar uni_char);
-    virtual bool    handleKeyHere(KEY key, MASK mask);
-    virtual bool    handleMouseDown(S32 x, S32 y, MASK mask);
-    virtual bool    handleMouseUp(S32 x, S32 y, MASK mask);
-    virtual bool    handleHover(S32 x, S32 y, MASK mask);
-    virtual bool    handleRightMouseDown(S32 x, S32 y, MASK mask);
-    virtual bool    handleRightMouseUp(S32 x, S32 y, MASK mask);
-    virtual bool    handleDoubleClick(S32 x, S32 y, MASK mask);
-    virtual void    draw();
-    /*virtual*/ bool postBuild();
-
-    /*virtual*/ void onVisibilityChange(bool visible);
-
-    virtual void    onMouseLeave(S32 x, S32 y, MASK mask);
-    virtual void    onMouseCaptureLost();
-
-    virtual void    onCommit();
+    virtual bool    handleUnicodeCharHere(llwchar uni_char) override;
+    virtual bool    handleKeyHere(KEY key, MASK mask) override;
+    virtual bool    handleMouseDown(S32 x, S32 y, MASK mask) override;
+    virtual bool    handleMouseUp(S32 x, S32 y, MASK mask) override;
+    virtual bool    handleHover(S32 x, S32 y, MASK mask) override;
+    virtual bool    handleRightMouseDown(S32 x, S32 y, MASK mask) override;
+    virtual bool    handleRightMouseUp(S32 x, S32 y, MASK mask) override;
+    virtual bool    handleDoubleClick(S32 x, S32 y, MASK mask) override;
+    virtual void    draw() override;
+    /*virtual*/ bool postBuild()  override;
+
+    void onVisibilityChange(bool visible) override;
+    void reshape(S32 width, S32 height, bool called_from_parent = true) override;
+    void translate(S32 x, S32 y) override;
+    void setRect(const LLRect& rect) override;
+    void dirtyRect() override;
+
+    virtual void    onMouseLeave(S32 x, S32 y, MASK mask) override;
+    virtual void    onMouseCaptureLost() override;
+
+    virtual void    onCommit() override;
 
     void            setUnselectedLabelColor(const LLUIColor& c);
     void            setSelectedLabelColor(const LLUIColor& c);
@@ -227,7 +231,7 @@ public:
     const std::string   getLabelSelected() const { return wstring_to_utf8str(mSelectedLabel); }
 
     void            setImageColor(const LLUIColor& c);
-    /*virtual*/ void    setColor(const LLUIColor& c);
+    /*virtual*/ void    setColor(const LLUIColor& c) override;
 
     void            setImages(const std::string &image_name, const std::string &selected_name);
 
@@ -245,13 +249,12 @@ public:
     void            setLabel(const std::string& label);
     void            setLabel(const LLUIString& label);
     void            setLabel( const LLStringExplicit& label);
-    virtual bool    setLabelArg( const std::string& key, const LLStringExplicit& text );
+    virtual bool    setLabelArg( const std::string& key, const LLStringExplicit& text ) override;
     void            setLabelUnselected(const LLStringExplicit& label);
     void            setLabelSelected(const LLStringExplicit& label);
-    void            setDisabledLabelColor( const LLUIColor& c )      { mDisabledLabelColor = c; }
+    void            setDisabledLabelColor(const LLUIColor& c);
 
-    void            setFont(const LLFontGL *font)
-        { mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); }
+    void            setFont(const LLFontGL* font);
     const LLFontGL* getFont() const { return mGLFont; }
     const std::string& getText() const { return getCurrentLabel().getString(); }
 
@@ -262,7 +265,7 @@ public:
     void            setScaleImage(bool scale)           { mScaleImage = scale; }
     bool            getScaleImage() const               { return mScaleImage; }
 
-    void            setDropShadowedText(bool b)         { mDropShadowedText = b; }
+    void            setDropShadowedText(bool b);
 
     void            setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; }
 
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 0c56582ea6..19ae35813c 100644
--- a/indra/newview/llhudnametag.cpp
+++ b/indra/newview/llhudnametag.cpp
@@ -290,6 +290,15 @@ void LLHUDNameTag::renderText()
     LLVector3 render_position = mPositionAgent
             + (x_pixel_vec * screen_offset.mV[VX])
             + (y_pixel_vec * screen_offset.mV[VY]);
+    bool reset_buffers = false;
+    const F32 treshold = 0.000001f;
+    if (abs(mLastRenderPosition.mV[VX] - render_position.mV[VX]) > treshold
+        || abs(mLastRenderPosition.mV[VY] - render_position.mV[VY]) > treshold
+        || abs(mLastRenderPosition.mV[VZ] - render_position.mV[VZ]) > treshold)
+    {
+        reset_buffers = true;
+        mLastRenderPosition = render_position;
+    }
 
     LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
     LLRect screen_rect;
@@ -313,6 +322,11 @@ void LLHUDNameTag::renderText()
         for(std::vector<LLHUDTextSegment>::iterator segment_iter = mLabelSegments.begin();
             segment_iter != mLabelSegments.end(); ++segment_iter )
         {
+            if (reset_buffers)
+            {
+                segment_iter->mFontBufferLabel.reset();
+            }
+
             // Label segments use default font
             const LLFontGL* fontp = (segment_iter->mStyle == LLFontGL::BOLD) ? mBoldFontp : mFontp;
             y_offset -= fontp->getLineHeight();
@@ -350,6 +364,11 @@ void LLHUDNameTag::renderText()
         for (std::vector<LLHUDTextSegment>::iterator segment_iter = mTextSegments.begin() + start_segment;
              segment_iter != mTextSegments.end(); ++segment_iter )
         {
+            if (reset_buffers)
+            {
+                segment_iter->mFontBufferText.reset();
+            }
+
             const LLFontGL* fontp = segment_iter->mFont;
             y_offset -= fontp->getLineHeight();
             y_offset -= LINE_PADDING;
diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h
index ee315f47af..b48a606982 100644
--- a/indra/newview/llhudnametag.h
+++ b/indra/newview/llhudnametag.h
@@ -177,6 +177,7 @@ private:
     S32             mMaxLines;
     S32             mOffsetY;
     F32             mRadius;
+    LLVector3                     mLastRenderPosition;
     std::vector<LLHUDTextSegment> mTextSegments;
     std::vector<LLHUDTextSegment> mLabelSegments;
 //  LLFrameTimer    mResizeTimer;
-- 
cgit v1.2.3