Selaa lähdekoodia

Refactored screen-size rendertarget allocation in preparation for postprocessing.
Removed the "size 0,0 follows window size" mechanism from Texture2D.

Lasse Öörni 14 vuotta sitten
vanhempi
sitoutus
75096fe6f9

+ 4 - 2
Docs/Reference.dox

@@ -475,13 +475,13 @@ Finally note that due to OpenGL framebuffer object limitations an extra framebuf
 
 
 \page APIDifferences Differences between Direct3D9 and OpenGL
 \page APIDifferences Differences between Direct3D9 and OpenGL
 
 
-- On Direct3D9 shader uniform parameters are global. On OpenGL they are shader-specific. To ensure correct operation also on OpenGL, first set the shaders, then query Graphics whether each shader parameter is needed, and set the corresponding parameter if needed. This includes also frame-global parameters, which on Direct3D9 need to be set only once per frame, if the uniform register assignments are fixed.
+- On Direct3D9 shader uniform parameters are global. On OpenGL they are shader-specific. To ensure correct operation also on OpenGL, first set the shaders, then query Graphics whether each shader parameter is needed, and set the corresponding parameter if needed.
 
 
 - On OpenGL vertex attribute bindings also depend on the currently set shaders. To ensure correct operation, first set the shaders, then the vertex buffers.
 - On OpenGL vertex attribute bindings also depend on the currently set shaders. To ensure correct operation, first set the shaders, then the vertex buffers.
 
 
 - On Direct3D9 the depth-stencil surface can be equal or larger in size than the color rendertarget. On OpenGL the sizes must always match. Furthermore, OpenGL can not use the backbuffer depth-stencil surface when rendering to a texture. To overcome these limitations, Graphics will create correctly sized depth-stencil surfaces on demand whenever a texture is set as a color rendertarget, and a null depth-stencil is specified.
 - On Direct3D9 the depth-stencil surface can be equal or larger in size than the color rendertarget. On OpenGL the sizes must always match. Furthermore, OpenGL can not use the backbuffer depth-stencil surface when rendering to a texture. To overcome these limitations, Graphics will create correctly sized depth-stencil surfaces on demand whenever a texture is set as a color rendertarget, and a null depth-stencil is specified.
 
 
-- On Direct3D9 setting the first color rendertarget resets the viewport dimensions. On OpenGL there is no such mechanism. However, as sometimes (for example in OpenGL shadow rendering) only a depth-stencil texture will be used for rendering, in OpenGL mode Graphics instead resets the viewport when the depth-stencil is set. The following sequence will produce reliable results on both APIs: first set the rendertargets, then the depth-stencil surface, and finally the viewport, if you need it to be less than the whole rendertarget.
+- On Direct3D9 setting the first color rendertarget resets the viewport dimensions. On OpenGL there is no such mechanism. However, as sometimes (for example in OpenGL shadow rendering) only a depth-stencil texture will be used for rendering, in OpenGL mode Graphics instead resets the viewport when the depth-stencil is set. The following sequence will produce reliable results on both APIs: first set the rendertarget(s), then the depth-stencil surface, and finally the viewport, if you need it to be less than the whole rendertarget.
 
 
 - On OpenGL modifying a texture will cause it to be momentarily set on the first texture unit. If another texture was set there, the assignment will be lost. Graphics performs a check to not assign textures redundantly, so it is safe and recommended to always set all needed textures before rendering.
 - On OpenGL modifying a texture will cause it to be momentarily set on the first texture unit. If another texture was set there, the assignment will be lost. Graphics performs a check to not assign textures redundantly, so it is safe and recommended to always set all needed textures before rendering.
 
 
@@ -493,6 +493,8 @@ Finally note that due to OpenGL framebuffer object limitations an extra framebuf
 
 
 - At least for now, instancing is not supported for OpenGL. It still benefits from the instance group rendering loop, which only changes the model transform for each object with the same material and light, instead of setting the whole renderstate.
 - At least for now, instancing is not supported for OpenGL. It still benefits from the instance group rendering loop, which only changes the model transform for each object with the same material and light, instead of setting the whole renderstate.
 
 
+- To ensure similar UV addressing for render-to-texture viewports on both APIs, on OpenGL texture viewports will be rendered upside down.
+
 Note that these differences only need to be observed when writing custom rendering functionality and accessing Graphics directly. When using Renderer and the Drawable components, they are taken care of automatically.
 Note that these differences only need to be observed when writing custom rendering functionality and accessing Graphics directly. When using Renderer and the Drawable components, they are taken care of automatically.
 
 
 
 

+ 1 - 1
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -2133,7 +2133,7 @@ void Graphics::OnDeviceReset()
         if (!depthTexture_)
         if (!depthTexture_)
         {
         {
             depthTexture_ = new Texture2D(context_);
             depthTexture_ = new Texture2D(context_);
-            depthTexture_->SetSize(0, 0, (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z'), TEXTURE_DEPTHSTENCIL);
+            depthTexture_->SetSize(width_, height_, (D3DFORMAT)MAKEFOURCC('I', 'N', 'T', 'Z'), TEXTURE_DEPTHSTENCIL);
         }
         }
         
         
         impl_->defaultDepthStencilSurface_ = (IDirect3DSurface9*)depthTexture_->GetRenderSurface()->GetSurface();
         impl_->defaultDepthStencilSurface_ = (IDirect3DSurface9*)depthTexture_->GetRenderSurface()->GetSurface();

+ 6 - 20
Engine/Graphics/Direct3D9/D3D9Texture2D.cpp

@@ -36,8 +36,7 @@
 OBJECTTYPESTATIC(Texture2D);
 OBJECTTYPESTATIC(Texture2D);
 
 
 Texture2D::Texture2D(Context* context) :
 Texture2D::Texture2D(Context* context) :
-    Texture(context),
-    followWindowSize_(false)
+    Texture(context)
 {
 {
 }
 }
 
 
@@ -75,16 +74,16 @@ bool Texture2D::Load(Deserializer& source)
 
 
 void Texture2D::OnDeviceLost()
 void Texture2D::OnDeviceLost()
 {
 {
-    if (pool_ == D3DPOOL_DEFAULT || followWindowSize_)
+    if (pool_ == D3DPOOL_DEFAULT)
         Release();
         Release();
 }
 }
 
 
 void Texture2D::OnDeviceReset()
 void Texture2D::OnDeviceReset()
 {
 {
-    if (pool_ == D3DPOOL_DEFAULT || followWindowSize_)
+    if (pool_ == D3DPOOL_DEFAULT)
     {
     {
         // If has a file name, reload through the resource cache. Otherwise recreate and mark the data lost
         // If has a file name, reload through the resource cache. Otherwise recreate and mark the data lost
-        if (!GetName().Trimmed().Empty() && !followWindowSize_)
+        if (!GetName().Trimmed().Empty())
             GetSubsystem<ResourceCache>()->ReloadResource(this);
             GetSubsystem<ResourceCache>()->ReloadResource(this);
         else
         else
         {
         {
@@ -148,15 +147,8 @@ bool Texture2D::SetSize(int width, int height, unsigned format, TextureUsage usa
         pool_ = D3DPOOL_DEFAULT;
         pool_ = D3DPOOL_DEFAULT;
     }
     }
     
     
-    if (width <= 0 || height <= 0)
-        followWindowSize_ = true;
-    else
-    {
-        width_ = width;
-        height_ = height;
-        followWindowSize_ = false;
-    }
-    
+    width_ = width;
+    height_ = height;
     format_ = format;
     format_ = format;
     
     
     return Create();
     return Create();
@@ -463,12 +455,6 @@ bool Texture2D::Create()
     if (!graphics_)
     if (!graphics_)
         return false;
         return false;
     
     
-    if (followWindowSize_)
-    {
-        width_ = graphics_->GetWidth();
-        height_ = graphics_->GetHeight();
-    }
-    
     if (!width_ || !height_)
     if (!width_ || !height_)
         return false;
         return false;
     
     

+ 0 - 2
Engine/Graphics/Direct3D9/D3D9Texture2D.h

@@ -69,6 +69,4 @@ private:
     
     
     /// Render surface.
     /// Render surface.
     SharedPtr<RenderSurface> renderSurface_;
     SharedPtr<RenderSurface> renderSurface_;
-    /// Follow window size flag.
-    bool followWindowSize_;
 };
 };

+ 5 - 21
Engine/Graphics/OpenGL/OGLTexture2D.cpp

@@ -36,8 +36,7 @@
 OBJECTTYPESTATIC(Texture2D);
 OBJECTTYPESTATIC(Texture2D);
 
 
 Texture2D::Texture2D(Context* context) :
 Texture2D::Texture2D(Context* context) :
-    Texture(context),
-    followWindowSize_(false)
+    Texture(context)
 {
 {
     target_ = GL_TEXTURE_2D;
     target_ = GL_TEXTURE_2D;
 }
 }
@@ -96,9 +95,7 @@ void Texture2D::OnDeviceLost()
 
 
 void Texture2D::OnDeviceReset()
 void Texture2D::OnDeviceReset()
 {
 {
-    if (followWindowSize_)
-        Create();
-    else if (!object_)
+    if (!object_)
     {
     {
         Create();
         Create();
         
         
@@ -162,16 +159,9 @@ bool Texture2D::SetSize(int width, int height, unsigned format, TextureUsage usa
         dynamic_ = true;
         dynamic_ = true;
     else
     else
         dynamic_ = false;
         dynamic_ = false;
-    
-    if (width <= 0 || height <= 0)
-        followWindowSize_ = true;
-    else
-    {
-        width_ = width;
-        height_ = height;
-        followWindowSize_ = false;
-    }
-    
+
+    width_ = width;
+    height_ = height;
     format_ = format;
     format_ = format;
     
     
     return Create();
     return Create();
@@ -376,12 +366,6 @@ bool Texture2D::Create()
     if (!graphics_)
     if (!graphics_)
         return false;
         return false;
     
     
-    if (followWindowSize_)
-    {
-        width_ = graphics_->GetWidth();
-        height_ = graphics_->GetHeight();
-    }
-    
     if (!width_ || !height_)
     if (!width_ || !height_)
         return false;
         return false;
     
     

+ 0 - 2
Engine/Graphics/OpenGL/OGLTexture2D.h

@@ -68,6 +68,4 @@ private:
     
     
     /// Render surface.
     /// Render surface.
     SharedPtr<RenderSurface> renderSurface_;
     SharedPtr<RenderSurface> renderSurface_;
-    /// Follow window size flag.
-    bool followWindowSize_;
 };
 };

+ 94 - 68
Engine/Graphics/Renderer.cpp

@@ -343,51 +343,8 @@ void Renderer::SetLightPrepass(bool enable)
                 graphics_->GetTripleBuffer(), 1);
                 graphics_->GetTripleBuffer(), 1);
         }
         }
         
         
-        // Create the G-buffer textures if necessary
-        if (enable)
-        {
-            if (!normalBuffer_)
-            {
-                normalBuffer_ = new Texture2D(context_);
-                normalBuffer_->SetSize(0, 0, Graphics::GetRGBAFormat(), TEXTURE_RENDERTARGET);
-            }
-            
-            if (!depthBuffer_)
-            {
-                // If reading the hardware depth buffer is supported, create a depth-stencil texture. Otherwise create an
-                // ordinary rendertarget for writing linear depth manually
-                if (graphics_->GetHardwareDepthSupport())
-                {
-                    #ifdef USE_OPENGL
-                    depthBuffer_ = new Texture2D(context_);
-                    depthBuffer_->SetSize(0, 0, Graphics::GetDepthStencilFormat(), TEXTURE_DEPTHSTENCIL);
-                    #else
-                    depthBuffer_ = graphics_->GetDepthTexture();
-                    #endif
-                }
-                else
-                {
-                    depthBuffer_ = new Texture2D(context_);
-                    depthBuffer_->SetSize(0, 0, Graphics::GetLinearDepthFormat(), TEXTURE_RENDERTARGET);
-                }
-            }
-            
-            if (!lightBuffer_)
-            {
-                lightBuffer_ = new Texture2D(context_);
-                lightBuffer_->SetSize(0, 0, Graphics::GetRGBAFormat(), TEXTURE_RENDERTARGET);
-            }
-        }
-        else
-        {
-            normalBuffer_.Reset();
-            depthBuffer_.Reset();
-            lightBuffer_.Reset();
-        }
-        
         lightPrepass_ = enable;
         lightPrepass_ = enable;
         shadersDirty_ = true;
         shadersDirty_ = true;
-        CheckScreenBuffer();
     }
     }
 }
 }
 
 
@@ -526,7 +483,6 @@ void Renderer::SetEdgeFilter(bool enable)
     }
     }
     
     
     edgeFilter_ = enable;
     edgeFilter_ = enable;
-    CheckScreenBuffer();
 }
 }
 
 
 void Renderer::SetEdgeFilterParameters(const EdgeFilterParameters& parameters)
 void Renderer::SetEdgeFilterParameters(const EdgeFilterParameters& parameters)
@@ -618,18 +574,6 @@ unsigned Renderer::GetNumOccluders(bool allViews) const
     return numOccluders;
     return numOccluders;
 }
 }
 
 
-Texture2D* Renderer::GetScreenBuffer()
-{
-    if (!screenBuffer_)
-    {
-        screenBuffer_ = new Texture2D(context_);
-        screenBuffer_->SetSize(0, 0, Graphics::GetRGBFormat(), TEXTURE_RENDERTARGET);
-        screenBuffer_->SetFilterMode(FILTER_BILINEAR);
-    }
-    
-    return screenBuffer_;
-}
-
 void Renderer::Update(float timeStep)
 void Renderer::Update(float timeStep)
 {
 {
     PROFILE(UpdateViews);
     PROFILE(UpdateViews);
@@ -683,7 +627,11 @@ void Renderer::Update(float timeStep)
         
         
         // Update the viewport's main view and any auxiliary views it has created
         // Update the viewport's main view and any auxiliary views it has created
         for (unsigned i = mainView; i < numViews_; ++i)
         for (unsigned i = mainView; i < numViews_; ++i)
+        {
+            // Reset shadow map allocations; they can be reused between views as each is rendered completely at a time
+            ResetShadowMapAllocations();
             views_[i]->Update(frame_);
             views_[i]->Update(frame_);
+        }
     }
     }
 }
 }
 
 
@@ -694,6 +642,9 @@ void Renderer::Render()
     
     
     PROFILE(RenderViews);
     PROFILE(RenderViews);
     
     
+    // Remove unused buffers from last frame
+    ResetRenderBufferAllocations(true);
+    
     graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
     graphics_->SetDefaultTextureFilterMode(textureFilterMode_);
     graphics_->SetTextureAnisotropy(textureAnisotropy_);
     graphics_->SetTextureAnisotropy(textureAnisotropy_);
     
     
@@ -715,7 +666,11 @@ void Renderer::Render()
     
     
     // Render views from last to first (each main view is rendered after the auxiliary views it depends on)
     // 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)
     for (unsigned i = numViews_ - 1; i < numViews_; --i)
+    {
+        // Buffers can be reused between views, as each is rendered completely
+        ResetRenderBufferAllocations();
         views_[i]->Render();
         views_[i]->Render();
+    }
     
     
     // Copy the number of batches & primitives from Graphics so that we can account for 3D geometry only
     // Copy the number of batches & primitives from Graphics so that we can account for 3D geometry only
     numPrimitives_ = graphics_->GetNumPrimitives();
     numPrimitives_ = graphics_->GetNumPrimitives();
@@ -944,6 +899,61 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
     return newShadowMap;
     return newShadowMap;
 }
 }
 
 
+Texture2D* Renderer::GetRenderBuffer(int width, int height, unsigned format, bool filtered)
+{
+    if (!width)
+        width = graphics_->GetWidth();
+    if (!height)
+        height = graphics_->GetHeight();
+    
+    bool depthStencil = (format == Graphics::GetDepthStencilFormat());
+    if (depthStencil)
+        filtered = false;
+    
+    long long searchKey = ((long long)format << 32) | (width << 16) | height;
+    if (filtered)
+        searchKey |= 0x8000000000000000LL;
+    
+    // Return the default depth-stencil if applicable
+    if (width <= graphics_->GetWidth() && height <= graphics_->GetHeight() && depthStencil)
+        return graphics_->GetDepthTexture();
+    
+    bool needNew = false;
+    
+    // If new size or format, initialize the allocation stats
+    if (renderBuffers_.Find(searchKey) == renderBuffers_.End())
+    {
+        renderBufferAllocations_[searchKey] = 0;
+        renderBufferMaxAllocations_[searchKey] = 0;
+    }
+    
+    unsigned& allocations = renderBufferAllocations_[searchKey];
+    unsigned& maxAllocations = renderBufferMaxAllocations_[searchKey];
+    ++allocations;
+    if (allocations > maxAllocations)
+        maxAllocations = allocations;
+    
+    if (allocations > renderBuffers_[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));
+        return newBuffer;
+    }
+    else
+        return renderBuffers_[searchKey][allocations - 1];
+}
+
+RenderSurface* Renderer::GetDepthStencil(int width, int height)
+{
+    // GetRenderBuffer() may return 0 if using the default depth-stencil, so watch out
+    Texture2D* depthTexture = GetRenderBuffer(width, height, Graphics::GetDepthStencilFormat());
+    return depthTexture ? depthTexture->GetRenderSurface() : 0;
+}
+
 OcclusionBuffer* Renderer::GetOcclusionBuffer(Camera* camera)
 OcclusionBuffer* Renderer::GetOcclusionBuffer(Camera* camera)
 {
 {
     if (numOcclusionBuffers_ >= occlusionBuffers_.Size())
     if (numOcclusionBuffers_ >= occlusionBuffers_.Size())
@@ -1224,6 +1234,33 @@ void Renderer::ResetShadowMapAllocations()
         i->second_.Clear();
         i->second_.Clear();
 }
 }
 
 
+void Renderer::ResetRenderBufferAllocations(bool remove)
+{
+    // Optionally remove ´buffers that were not used at all (at the beginning of each frame's rendering step)
+    if (remove)
+    {
+        for (HashMap<long long, unsigned>::Iterator i = renderBufferMaxAllocations_.Begin(); i != renderBufferMaxAllocations_.End();)
+        {
+            HashMap<long long, unsigned>::Iterator current = i++;
+            if (!current->second_)
+            {
+                renderBuffers_.Erase(current->first_);
+                renderBufferAllocations_.Erase(current->first_);
+                renderBufferMaxAllocations_.Erase(current);
+            }
+            else
+            {
+                renderBuffers_[current->first_].Resize(current->second_);
+                current->second_ = 0;
+            }
+        }
+    }
+    
+    // Then reset allocation value of remaining buffer sizes
+    for (HashMap<long long, unsigned>::Iterator i = renderBufferAllocations_.Begin(); i != renderBufferAllocations_.End(); ++i)
+        i->second_ = 0;
+}
+
 void Renderer::Initialize()
 void Renderer::Initialize()
 {
 {
     Graphics* graphics = GetSubsystem<Graphics>();
     Graphics* graphics = GetSubsystem<Graphics>();
@@ -1589,21 +1626,10 @@ void Renderer::CreateInstancingBuffer()
 void Renderer::ResetShadowMaps()
 void Renderer::ResetShadowMaps()
 {
 {
     shadowMaps_.Clear();
     shadowMaps_.Clear();
+    shadowMapAllocations_.Clear();
     colorShadowMaps_.Clear();
     colorShadowMaps_.Clear();
 }
 }
 
 
-void Renderer::CheckScreenBuffer()
-{
-    bool needScreenBuffer = edgeFilter_;
-    #ifdef USE_OPENGL
-    if (lightPrepass_)
-        needScreenBuffer = true;
-    #endif
-    
-    if (!needScreenBuffer)
-        screenBuffer_.Reset();
-}
-
 void Renderer::HandleScreenMode(StringHash eventType, VariantMap& eventData)
 void Renderer::HandleScreenMode(StringHash eventType, VariantMap& eventData)
 {
 {
     if (!initialized_)
     if (!initialized_)

+ 14 - 20
Engine/Graphics/Renderer.h

@@ -302,14 +302,6 @@ public:
     TextureCube* GetFaceSelectCubeMap() const { return faceSelectCubeMap_; }
     TextureCube* GetFaceSelectCubeMap() const { return faceSelectCubeMap_; }
     /// Return the shadowed pointlight indirection cube map.
     /// Return the shadowed pointlight indirection cube map.
     TextureCube* GetIndirectionCubeMap() const { return indirectionCubeMap_; }
     TextureCube* GetIndirectionCubeMap() const { return indirectionCubeMap_; }
-    /// Return the normal buffer for light pre-pass rendering.
-    Texture2D* GetNormalBuffer() const { return normalBuffer_; }
-    /// Return the depth buffer for light pre-pass rendering.
-    Texture2D* GetDepthBuffer() const { return depthBuffer_; }
-    /// Return the light accumulation buffer for light pre-pass rendering.
-    Texture2D* GetLightBuffer() const { return lightBuffer_; }
-    /// Return the screen buffer for postprocessing, created on demand.
-    Texture2D* GetScreenBuffer();
     /// Return the instancing vertex buffer
     /// Return the instancing vertex buffer
     VertexBuffer* GetInstancingBuffer() const { return dynamicInstancing_ ? instancingBuffer_ : (VertexBuffer*)0; }
     VertexBuffer* GetInstancingBuffer() const { return dynamicInstancing_ ? instancingBuffer_ : (VertexBuffer*)0; }
     /// Return a vertex shader by name.
     /// Return a vertex shader by name.
@@ -335,6 +327,10 @@ public:
     Geometry* GetLightGeometry(Light* light);
     Geometry* GetLightGeometry(Light* light);
     /// Allocate a shadow map. If shadow map reuse is disabled, a different map is returned each time.
     /// 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);
     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);
+    /// Allocate a depth-stencil surface. May return the backbuffer depth-stencil if applicable. Should only be called during actual rendering, not before.
+    RenderSurface* GetDepthStencil(int width, int height);
     /// Allocate an occlusion buffer.
     /// Allocate an occlusion buffer.
     OcclusionBuffer* GetOcclusionBuffer(Camera* camera);
     OcclusionBuffer* GetOcclusionBuffer(Camera* camera);
     /// Allocate a temporary shadow camera and a scene node for it. Is thread-safe.
     /// Allocate a temporary shadow camera and a scene node for it. Is thread-safe.
@@ -349,8 +345,6 @@ public:
     void SetCullMode(CullMode mode, Camera* camera);
     void SetCullMode(CullMode mode, Camera* camera);
     /// Ensure sufficient size of the instancing vertex buffer. Return true if successful.
     /// Ensure sufficient size of the instancing vertex buffer. Return true if successful.
     bool ResizeInstancingBuffer(unsigned numInstances);
     bool ResizeInstancingBuffer(unsigned numInstances);
-    /// Reset shadow map allocation counts.
-    void ResetShadowMapAllocations();
     
     
 private:
 private:
     /// Initialize when screen mode initially set.
     /// Initialize when screen mode initially set.
@@ -371,10 +365,12 @@ private:
     void CreateGeometries();
     void CreateGeometries();
     /// Create instancing vertex buffer.
     /// Create instancing vertex buffer.
     void CreateInstancingBuffer();
     void CreateInstancingBuffer();
+    /// 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);
     /// Remove all shadow maps. Called when global shadow map resolution or format is changed.
     /// Remove all shadow maps. Called when global shadow map resolution or format is changed.
     void ResetShadowMaps();
     void ResetShadowMaps();
-    /// Remove the screen buffer if no longer needed.
-    void CheckScreenBuffer();
     /// Handle screen mode event.
     /// Handle screen mode event.
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
     void HandleScreenMode(StringHash eventType, VariantMap& eventData);
     /// Handle graphics features (re)check event.
     /// Handle graphics features (re)check event.
@@ -406,14 +402,6 @@ private:
     SharedPtr<TextureCube> faceSelectCubeMap_;
     SharedPtr<TextureCube> faceSelectCubeMap_;
     /// Indirection cube map for shadowed pointlights.
     /// Indirection cube map for shadowed pointlights.
     SharedPtr<TextureCube> indirectionCubeMap_;
     SharedPtr<TextureCube> indirectionCubeMap_;
-    /// Normal buffer for light pre-pass rendering.
-    SharedPtr<Texture2D> normalBuffer_;
-    /// Depth buffer for light pre-pass rendering.
-    SharedPtr<Texture2D> depthBuffer_;
-    /// Light accumulation buffer for light pre-pass rendering.
-    SharedPtr<Texture2D> lightBuffer_;
-    /// Screen buffer for post-processing.
-    SharedPtr<Texture2D> screenBuffer_;
     /// Stencil rendering vertex shader.
     /// Stencil rendering vertex shader.
     SharedPtr<ShaderVariation> stencilVS_;
     SharedPtr<ShaderVariation> stencilVS_;
     /// Stencil rendering pixel shader.
     /// Stencil rendering pixel shader.
@@ -432,6 +420,12 @@ private:
     HashMap<int, SharedPtr<Texture2D> > colorShadowMaps_;
     HashMap<int, SharedPtr<Texture2D> > colorShadowMaps_;
     /// Shadow map allocations by resolution.
     /// Shadow map allocations by resolution.
     HashMap<int, PODVector<Light*> > shadowMapAllocations_;
     HashMap<int, PODVector<Light*> > shadowMapAllocations_;
+    /// Renderbuffers by resolution and format.
+    HashMap<long long, Vector<SharedPtr<Texture2D> > > renderBuffers_;
+    /// Renderbuffer current allocations by resolution and format.
+    HashMap<long long, unsigned> renderBufferAllocations_;
+    /// Renderbuffer maximum allocations by resolution and format.
+    HashMap<long long, unsigned> renderBufferMaxAllocations_;
     /// Viewports.
     /// Viewports.
     Vector<Viewport> viewports_;
     Vector<Viewport> viewports_;
     /// Views.
     /// Views.

+ 31 - 19
Engine/Graphics/View.cpp

@@ -153,7 +153,7 @@ View::View(Context* context) :
     cameraZone_(0),
     cameraZone_(0),
     farClipZone_(0),
     farClipZone_(0),
     renderTarget_(0),
     renderTarget_(0),
-    depthStencil_(0)
+    screenBuffer_(0)
 {
 {
     frame_.camera_ = 0;
     frame_.camera_ = 0;
     
     
@@ -198,11 +198,7 @@ bool View::Define(RenderSurface* renderTarget, const Viewport& viewport)
     octree_ = octree;
     octree_ = octree;
     camera_ = viewport.camera_;
     camera_ = viewport.camera_;
     renderTarget_ = renderTarget;
     renderTarget_ = renderTarget;
-    
-    if (!renderTarget)
-        depthStencil_ = 0;
-    else
-        depthStencil_ = renderTarget->GetLinkedDepthStencil();
+    screenBuffer_ = 0;
     
     
     // Validate the rect and calculate size. If zero rect, use whole rendertarget size
     // Validate the rect and calculate size. If zero rect, use whole rendertarget size
     int rtWidth = renderTarget ? renderTarget->GetWidth() : graphics_->GetWidth();
     int rtWidth = renderTarget ? renderTarget->GetWidth() : graphics_->GetWidth();
@@ -275,9 +271,6 @@ void View::Update(const FrameInfo& frame)
     // Cache the camera frustum to avoid recalculating it constantly
     // Cache the camera frustum to avoid recalculating it constantly
     frustum_ = camera_->GetFrustum();
     frustum_ = camera_->GetFrustum();
     
     
-    // Reset shadow map allocations; they can be reused between views as each is rendered completely at a time
-    renderer_->ResetShadowMapAllocations();
-    
     GetDrawables();
     GetDrawables();
     GetBatches();
     GetBatches();
     UpdateGeometries();
     UpdateGeometries();
@@ -987,8 +980,10 @@ void View::RenderBatchesForward()
     lightStencilValue_ = 1;
     lightStencilValue_ = 1;
     
     
     bool needBlit = edgeFilter_;
     bool needBlit = edgeFilter_;
-    RenderSurface* renderTarget = needBlit ? renderer_->GetScreenBuffer()->GetRenderSurface() : renderTarget_;
-    RenderSurface* depthStencil = needBlit ? 0 : depthStencil_;
+    if (needBlit)
+        screenBuffer_ = renderer_->GetRenderBuffer(0, 0, Graphics::GetRGBFormat(), true);
+    RenderSurface* renderTarget = needBlit ? screenBuffer_->GetRenderSurface() : renderTarget_;
+    RenderSurface* depthStencil = GetDepthStencil(renderTarget);
     
     
     // If not reusing shadowmaps, render all of them first
     // If not reusing shadowmaps, render all of them first
     if (!renderer_->GetReuseShadowMaps() && renderer_->GetDrawShadows() && !lightQueues_.Empty())
     if (!renderer_->GetReuseShadowMaps() && renderer_->GetDrawShadows() && !lightQueues_.Empty())
@@ -1080,19 +1075,23 @@ void View::RenderBatchesLightPrepass()
         }
         }
     }
     }
     
     
-    Texture2D* normalBuffer = renderer_->GetNormalBuffer();
-    Texture2D* depthBuffer = renderer_->GetDepthBuffer();
+    bool hwDepth = graphics_->GetHardwareDepthSupport();
+    Texture2D* normalBuffer = renderer_->GetRenderBuffer(0, 0, Graphics::GetRGBAFormat());
+    Texture2D* depthBuffer = renderer_->GetRenderBuffer(0, 0, hwDepth ? Graphics::GetDepthStencilFormat() : Graphics::GetLinearDepthFormat());
+    Texture2D* lightBuffer = renderer_->GetRenderBuffer(0, 0, Graphics::GetRGBAFormat());
     
     
     #ifdef USE_OPENGL
     #ifdef USE_OPENGL
     bool needBlit = true;
     bool needBlit = true;
     #else
     #else
     bool needBlit = edgeFilter_;
     bool needBlit = edgeFilter_;
     #endif
     #endif
-    RenderSurface* renderTarget = needBlit ? renderer_->GetScreenBuffer()->GetRenderSurface() : renderTarget_;
-    RenderSurface* depthStencil = 0;
+    if (needBlit)
+        screenBuffer_ = renderer_->GetRenderBuffer(0, 0, Graphics::GetRGBFormat(), true);
+    RenderSurface* renderTarget = needBlit ? screenBuffer_->GetRenderSurface() : renderTarget_;
+    RenderSurface* depthStencil;
     
     
     // Hardware depth support: render to RGBA normal buffer and read hardware depth
     // Hardware depth support: render to RGBA normal buffer and read hardware depth
-    if (graphics_->GetHardwareDepthSupport())
+    if (hwDepth)
     {
     {
         depthStencil = depthBuffer->GetRenderSurface();
         depthStencil = depthBuffer->GetRenderSurface();
         graphics_->SetRenderTarget(0, normalBuffer);
         graphics_->SetRenderTarget(0, normalBuffer);
@@ -1100,6 +1099,7 @@ void View::RenderBatchesLightPrepass()
     // No hardware depth support: render to RGBA normal buffer and R32F depth
     // No hardware depth support: render to RGBA normal buffer and R32F depth
     else
     else
     {
     {
+        depthStencil = renderer_->GetDepthStencil(0, 0);
         graphics_->SetRenderTarget(0, normalBuffer);
         graphics_->SetRenderTarget(0, normalBuffer);
         graphics_->SetRenderTarget(1, depthBuffer);
         graphics_->SetRenderTarget(1, depthBuffer);
     }
     }
@@ -1120,7 +1120,6 @@ void View::RenderBatchesLightPrepass()
     bool optimizeLightBuffer = !hasZeroLightMask_ && !lightQueues_.Empty() && lightQueues_.Front().light_->GetLightType() ==
     bool optimizeLightBuffer = !hasZeroLightMask_ && !lightQueues_.Empty() && lightQueues_.Front().light_->GetLightType() ==
         LIGHT_DIRECTIONAL && (lightQueues_.Front().light_->GetLightMask() & 0xff) == 0xff;
         LIGHT_DIRECTIONAL && (lightQueues_.Front().light_->GetLightMask() & 0xff) == 0xff;
     
     
-    Texture2D* lightBuffer = renderer_->GetLightBuffer();
     graphics_->ResetRenderTarget(1);
     graphics_->ResetRenderTarget(1);
     graphics_->SetRenderTarget(0, lightBuffer);
     graphics_->SetRenderTarget(0, lightBuffer);
     graphics_->SetDepthStencil(depthStencil);
     graphics_->SetDepthStencil(depthStencil);
@@ -1222,7 +1221,7 @@ void View::BlitFramebuffer()
     graphics_->SetScissorTest(false);
     graphics_->SetScissorTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetStencilTest(false);
     graphics_->SetRenderTarget(0, renderTarget_);
     graphics_->SetRenderTarget(0, renderTarget_);
-    graphics_->SetDepthStencil(depthStencil_);
+    graphics_->SetDepthStencil(GetDepthStencil(renderTarget_));
     graphics_->SetViewport(screenRect_);
     graphics_->SetViewport(screenRect_);
     
     
     String shaderName = edgeFilter_ ? "EdgeFilter" : "CopyFramebuffer";
     String shaderName = edgeFilter_ ? "EdgeFilter" : "CopyFramebuffer";
@@ -1257,7 +1256,7 @@ void View::BlitFramebuffer()
         graphics_->SetShaderParameter(PSP_SAMPLEOFFSETS, Vector4(addX, addY, 0.0f, 0.0f));
         graphics_->SetShaderParameter(PSP_SAMPLEOFFSETS, Vector4(addX, addY, 0.0f, 0.0f));
     }
     }
     
     
-    graphics_->SetTexture(TU_DIFFUSE, renderer_->GetScreenBuffer());
+    graphics_->SetTexture(TU_DIFFUSE, screenBuffer_);
     DrawFullscreenQuad(camera_, false);
     DrawFullscreenQuad(camera_, false);
     graphics_->SetTexture(TU_DIFFUSE, 0);
     graphics_->SetTexture(TU_DIFFUSE, 0);
 }
 }
@@ -2345,3 +2344,16 @@ void View::RenderShadowMap(const LightBatchQueue& queue)
     graphics_->SetColorWrite(true);
     graphics_->SetColorWrite(true);
     graphics_->SetDepthBias(0.0f, 0.0f);
     graphics_->SetDepthBias(0.0f, 0.0f);
 }
 }
+
+RenderSurface* View::GetDepthStencil(RenderSurface* renderTarget)
+{
+    // If using the backbuffer, return the backbuffer stencil
+    if (!renderTarget)
+        return 0;
+    // Then check for linked depth stencil
+    RenderSurface* depthStencil = renderTarget->GetLinkedDepthStencil();
+    // Finally get one from Renderer
+    if (!depthStencil)
+        depthStencil = renderer_->GetDepthStencil(renderTarget->GetWidth(), renderTarget->GetHeight());
+    return depthStencil;
+}

+ 5 - 6
Engine/Graphics/View.h

@@ -103,8 +103,6 @@ public:
     Camera* GetCamera() const { return camera_; }
     Camera* GetCamera() const { return camera_; }
     /// Return the rendertarget. 0 if using the backbuffer.
     /// Return the rendertarget. 0 if using the backbuffer.
     RenderSurface* GetRenderTarget() const { return renderTarget_; }
     RenderSurface* GetRenderTarget() const { return renderTarget_; }
-    /// Return the depth-stencil. 0 if using the backbuffer's depth-stencil.
-    RenderSurface* GetDepthStencil() const { return depthStencil_; }
     /// Return geometry objects.
     /// Return geometry objects.
     const PODVector<Drawable*>& GetGeometries() const { return geometries_; }
     const PODVector<Drawable*>& GetGeometries() const { return geometries_; }
     /// Return occluder objects.
     /// Return occluder objects.
@@ -183,9 +181,10 @@ private:
     void RenderBatchQueue(const BatchQueue& queue, bool useScissor = false);
     void RenderBatchQueue(const BatchQueue& queue, bool useScissor = false);
     /// Render batches lit by a specific light.
     /// Render batches lit by a specific light.
     void RenderLightBatchQueue(const BatchQueue& queue, Light* forwardQueueLight);
     void RenderLightBatchQueue(const BatchQueue& queue, Light* forwardQueueLight);
-
     /// Render a shadow map.
     /// Render a shadow map.
     void RenderShadowMap(const LightBatchQueue& queue);
     void RenderShadowMap(const LightBatchQueue& queue);
+    /// Return the proper depth-stencil surface to use for a rendertarget.
+    RenderSurface* GetDepthStencil(RenderSurface* renderTarget);
     
     
     /// Graphics subsystem.
     /// Graphics subsystem.
     WeakPtr<Graphics> graphics_;
     WeakPtr<Graphics> graphics_;
@@ -201,10 +200,10 @@ private:
     Zone* farClipZone_;
     Zone* farClipZone_;
     /// Occlusion buffer for the main camera.
     /// Occlusion buffer for the main camera.
     OcclusionBuffer* occlusionBuffer_;
     OcclusionBuffer* occlusionBuffer_;
-    /// Color buffer to use.
+    /// Color rendertarget to use.
     RenderSurface* renderTarget_;
     RenderSurface* renderTarget_;
-    /// Depth buffer to use.
-    RenderSurface* depthStencil_;
+    /// Intermediate screen buffer used in postprocessing and OpenGL light pre-pass framebuffer blit.
+    Texture2D* screenBuffer_;
     /// Screen rectangle.
     /// Screen rectangle.
     IntRect screenRect_;
     IntRect screenRect_;
     /// Information of the frame being rendered.
     /// Information of the frame being rendered.