Quellcode durchsuchen

Use a vertex buffer for UI rendering instead of several immediate mode draw operations. The vertex buffer is locked and updated once per frame, instead of several smaller locks.

Lasse Öörni vor 14 Jahren
Ursprung
Commit
71d2e019e6
5 geänderte Dateien mit 82 neuen und 53 gelöschten Zeilen
  1. 1 1
      Docs/Reference.dox
  2. 51 10
      Engine/UI/UI.cpp
  3. 3 0
      Engine/UI/UI.h
  4. 25 40
      Engine/UI/UIBatch.cpp
  5. 2 2
      Engine/UI/UIBatch.h

+ 1 - 1
Docs/Reference.dox

@@ -367,7 +367,7 @@ Graphics implements the low-level functionality:
 - Handling lost device
 - Handling lost device
 - Performing primitive rendering operations
 - Performing primitive rendering operations
 
 
-It also provides a low-performance, immediate-like interface for manually defining small amounts of geometry to be rendered. This interface is used for rendering the debug geometry and the user interface.
+It also provides a low-performance, immediate-like interface for manually defining small amounts of geometry to be rendered. This interface is used for rendering the debug geometry.
 
 
 Screen resolution, fullscreen/windowed, vertical sync and hardware multisampling level are all set at once by calling Graphics's \ref Graphics::SetMode "SetMode()" function.
 Screen resolution, fullscreen/windowed, vertical sync and hardware multisampling level are all set at once by calling Graphics's \ref Graphics::SetMode "SetMode()" function.
 
 

+ 51 - 10
Engine/UI/UI.cpp

@@ -46,6 +46,7 @@
 #include "Texture2D.h"
 #include "Texture2D.h"
 #include "UI.h"
 #include "UI.h"
 #include "UIEvents.h"
 #include "UIEvents.h"
+#include "VertexBuffer.h"
 #include "Window.h"
 #include "Window.h"
 
 
 #include "Sort.h"
 #include "Sort.h"
@@ -220,12 +221,37 @@ void UI::RenderUpdate()
     if (!rootElement_ || !graphics_ || graphics_->IsDeviceLost())
     if (!rootElement_ || !graphics_ || graphics_->IsDeviceLost())
         return;
         return;
     
     
-    PROFILE(GetUIBatches);
+    {
+        PROFILE(GetUIBatches);
+        
+        // Get batches & quads from the UI elements
+        batches_.Clear();
+        quads_.Clear();
+        const IntVector2& rootSize = rootElement_->GetSize();
+        GetBatches(rootElement_, IntRect(0, 0, rootSize.x_, rootSize.y_));
+    }
     
     
-    batches_.Clear();
-    quads_.Clear();
-    const IntVector2& rootSize = rootElement_->GetSize();
-    GetBatches(rootElement_, IntRect(0, 0, rootSize.x_, rootSize.y_));
+    {
+        PROFILE(UpdateUIGeometry);
+        
+        // Update quad geometry into the vertex buffer
+        unsigned numVertices = quads_.Size() * 6;
+        if (numVertices)
+        {
+            if (vertexBuffer_->GetVertexCount() < numVertices)
+                vertexBuffer_->SetSize(numVertices, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1, true);
+        
+            unsigned vertexSize = vertexBuffer_->GetVertexSize();
+            unsigned char* lockedData = (unsigned char*)vertexBuffer_->Lock(0, numVertices, LOCK_DISCARD);
+        
+            if (lockedData)
+            {
+                for (unsigned i = 0; i < batches_.Size(); ++i)
+                    batches_[i].UpdateGeometry(graphics_, lockedData + 6 * batches_[i].quadStart_ * vertexSize);
+                vertexBuffer_->Unlock();
+            }
+        }
+    }
     
     
     // If no drag, reset cursor shape for next frame
     // If no drag, reset cursor shape for next frame
     if (cursor_ && !dragElement_)
     if (cursor_ && !dragElement_)
@@ -259,6 +285,7 @@ void UI::Render()
     graphics_->SetDepthWrite(false);
     graphics_->SetDepthWrite(false);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetStencilTest(false);
     graphics_->SetStencilTest(false);
+    graphics_->SetVertexBuffer(vertexBuffer_);
     
     
     ShaderVariation* ps = 0;
     ShaderVariation* ps = 0;
     ShaderVariation* vs = 0;
     ShaderVariation* vs = 0;
@@ -267,18 +294,21 @@ void UI::Render()
     
     
     for (unsigned i = 0; i < batches_.Size(); ++i)
     for (unsigned i = 0; i < batches_.Size(); ++i)
     {
     {
-        // Choose shaders here so that UIBatch does not need to look up shaders each time
-        if (!batches_[i].texture_)
+        const UIBatch& batch = batches_[i];
+        if (!batch.quadCount_)
+            continue;
+        
+        if (!batch.texture_)
         {
         {
             ps = noTexturePS_;
             ps = noTexturePS_;
             vs = noTextureVS_;
             vs = noTextureVS_;
         }
         }
         else
         else
         {
         {
-            // If texture contains only an alpha channel, interpret it as alpha (for fonts)
+            // If texture contains only an alpha channel, use alpha shader (for fonts)
             vs = diffTextureVS_;
             vs = diffTextureVS_;
             
             
-            if (batches_[i].texture_->GetFormat() == alphaFormat)
+            if (batch.texture_->GetFormat() == alphaFormat)
                 ps = alphaTexturePS_;
                 ps = alphaTexturePS_;
             else
             else
                 ps = diffTexturePS_;
                 ps = diffTexturePS_;
@@ -292,7 +322,16 @@ void UI::Render()
         if (graphics_->NeedParameterUpdate(PSP_MATDIFFCOLOR, this))
         if (graphics_->NeedParameterUpdate(PSP_MATDIFFCOLOR, this))
             graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
             graphics_->SetShaderParameter(PSP_MATDIFFCOLOR, Color(1.0f, 1.0f, 1.0f, 1.0f));
         
         
-        batches_[i].Draw(graphics_);
+        // Use alpha test if not alpha blending
+        if (batch.blendMode_ != BLEND_ALPHA && batch.blendMode_ != BLEND_ADDALPHA && batch.blendMode_ != BLEND_PREMULALPHA)
+            graphics_->SetAlphaTest(true, CMP_GREATEREQUAL, 0.5f);
+        else
+            graphics_->SetAlphaTest(false);
+        
+        graphics_->SetBlendMode(batch.blendMode_);
+        graphics_->SetScissorTest(true, batch.scissor_);
+        graphics_->SetTexture(0, batch.texture_);
+        graphics_->Draw(TRIANGLE_LIST, batch.quadStart_ * 6, batch.quadCount_ * 6);
     }
     }
 }
 }
 
 
@@ -433,6 +472,8 @@ void UI::Initialize()
         alphaTexturePS_ = basicPS->GetVariation("AlphaVCol");
         alphaTexturePS_ = basicPS->GetVariation("AlphaVCol");
     }
     }
     
     
+    vertexBuffer_ = new VertexBuffer(context_);
+    
     LOGINFO("Initialized user interface");
     LOGINFO("Initialized user interface");
     initialized_ = true;
     initialized_ = true;
 }
 }

+ 3 - 0
Engine/UI/UI.h

@@ -31,6 +31,7 @@ class Graphics;
 class ResourceCache;
 class ResourceCache;
 class UIBatch;
 class UIBatch;
 class UIElement;
 class UIElement;
+class VertexBuffer;
 class XMLElement;
 class XMLElement;
 class XMLFile;
 class XMLFile;
 
 
@@ -139,6 +140,8 @@ private:
     PODVector<UIBatch> batches_;
     PODVector<UIBatch> batches_;
     /// UI rendering quads.
     /// UI rendering quads.
     PODVector<UIQuad> quads_;
     PODVector<UIQuad> quads_;
+    /// UI vertex buffer.
+    SharedPtr<VertexBuffer> vertexBuffer_;
     /// Clipboard text.
     /// Clipboard text.
     String clipBoard_;
     String clipBoard_;
     /// Mouse buttons held down.
     /// Mouse buttons held down.

+ 25 - 40
Engine/UI/UIBatch.cpp

@@ -165,21 +165,11 @@ bool UIBatch::Merge(const UIBatch& batch)
     return true;
     return true;
 }
 }
 
 
-void UIBatch::Draw(Graphics* graphics) const
+void UIBatch::UpdateGeometry(Graphics* graphics, void* lockedData)
 {
 {
-    if (!quads_ || !quadCount_)
+    if (!quadCount_)
         return;
         return;
     
     
-    // Use alpha test if not alpha blending
-    if (blendMode_ != BLEND_ALPHA && blendMode_ != BLEND_ADDALPHA && blendMode_ != BLEND_PREMULALPHA)
-        graphics->SetAlphaTest(true, CMP_GREATEREQUAL, 0.5f);
-    else
-        graphics->SetAlphaTest(false);
-    
-    graphics->SetBlendMode(blendMode_);
-    graphics->SetScissorTest(true, scissor_);
-    graphics->SetTexture(0, texture_);
-    
     #ifdef USE_OPENGL
     #ifdef USE_OPENGL
     Vector2 posAdjust(Vector2::ZERO);
     Vector2 posAdjust(Vector2::ZERO);
     #else
     #else
@@ -187,18 +177,15 @@ void UIBatch::Draw(Graphics* graphics) const
     #endif
     #endif
     Vector2 invScreenSize(1.0f / (float)graphics->GetWidth(), 1.0f / (float)graphics->GetHeight());
     Vector2 invScreenSize(1.0f / (float)graphics->GetWidth(), 1.0f / (float)graphics->GetHeight());
     
     
-    const PODVector<UIQuad>& quads = *quads_;
+    float* dest = (float*)lockedData;
     
     
     if (texture_)
     if (texture_)
     {
     {
         Vector2 invTextureSize(1.0f / (float)texture_->GetWidth(), 1.0f / (float)texture_->GetHeight());
         Vector2 invTextureSize(1.0f / (float)texture_->GetWidth(), 1.0f / (float)texture_->GetHeight());
         
         
-        graphics->BeginImmediate(TRIANGLE_LIST, quadCount_ * 6, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1);
-        float* dest = (float*)graphics->GetImmediateDataPtr();
-        
-        for (unsigned i = quadStart_; i < quadStart_ + quadCount_; ++i)
+        for (unsigned i = 0; i < quadCount_; ++i)
         {
         {
-            const UIQuad& quad = quads[i];
+            const UIQuad& quad = quads_->At(quadStart_ + i);
             Vector2 topLeft, bottomRight, topLeftUV, bottomRightUV;
             Vector2 topLeft, bottomRight, topLeftUV, bottomRightUV;
             
             
             topLeft = (Vector2((float)quad.left_, (float)quad.top_) - posAdjust) * invScreenSize;
             topLeft = (Vector2((float)quad.left_, (float)quad.top_) - posAdjust) * invScreenSize;
@@ -207,66 +194,64 @@ void UIBatch::Draw(Graphics* graphics) const
             bottomRightUV = Vector2((float)quad.rightUV_, (float)quad.bottomUV_) * invTextureSize;
             bottomRightUV = Vector2((float)quad.rightUV_, (float)quad.bottomUV_) * invTextureSize;
             
             
             *dest++ = topLeft.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
             *dest++ = topLeft.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].topLeftColor_; dest++;
+            *((unsigned*)dest) = quad.topLeftColor_; dest++;
             *dest++ = topLeftUV.x_; *dest++ = topLeftUV.y_;
             *dest++ = topLeftUV.x_; *dest++ = topLeftUV.y_;
             
             
             *dest++ = bottomRight.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
             *dest++ = bottomRight.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].topRightColor_; dest++;
+            *((unsigned*)dest) = quad.topRightColor_; dest++;
             *dest++ = bottomRightUV.x_; *dest++ = topLeftUV.y_;
             *dest++ = bottomRightUV.x_; *dest++ = topLeftUV.y_;
             
             
             *dest++ = topLeft.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
             *dest++ = topLeft.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].bottomLeftColor_; dest++;
+            *((unsigned*)dest) = quad.bottomLeftColor_; dest++;
             *dest++ = topLeftUV.x_; *dest++ = bottomRightUV.y_;
             *dest++ = topLeftUV.x_; *dest++ = bottomRightUV.y_;
             
             
             *dest++ = bottomRight.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
             *dest++ = bottomRight.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
-
-            *((unsigned*)dest) = quads[i].topRightColor_; dest++;
+            *((unsigned*)dest) = quad.topRightColor_; dest++;
             *dest++ = bottomRightUV.x_; *dest++ = topLeftUV.y_;
             *dest++ = bottomRightUV.x_; *dest++ = topLeftUV.y_;
             
             
             *dest++ = bottomRight.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
             *dest++ = bottomRight.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].bottomRightColor_; dest++;
+            *((unsigned*)dest) = quad.bottomRightColor_; dest++;
             *dest++ = bottomRightUV.x_; *dest++ = bottomRightUV.y_;
             *dest++ = bottomRightUV.x_; *dest++ = bottomRightUV.y_;
             
             
             *dest++ = topLeft.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
             *dest++ = topLeft.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].bottomLeftColor_; dest++;
+            *((unsigned*)dest) = quad.bottomLeftColor_; dest++;
             *dest++ = topLeftUV.x_; *dest++ = bottomRightUV.y_;
             *dest++ = topLeftUV.x_; *dest++ = bottomRightUV.y_;
         }
         }
-        
-        graphics->EndImmediate();
     }
     }
     else
     else
     {
     {
-        graphics->BeginImmediate(TRIANGLE_LIST, quadCount_ * 6, MASK_POSITION | MASK_COLOR);
-        float* dest = (float*)graphics->GetImmediateDataPtr();
-        
-        for (unsigned i = quadStart_; i < quadStart_ + quadCount_; ++i)
+        for (unsigned i = 0; i < quadCount_; ++i)
         {
         {
-            const UIQuad& quad = quads[i];
+            const UIQuad& quad = quads_->At(quadStart_ + i);
             Vector2 topLeft, bottomRight, topLeftUV, bottomRightUV;
             Vector2 topLeft, bottomRight, topLeftUV, bottomRightUV;
             
             
             topLeft = (Vector2((float)quad.left_, (float)quad.top_) - posAdjust) * invScreenSize;
             topLeft = (Vector2((float)quad.left_, (float)quad.top_) - posAdjust) * invScreenSize;
             bottomRight = (Vector2((float)quad.right_, (float)quad.bottom_) - posAdjust) * invScreenSize;
             bottomRight = (Vector2((float)quad.right_, (float)quad.bottom_) - posAdjust) * invScreenSize;
             
             
             *dest++ = topLeft.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
             *dest++ = topLeft.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].topLeftColor_; dest++;
+            *((unsigned*)dest) = quad.topLeftColor_; dest++;
+            dest += 2; // Jump over unused UV coordinates
             
             
             *dest++ = bottomRight.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
             *dest++ = bottomRight.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].topRightColor_; dest++;
+            *((unsigned*)dest) = quad.topRightColor_; dest++;
+            dest += 2;
             
             
             *dest++ = topLeft.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
             *dest++ = topLeft.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].bottomLeftColor_; dest++;
+            *((unsigned*)dest) = quad.bottomLeftColor_; dest++;
+            dest += 2;
             
             
             *dest++ = bottomRight.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
             *dest++ = bottomRight.x_; *dest++ = topLeft.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].topRightColor_; dest++;
+            *((unsigned*)dest) = quad.topRightColor_; dest++;
+            dest += 2;
             
             
             *dest++ = bottomRight.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
             *dest++ = bottomRight.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].bottomRightColor_; dest++;
+            *((unsigned*)dest) = quad.bottomRightColor_; dest++;
+            dest += 2;
             
             
             *dest++ = topLeft.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
             *dest++ = topLeft.x_; *dest++ = bottomRight.y_; *dest++ = 0.0f;
-            *((unsigned*)dest) = quads[i].bottomLeftColor_; dest++;
+            *((unsigned*)dest) = quad.bottomLeftColor_; dest++;
+            dest += 2;
         }
         }
-        
-        graphics->EndImmediate();
     }
     }
 }
 }
 
 

+ 2 - 2
Engine/UI/UIBatch.h

@@ -85,8 +85,8 @@ public:
     void AddQuad(UIElement& element, int x, int y, int width, int height, int texOffsetX, int texOffsetY, int texWidth, int texHeight, const Color& color);
     void AddQuad(UIElement& element, int x, int y, int width, int height, int texOffsetX, int texOffsetY, int texWidth, int texHeight, const Color& color);
     /// Merge with another batch.
     /// Merge with another batch.
     bool Merge(const UIBatch& batch);
     bool Merge(const UIBatch& batch);
-    /// Draw.
-    void Draw(Graphics* graphics) const;
+    /// Update the vertex data.
+    void UpdateGeometry(Graphics* graphics, void* lockedData);
     
     
     /// Add or merge a batch.
     /// Add or merge a batch.
     static void AddOrMerge(const UIBatch& batch, PODVector<UIBatch>& batches);
     static void AddOrMerge(const UIBatch& batch, PODVector<UIBatch>& batches);