Browse Source

Time-based removal of unused occlusion and screen buffers.
Renamed RenderBuffer to ScreenBuffer to not clash with OpenGL terminology.

Lasse Öörni 14 years ago
parent
commit
1f45d256f4

+ 1 - 1
Engine/Graphics/Batch.cpp

@@ -227,7 +227,7 @@ void Batch::Prepare(Graphics* graphics, Renderer* renderer, bool setModelTransfo
         float heightRange = 0.5f * (viewport.bottom_ - viewport.top_) / rtHeight;
         
         #ifdef USE_OPENGL
-        Vector4 bufferUVOffset(((float)viewport.left_) / rttWidth + widthRange,
+        Vector4 bufferUVOffset(((float)viewport.left_) / rtWidth + widthRange,
             1.0f - (((float)viewport.top_) / rtHeight + heightRange), widthRange, heightRange);
         #else
         Vector4 bufferUVOffset((0.5f + (float)viewport.left_) / rtWidth + widthRange,

+ 10 - 0
Engine/Graphics/OcclusionBuffer.cpp

@@ -303,6 +303,11 @@ void OcclusionBuffer::BuildDepthHierarchy()
     depthHierarchyDirty_ = false;
 }
 
+void OcclusionBuffer::ResetUseTimer()
+{
+    useTimer_.Reset();
+}
+
 bool OcclusionBuffer::IsVisible(const BoundingBox& worldSpaceBox) const
 {
     if (!buffer_)
@@ -428,6 +433,11 @@ bool OcclusionBuffer::IsVisible(const BoundingBox& worldSpaceBox) const
     return false;
 }
 
+unsigned OcclusionBuffer::GetUseTimer()
+{
+    return useTimer_.GetMSec(false);
+}
+
 inline Vector4 OcclusionBuffer::ModelTransform(const Matrix4& transform, const Vector3& vertex) const
 {
     return Vector4(

+ 7 - 0
Engine/Graphics/OcclusionBuffer.h

@@ -27,6 +27,7 @@
 #include "Frustum.h"
 #include "Object.h"
 #include "GraphicsDefs.h"
+#include "Timer.h"
 
 class BoundingBox;
 class Camera;
@@ -78,6 +79,8 @@ public:
     bool Draw(const Matrix3x4& model, const void* vertexData, unsigned vertexSize, const void* indexData, unsigned indexSize, unsigned indexStart, unsigned indexCount);
     /// Build reduced size mip levels.
     void BuildDepthHierarchy();
+    /// Reset last used timer.
+    void ResetUseTimer();
     
     /// Return highest level depth values.
     int* GetBuffer() const { return buffer_; }
@@ -97,6 +100,8 @@ public:
     CullMode GetCullMode() const { return cullMode_; }
     /// Test a bounding box for visibility. For best performance, build depth hierarchy first.
     bool IsVisible(const BoundingBox& worldSpaceBox) const;
+    /// Return time since last use in milliseconds.
+    unsigned GetUseTimer();
     
 private:
     /// Apply modelview transform to vertex.
@@ -136,6 +141,8 @@ private:
     Matrix4 projection_;
     /// Combined view and projection matrix.
     Matrix4 viewProj_;
+    /// Last used timer.
+    Timer useTimer_;
     /// Near clip distance.
     float nearClip_;
     /// Far clip distance.

+ 80 - 57
Engine/Graphics/Renderer.cpp

@@ -255,6 +255,7 @@ static const String lightPSVariations[] =
 };
 
 static const unsigned INSTANCING_BUFFER_MASK = MASK_INSTANCEMATRIX1 | MASK_INSTANCEMATRIX2 | MASK_INSTANCEMATRIX3;
+static const unsigned MAX_BUFFER_AGE = 2000;
 static const Viewport noViewport;
 
 void EdgeFilterParameters::Validate()
@@ -642,17 +643,13 @@ void Renderer::Render()
     
     PROFILE(RenderViews);
     
-    // Remove unused buffers from last frame
-    ResetRenderBufferAllocations(true);
-    
     graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
     graphics_->SetTextureAnisotropy(textureAnisotropy_);
+    graphics_->ClearParameterSources();
     
     // If no views, just clear the screen
     if (!numViews_)
     {
-        numPrimitives_ = 0;
-        numBatches_ = 0;
         graphics_->SetAlphaTest(false);
         graphics_->SetBlendMode(BLEND_REPLACE);
         graphics_->SetColorWrite(true);
@@ -660,21 +657,31 @@ void Renderer::Render()
         graphics_->SetFillMode(FILL_SOLID);
         graphics_->SetScissorTest(false);
         graphics_->SetStencilTest(false);
+        graphics_->ResetRenderTargets();
+        graphics_->ResetDepthStencil();
+        graphics_->SetViewport(IntRect(0, 0, graphics_->GetWidth(), graphics_->GetHeight()));
         graphics_->Clear(CLEAR_COLOR | CLEAR_DEPTH | CLEAR_STENCIL);
-        return;
+        
+        numPrimitives_ = 0;
+        numBatches_ = 0;
     }
-    
-    // Render views from last to first (each main view is rendered after the auxiliary views it depends on)
-    for (unsigned i = numViews_ - 1; i < numViews_; --i)
+    else
     {
-        // Buffers can be reused between views, as each is rendered completely
-        ResetRenderBufferAllocations();
-        views_[i]->Render();
+        // Render views from last to first (each main view is rendered after the auxiliary views it depends on)
+        for (unsigned i = numViews_ - 1; i < numViews_; --i)
+        {
+            // Screen buffers can be reused between views, as each is rendered completely
+            ResetScreenBufferAllocations();
+            views_[i]->Render();
+        }
+        
+        // Copy the number of batches & primitives from Graphics so that we can account for 3D geometry only
+        numPrimitives_ = graphics_->GetNumPrimitives();
+        numBatches_ = graphics_->GetNumBatches();
     }
     
-    // Copy the number of batches & primitives from Graphics so that we can account for 3D geometry only
-    numPrimitives_ = graphics_->GetNumPrimitives();
-    numBatches_ = graphics_->GetNumBatches();
+    // Remove unused occlusion buffers and renderbuffers
+    RemoveUnusedBuffers();
 }
 
 void Renderer::DrawDebugGeometry(bool depthTest)
@@ -899,7 +906,7 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
     return newShadowMap;
 }
 
-Texture2D* Renderer::GetRenderBuffer(int width, int height, unsigned format, bool filtered)
+Texture2D* Renderer::GetScreenBuffer(int width, int height, unsigned format, bool filtered)
 {
     bool depthStencil = (format == Graphics::GetDepthStencilFormat());
     if (depthStencil)
@@ -917,42 +924,38 @@ Texture2D* Renderer::GetRenderBuffer(int width, int height, unsigned format, boo
             return depthTexture;
     }
     
-    bool needNew = false;
-    
     // If new size or format, initialize the allocation stats
-    if (renderBuffers_.Find(searchKey) == renderBuffers_.End())
-    {
-        renderBufferAllocations_[searchKey] = 0;
-        renderBufferMaxAllocations_[searchKey] = 0;
-    }
+    if (screenBuffers_.Find(searchKey) == screenBuffers_.End())
+        screenBufferAllocations_[searchKey] = 0;
     
-    unsigned& allocations = renderBufferAllocations_[searchKey];
-    unsigned& maxAllocations = renderBufferMaxAllocations_[searchKey];
-    ++allocations;
-    if (allocations > maxAllocations)
-        maxAllocations = allocations;
-    
-    if (allocations > renderBuffers_[searchKey].Size())
+    unsigned allocations = screenBufferAllocations_[searchKey]++;
+    if (allocations >= screenBuffers_[searchKey].Size())
     {
         SharedPtr<Texture2D> newBuffer(new Texture2D(context_));
         newBuffer->SetSize(width, height, format, depthStencil ? TEXTURE_DEPTHSTENCIL : TEXTURE_RENDERTARGET);
         if (filtered)
             newBuffer->SetFilterMode(FILTER_BILINEAR);
-        renderBuffers_[searchKey].Push(newBuffer);
-        LOGDEBUG("Allocated new renderbuffer size " + String(width) + "x" + String(height) + " format " + String(format));
+        newBuffer->ResetUseTimer();
+        screenBuffers_[searchKey].Push(newBuffer);
+        LOGDEBUG("Allocated new screen buffer size " + String(width) + "x" + String(height) + " format " + String(format));
         return newBuffer;
     }
     else
-        return renderBuffers_[searchKey][allocations - 1];
+    {
+        Texture2D* buffer = screenBuffers_[searchKey][allocations];
+        buffer->ResetUseTimer();
+        return buffer;
+    }
 }
 
 RenderSurface* Renderer::GetDepthStencil(int width, int height)
 {
     // Return the default depth-stencil surface if applicable
+    // (when using OpenGL Graphics will allocate right size surfaces on demand to emulate Direct3D9)
     if (width <= graphics_->GetWidth() && height <= graphics_->GetHeight())
         return 0;
     else
-        return GetRenderBuffer(width, height, Graphics::GetDepthStencilFormat())->GetRenderSurface();
+        return GetScreenBuffer(width, height, Graphics::GetDepthStencilFormat())->GetRenderSurface();
 }
 
 OcclusionBuffer* Renderer::GetOcclusionBuffer(Camera* camera)
@@ -969,6 +972,7 @@ OcclusionBuffer* Renderer::GetOcclusionBuffer(Camera* camera)
     OcclusionBuffer* buffer = occlusionBuffers_[numOcclusionBuffers_];
     buffer->SetSize(width, height);
     buffer->SetView(camera);
+    buffer->ResetUseTimer();
     
     ++numOcclusionBuffers_;
     return buffer;
@@ -1229,36 +1233,47 @@ bool Renderer::ResizeInstancingBuffer(unsigned numInstances)
     return true;
 }
 
-void Renderer::ResetShadowMapAllocations()
-{
-    for (HashMap<int, PODVector<Light*> >::Iterator i = shadowMapAllocations_.Begin(); i != shadowMapAllocations_.End(); ++i)
-        i->second_.Clear();
-}
-
-void Renderer::ResetRenderBufferAllocations(bool remove)
+void Renderer::RemoveUnusedBuffers()
 {
-    // Optionally remove buffers that were not used at all
-    if (remove)
+    for (unsigned i = occlusionBuffers_.Size() - 1; i < occlusionBuffers_.Size(); --i)
     {
-        for (HashMap<long long, unsigned>::Iterator i = renderBufferMaxAllocations_.Begin(); i != renderBufferMaxAllocations_.End();)
+        if (occlusionBuffers_[i]->GetUseTimer() > MAX_BUFFER_AGE)
         {
-            HashMap<long long, unsigned>::Iterator current = i++;
-            if (!current->second_)
-            {
-                renderBuffers_.Erase(current->first_);
-                renderBufferAllocations_.Erase(current->first_);
-                renderBufferMaxAllocations_.Erase(current);
-            }
-            else
+            LOGDEBUG("Removed unused occlusion buffer");
+            occlusionBuffers_.Erase(i);
+        }
+    }
+    
+    for (HashMap<long long, Vector<SharedPtr<Texture2D> > >::Iterator i = screenBuffers_.Begin(); i != screenBuffers_.End();)
+    {
+        HashMap<long long, Vector<SharedPtr<Texture2D> > >::Iterator current = i++;
+        Vector<SharedPtr<Texture2D> >& buffers = current->second_;
+        for (unsigned j = buffers.Size() - 1; j < buffers.Size(); --j)
+        {
+            Texture2D* buffer = buffers[j];
+            if (buffer->GetUseTimer() > MAX_BUFFER_AGE)
             {
-                renderBuffers_[current->first_].Resize(current->second_);
-                current->second_ = 0;
+                LOGDEBUG("Removed unused screen buffer size " + String(buffer->GetWidth()) + "x" + String(buffer->GetHeight()) + " format " + String(buffer->GetFormat()));
+                buffers.Erase(j);
             }
         }
+        if (buffers.Empty())
+        {
+            screenBufferAllocations_.Erase(current->first_);
+            screenBuffers_.Erase(current);
+        }
     }
-    
-    // Then reset allocation value of remaining buffer sizes
-    for (HashMap<long long, unsigned>::Iterator i = renderBufferAllocations_.Begin(); i != renderBufferAllocations_.End(); ++i)
+}
+
+void Renderer::ResetShadowMapAllocations()
+{
+    for (HashMap<int, PODVector<Light*> >::Iterator i = shadowMapAllocations_.Begin(); i != shadowMapAllocations_.End(); ++i)
+        i->second_.Clear();
+}
+
+void Renderer::ResetScreenBufferAllocations()
+{
+    for (HashMap<long long, unsigned>::Iterator i = screenBufferAllocations_.Begin(); i != screenBufferAllocations_.End(); ++i)
         i->second_ = 0;
 }
 
@@ -1311,6 +1326,7 @@ void Renderer::Initialize()
     viewports_.Resize(1);
     ResetViews();
     ResetShadowMaps();
+    ResetBuffers();
     
     shadersDirty_ = true;
     initialized_ = true;
@@ -1631,6 +1647,13 @@ void Renderer::ResetShadowMaps()
     colorShadowMaps_.Clear();
 }
 
+void Renderer::ResetBuffers()
+{
+    occlusionBuffers_.Clear();
+    screenBuffers_.Clear();
+    screenBufferAllocations_.Clear();
+}
+
 void Renderer::HandleScreenMode(StringHash eventType, VariantMap& eventData)
 {
     if (!initialized_)

+ 9 - 7
Engine/Graphics/Renderer.h

@@ -328,7 +328,7 @@ public:
     /// Allocate a shadow map. If shadow map reuse is disabled, a different map is returned each time.
     Texture2D* GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight);
     /// Allocate a rendertarget or depth-stencil texture for light pre-pass rendering or postprocessing. Should only be called during actual rendering, not before.
-    Texture2D* GetRenderBuffer(int width, int height, unsigned format, bool filtered = false);
+    Texture2D* GetScreenBuffer(int width, int height, unsigned format, bool filtered = false);
     /// Allocate a depth-stencil surface that does not need to be readable. Should only be called during actual rendering, not before.
     RenderSurface* GetDepthStencil(int width, int height);
     /// Allocate an occlusion buffer.
@@ -365,12 +365,16 @@ private:
     void CreateGeometries();
     /// Create instancing vertex buffer.
     void CreateInstancingBuffer();
+    /// Remove unused occlusion and screen buffers.
+    void RemoveUnusedBuffers();
     /// Reset shadow map allocation counts.
     void ResetShadowMapAllocations();
-    /// Reset renderbuffer allocation counts. Optionally also remove buffers which were not requested at all during last frame.
-    void ResetRenderBufferAllocations(bool remove = false);
+    /// Reset screem buffer allocation counts.
+    void ResetScreenBufferAllocations();
     /// Remove all shadow maps. Called when global shadow map resolution or format is changed.
     void ResetShadowMaps();
+    /// Remove all occlusion and screen buffers.
+    void ResetBuffers();
     /// Handle screen mode event.
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
     /// Handle graphics features (re)check event.
@@ -421,11 +425,9 @@ private:
     /// Shadow map allocations by resolution.
     HashMap<int, PODVector<Light*> > shadowMapAllocations_;
     /// Renderbuffers by resolution and format.
-    HashMap<long long, Vector<SharedPtr<Texture2D> > > renderBuffers_;
+    HashMap<long long, Vector<SharedPtr<Texture2D> > > screenBuffers_;
     /// Renderbuffer current allocations by resolution and format.
-    HashMap<long long, unsigned> renderBufferAllocations_;
-    /// Renderbuffer maximum allocations by resolution and format.
-    HashMap<long long, unsigned> renderBufferMaxAllocations_;
+    HashMap<long long, unsigned> screenBufferAllocations_;
     /// Viewports.
     Vector<Viewport> viewports_;
     /// Views.

+ 9 - 8
Engine/Graphics/View.cpp

@@ -203,8 +203,8 @@ bool View::Define(RenderSurface* renderTarget, const Viewport& viewport)
     #ifdef USE_OPENGL
     if (renderTarget_)
     {
-        viewRect_.bottom_ = rtSize_.y - viewRect_.top_;
-        viewRect_.top_ = viewRect.bottom_ - viewSize_.y;
+        viewRect_.bottom_ = rtSize_.y_ - viewRect_.top_;
+        viewRect_.top_ = viewRect_.bottom_ - viewSize_.y_;
     }
     #endif
     
@@ -970,7 +970,7 @@ void View::RenderBatchesForward()
     
     bool needBlit = edgeFilter_;
     if (needBlit)
-        screenBuffer_ = renderer_->GetRenderBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBFormat(), true);
+        screenBuffer_ = renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBFormat(), true);
     RenderSurface* renderTarget = needBlit ? screenBuffer_->GetRenderSurface() : renderTarget_;
     RenderSurface* depthStencil = GetDepthStencil(renderTarget);
     
@@ -1065,10 +1065,10 @@ void View::RenderBatchesLightPrepass()
     }
     
     bool hwDepth = graphics_->GetHardwareDepthSupport();
-    Texture2D* normalBuffer = renderer_->GetRenderBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBAFormat());
-    Texture2D* depthBuffer = renderer_->GetRenderBuffer(rtSize_.x_, rtSize_.y_, hwDepth ? Graphics::GetDepthStencilFormat() :
+    Texture2D* normalBuffer = renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBAFormat());
+    Texture2D* lightBuffer = renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBAFormat());
+    Texture2D* depthBuffer = renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, hwDepth ? Graphics::GetDepthStencilFormat() :
         Graphics::GetLinearDepthFormat());
-    Texture2D* lightBuffer = renderer_->GetRenderBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBAFormat());
     
     #ifdef USE_OPENGL
     bool needBlit = true;
@@ -1076,9 +1076,9 @@ void View::RenderBatchesLightPrepass()
     bool needBlit = edgeFilter_;
     #endif
     if (needBlit)
-        screenBuffer_ = renderer_->GetRenderBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBFormat(), true);
+        screenBuffer_ = renderer_->GetScreenBuffer(rtSize_.x_, rtSize_.y_, Graphics::GetRGBFormat(), true);
     RenderSurface* renderTarget = needBlit ? screenBuffer_->GetRenderSurface() : renderTarget_;
-    RenderSurface* depthStencil = 0;
+    RenderSurface* depthStencil;
     
     // Hardware depth support: render to RGBA normal buffer and read hardware depth
     if (hwDepth)
@@ -1089,6 +1089,7 @@ void View::RenderBatchesLightPrepass()
     // No hardware depth support: render to RGBA normal buffer and R32F depth
     else
     {
+        depthStencil = renderer_->GetDepthStencil(rtSize_.x_, rtSize_.y_);
         graphics_->SetRenderTarget(0, normalBuffer);
         graphics_->SetRenderTarget(1, depthBuffer);
     }

+ 3 - 5
Engine/UI/UI.cpp

@@ -262,18 +262,16 @@ void UI::Render()
     projection.m23_ = 0.0f;
     projection.m33_ = 1.0f;
     
-    graphics_->ResetRenderTargets();
-    graphics_->ResetDepthStencil();
-    graphics_->SetViewport(IntRect(0, 0, graphics_->GetWidth(), graphics_->GetHeight()));
-    
     graphics_->ClearParameterSources();
-    graphics_->ResetRenderTargets();
     graphics_->SetAlphaTest(false);
     graphics_->SetCullMode(CULL_CCW);
     graphics_->SetDepthTest(CMP_ALWAYS);
     graphics_->SetDepthWrite(false);
     graphics_->SetFillMode(FILL_SOLID);
     graphics_->SetStencilTest(false);
+    graphics_->ResetRenderTargets();
+    graphics_->ResetDepthStencil();
+    graphics_->SetViewport(IntRect(0, 0, graphics_->GetWidth(), graphics_->GetHeight()));
     
     ShaderVariation* ps = 0;
     ShaderVariation* vs = 0;