2
0
Эх сурвалжийг харах

Refactored occlusion buffer allocation to be thread-safe. Thread queries for directional shadowed lights as well.

Lasse Öörni 14 жил өмнө
parent
commit
6b504a0b21

+ 51 - 52
Engine/Graphics/Renderer.cpp

@@ -232,6 +232,7 @@ Renderer::Renderer(Context* context) :
     defaultZone_(new Zone(context)),
     defaultZone_(new Zone(context)),
     numViews_(0),
     numViews_(0),
     numShadowCameras_(0),
     numShadowCameras_(0),
+    numOcclusionBuffers_(0),
     textureAnisotropy_(4),
     textureAnisotropy_(4),
     textureFilterMode_(FILTER_TRILINEAR),
     textureFilterMode_(FILTER_TRILINEAR),
     textureQuality_(QUALITY_HIGH),
     textureQuality_(QUALITY_HIGH),
@@ -509,6 +510,7 @@ void Renderer::Update(float timeStep)
     frame_.timeStep_ = timeStep;
     frame_.timeStep_ = timeStep;
     frame_.camera_ = 0;
     frame_.camera_ = 0;
     numShadowCameras_ = 0;
     numShadowCameras_ = 0;
+    numOcclusionBuffers_ = 0;
     updateOctrees_.Clear();
     updateOctrees_.Clear();
     
     
     // Reload shaders if needed
     // Reload shaders if needed
@@ -658,37 +660,6 @@ bool Renderer::AddView(RenderSurface* renderTarget, const Viewport& viewport)
         return false;
         return false;
 }
 }
 
 
-OcclusionBuffer* Renderer::GetOrCreateOcclusionBuffer(Camera* camera, int maxOccluderTriangles, bool halfResolution)
-{
-    // Get an occlusion buffer matching the aspect ratio. If not found, allocate new
-    int width = occlusionBufferSize_;
-    int height = (int)((float)occlusionBufferSize_ / camera->GetAspectRatio() + 0.5f);
-    
-    if (halfResolution)
-    {
-        width >>= 1;
-        height >>= 1;
-    }
-    int searchKey = (width << 16) | height;
-    
-    SharedPtr<OcclusionBuffer> buffer;
-    HashMap<int, SharedPtr<OcclusionBuffer> >::Iterator i = occlusionBuffers_.Find(searchKey);
-    if (i != occlusionBuffers_.End())
-        buffer = i->second_;
-    else
-    {
-        buffer = new OcclusionBuffer(context_);
-        buffer->SetSize(width, height);
-        occlusionBuffers_[searchKey] = buffer;
-    }
-    
-    buffer->SetView(camera);
-    buffer->SetMaxTriangles(maxOccluderTriangles);
-    buffer->Clear();
-    
-    return buffer;
-}
-
 Geometry* Renderer::GetLightGeometry(Light* light)
 Geometry* Renderer::GetLightGeometry(Light* light)
 {
 {
     LightType type = light->GetLightType();
     LightType type = light->GetLightType();
@@ -700,7 +671,6 @@ Geometry* Renderer::GetLightGeometry(Light* light)
         return 0;
         return 0;
 }
 }
 
 
-
 Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight)
 Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWidth, unsigned viewHeight)
 {
 {
     LightType type = light->GetLightType();
     LightType type = light->GetLightType();
@@ -853,6 +823,54 @@ Texture2D* Renderer::GetShadowMap(Light* light, Camera* camera, unsigned viewWid
     return newShadowMap;
     return newShadowMap;
 }
 }
 
 
+OcclusionBuffer* Renderer::GetOcclusionBuffer(Camera* camera, bool halfResolution)
+{
+    OcclusionBuffer* buffer = 0;
+    
+    {
+        MutexLock lock(rendererMutex_);
+        if (numOcclusionBuffers_ >= occlusionBuffers_.Size())
+        {
+            SharedPtr<OcclusionBuffer> newBuffer(new OcclusionBuffer(context_));
+            occlusionBuffers_.Push(newBuffer);
+        }
+        
+        buffer = occlusionBuffers_[numOcclusionBuffers_];
+        ++numOcclusionBuffers_;
+    }
+    
+    int width = occlusionBufferSize_;
+    int height = (int)((float)occlusionBufferSize_ / camera->GetAspectRatio() + 0.5f);
+    if (halfResolution)
+    {
+        width >>= 1;
+        height >>= 1;
+    }
+    
+    buffer->SetSize(width, height);
+    buffer->SetView(camera);
+    
+    return buffer;
+}
+
+Camera* Renderer::GetShadowCamera()
+{
+    MutexLock lock(rendererMutex_);
+    
+    if (numShadowCameras_ >= shadowCameraNodes_.Size())
+    {
+        SharedPtr<Node> newNode(new Node(context_));
+        newNode->CreateComponent<Camera>();
+        shadowCameraNodes_.Push(newNode);
+    }
+    
+    Camera* camera = shadowCameraNodes_[numShadowCameras_]->GetComponent<Camera>();
+    camera->SetOrthographic(false);
+    camera->SetZoom(1.0f);
+    ++numShadowCameras_;
+    return camera;
+}
+
 ShaderVariation* Renderer::GetShader(const String& name, const String& extension, bool checkExists) const
 ShaderVariation* Renderer::GetShader(const String& name, const String& extension, bool checkExists) const
 {
 {
     String shaderName = shaderPath_;
     String shaderName = shaderPath_;
@@ -991,24 +1009,6 @@ void Renderer::SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, b
     }
     }
 }
 }
 
 
-Camera* Renderer::CreateShadowCamera()
-{
-    MutexLock lock(rendererMutex_);
-    
-    if (numShadowCameras_ >= shadowCameraNodes_.Size())
-    {
-        SharedPtr<Node> newNode(new Node(context_));
-        newNode->CreateComponent<Camera>();
-        shadowCameraNodes_.Push(newNode);
-    }
-    
-    Camera* camera = shadowCameraNodes_[numShadowCameras_]->GetComponent<Camera>();
-    camera->SetOrthographic(false);
-    camera->SetZoom(1.0f);
-    ++numShadowCameras_;
-    return camera;
-}
-
 bool Renderer::ResizeInstancingBuffer(unsigned numInstances)
 bool Renderer::ResizeInstancingBuffer(unsigned numInstances)
 {
 {
     if (!instancingBuffer_ || !dynamicInstancing_)
     if (!instancingBuffer_ || !dynamicInstancing_)
@@ -1342,8 +1342,7 @@ void Renderer::HandleScreenMode(StringHash eventType, VariantMap& eventData)
         Initialize();
         Initialize();
     else
     else
     {
     {
-        // When screen mode changes, purge old views and occlusion buffers
-        occlusionBuffers_.Clear();
+        // When screen mode changes, purge old views
         ResetViews();
         ResetViews();
     }
     }
 }
 }

+ 11 - 9
Engine/Graphics/Renderer.h

@@ -227,18 +227,18 @@ public:
     void DrawDebugGeometry(bool depthTest);
     void DrawDebugGeometry(bool depthTest);
     /// Add a view. Return true if successful.
     /// Add a view. Return true if successful.
     bool AddView(RenderSurface* renderTarget, const Viewport& viewport);
     bool AddView(RenderSurface* renderTarget, const Viewport& viewport);
-    /// Return an occlusion buffer for use.
-    OcclusionBuffer* GetOrCreateOcclusionBuffer(Camera* camera, int maxOccluderTriangles, bool halfResolution = false);
     /// Return volume geometry for a light.
     /// Return volume geometry for a light.
     Geometry* GetLightGeometry(Light* light);
     Geometry* GetLightGeometry(Light* light);
-    /// Return shadow map for a light. 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 an occlusion buffer. Is thread-safe.
+    OcclusionBuffer* GetOcclusionBuffer(Camera* camera, bool halfResolution = false);
+    /// Allocate a temporary shadow camera and a scene node for it. Is thread-safe.
+    Camera* GetShadowCamera();
     /// Get a shader program.
     /// Get a shader program.
     ShaderVariation* GetShader(const String& name, const String& extension, bool checkExists) const;
     ShaderVariation* GetShader(const String& name, const String& extension, bool checkExists) const;
     /// Choose shaders for a batch.
     /// Choose shaders for a batch.
     void SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, bool allowShadows = true);
     void SetBatchShaders(Batch& batch, Technique* technique, Pass* pass, bool allowShadows = true);
-    /// Allocate a temporary shadow camera and a scene node for it.
-    Camera* CreateShadowCamera();
     /// 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.
     /// Reset shadow map allocation counts.
@@ -300,8 +300,8 @@ private:
     SharedPtr<ShaderVariation> stencilPS_;
     SharedPtr<ShaderVariation> stencilPS_;
     /// Reusable scene nodes with shadow camera components.
     /// Reusable scene nodes with shadow camera components.
     Vector<SharedPtr<Node> > shadowCameraNodes_;
     Vector<SharedPtr<Node> > shadowCameraNodes_;
-    /// Occlusion buffers.
-    HashMap<int, SharedPtr<OcclusionBuffer> > occlusionBuffers_;
+    /// Reusable occlusion buffers.
+    Vector<SharedPtr<OcclusionBuffer> > occlusionBuffers_;
     /// Shadow maps by resolution.
     /// Shadow maps by resolution.
     HashMap<int, Vector<SharedPtr<Texture2D> > > shadowMaps_;
     HashMap<int, Vector<SharedPtr<Texture2D> > > shadowMaps_;
     /// Shadow map dummy color buffers by resolution.
     /// Shadow map dummy color buffers by resolution.
@@ -318,7 +318,7 @@ private:
     HashSet<Octree*> updateOctrees_;
     HashSet<Octree*> updateOctrees_;
     /// Techniques for which missing shader error has been displayed.
     /// Techniques for which missing shader error has been displayed.
     HashSet<Technique*> shaderErrorDisplayed_;
     HashSet<Technique*> shaderErrorDisplayed_;
-    /// Mutex for creating shadow camers.
+    /// Mutex for shadow camera and occlusion buffer allocation.
     Mutex rendererMutex_;
     Mutex rendererMutex_;
     /// Vertex shader format.
     /// Vertex shader format.
     String vsFormat_;
     String vsFormat_;
@@ -354,7 +354,9 @@ private:
     float occluderSizeThreshold_;
     float occluderSizeThreshold_;
     /// Number of views.
     /// Number of views.
     unsigned numViews_;
     unsigned numViews_;
-    /// Number of temporary shadow cameras.
+    /// Number of occlusion buffers in use.
+    unsigned numOcclusionBuffers_;
+    /// Number of temporary shadow cameras in use.
     unsigned numShadowCameras_;
     unsigned numShadowCameras_;
     /// Number of primitives (3D geometry only.)
     /// Number of primitives (3D geometry only.)
     unsigned numPrimitives_;
     unsigned numPrimitives_;

+ 23 - 38
Engine/Graphics/View.cpp

@@ -315,9 +315,8 @@ void View::GetDrawables()
         {
         {
             PROFILE(DrawOcclusion);
             PROFILE(DrawOcclusion);
             
             
-            buffer = renderer_->GetOrCreateOcclusionBuffer(camera_, maxOccluderTriangles_);
+            buffer = renderer_->GetOcclusionBuffer(camera_);
             DrawOccluders(buffer, occluders_);
             DrawOccluders(buffer, occluders_);
-            buffer->BuildDepthHierarchy();
         }
         }
     }
     }
     
     
@@ -472,24 +471,11 @@ void View::GetBatches()
             LightQueryResult& query = lightQueryResults_[i];
             LightQueryResult& query = lightQueryResults_[i];
             query.light_ = lights_[i];
             query.light_ = lights_[i];
             
             
-            // Do not include shadowed directional lights in the work queue, as occlusion can not yet be threaded
-            query.threaded_ = query.light_->GetLightType() != LIGHT_DIRECTIONAL || !query.light_->GetCastShadows();
-            if (query.threaded_)
-            {
-                WorkItem item;
-                item.workFunction_ = ProcessLightWork;
-                item.start_ = &query;
-                item.aux_ = this;
-                queue->AddWorkItem(item);
-            }
-        }
-        
-        // Process shadowed directional lights in the main thread
-        for (unsigned i = 0; i < lightQueryResults_.Size(); ++i)
-        {
-            LightQueryResult& query = lightQueryResults_[i];
-            if (!query.threaded_)
-                ProcessLight(query, 0);
+            WorkItem item;
+            item.workFunction_ = ProcessLightWork;
+            item.start_ = &query;
+            item.aux_ = this;
+            queue->AddWorkItem(item);
         }
         }
         
         
         // Ensure all lights have been processed before proceeding
         // Ensure all lights have been processed before proceeding
@@ -965,6 +951,9 @@ void View::UpdateOccluders(PODVector<Drawable*>& occluders, Camera* camera)
 
 
 void View::DrawOccluders(OcclusionBuffer* buffer, const PODVector<Drawable*>& occluders)
 void View::DrawOccluders(OcclusionBuffer* buffer, const PODVector<Drawable*>& occluders)
 {
 {
+    buffer->SetMaxTriangles(maxOccluderTriangles_);
+    buffer->Clear();
+    
     for (unsigned i = 0; i < occluders.Size(); ++i)
     for (unsigned i = 0; i < occluders.Size(); ++i)
     {
     {
         Drawable* occluder = occluders[i];
         Drawable* occluder = occluders[i];
@@ -977,14 +966,16 @@ void View::DrawOccluders(OcclusionBuffer* buffer, const PODVector<Drawable*>& oc
         
         
         // Check for running out of triangles
         // Check for running out of triangles
         if (!occluder->DrawOcclusion(buffer))
         if (!occluder->DrawOcclusion(buffer))
-            return;
+            break;
     }
     }
+    
+    buffer->BuildDepthHierarchy();
 }
 }
 
 
 void View::ProcessLight(LightQueryResult& query, unsigned threadIndex)
 void View::ProcessLight(LightQueryResult& query, unsigned threadIndex)
 {
 {
     Light* light = query.light_;
     Light* light = query.light_;
-    PODVector<Drawable*>& tempDrawables = tempDrawables_[threadIndex];
+    LightType type = light->GetLightType();
     
     
     // Check if light should be shadowed
     // Check if light should be shadowed
     bool isShadowed = drawShadows_ && light->GetCastShadows() && light->GetShadowIntensity() < 1.0f;
     bool isShadowed = drawShadows_ && light->GetCastShadows() && light->GetShadowIntensity() < 1.0f;
@@ -992,9 +983,8 @@ void View::ProcessLight(LightQueryResult& query, unsigned threadIndex)
     if (isShadowed && light->GetShadowDistance() > 0.0f && light->GetDistance() > light->GetShadowDistance())
     if (isShadowed && light->GetShadowDistance() > 0.0f && light->GetDistance() > light->GetShadowDistance())
         isShadowed = false;
         isShadowed = false;
     
     
-    LightType type = light->GetLightType();
-    
     // Get lit geometries. They must match the light mask and be inside the main camera frustum to be considered
     // Get lit geometries. They must match the light mask and be inside the main camera frustum to be considered
+    PODVector<Drawable*>& tempDrawables = tempDrawables_[threadIndex];
     query.litGeometries_.Clear();
     query.litGeometries_.Clear();
     
     
     switch (type)
     switch (type)
@@ -1051,26 +1041,21 @@ void View::ProcessLight(LightQueryResult& query, unsigned threadIndex)
     if (maxOccluderTriangles_ > 0 && isShadowed && light->GetLightType() == LIGHT_DIRECTIONAL)
     if (maxOccluderTriangles_ > 0 && isShadowed && light->GetLightType() == LIGHT_DIRECTIONAL)
     {
     {
         // This shadow camera is never used for actually querying shadow casters, just occluders
         // This shadow camera is never used for actually querying shadow casters, just occluders
-        Camera* shadowCamera = renderer_->CreateShadowCamera();
+        Camera* shadowCamera = renderer_->GetShadowCamera();
         SetupDirLightShadowCamera(shadowCamera, light, 0.0f, Min(light->GetShadowCascade().GetShadowRange(),
         SetupDirLightShadowCamera(shadowCamera, light, 0.0f, Min(light->GetShadowCascade().GetShadowRange(),
             camera_->GetFarClip()), true);
             camera_->GetFarClip()), true);
         
         
         // Get occluders, which must be shadow-casting themselves
         // Get occluders, which must be shadow-casting themselves
-        FrustumOctreeQuery octreeQuery(shadowOccluders_, shadowCamera->GetFrustum(), DRAWABLE_GEOMETRY, camera_->GetViewMask(),
+        FrustumOctreeQuery octreeQuery(tempDrawables, shadowCamera->GetFrustum(), DRAWABLE_GEOMETRY, camera_->GetViewMask(),
             true, true);
             true, true);
         octree_->GetDrawables(octreeQuery);
         octree_->GetDrawables(octreeQuery);
+        UpdateOccluders(tempDrawables, shadowCamera);
         
         
-        UpdateOccluders(shadowOccluders_, shadowCamera);
-        
-        if (shadowOccluders_.Size())
+        if (tempDrawables.Size())
         {
         {
-            PROFILE(DrawDirLightOcclusion);
-            
             // Shadow viewport is rectangular and consumes more CPU fillrate, so halve size
             // Shadow viewport is rectangular and consumes more CPU fillrate, so halve size
-            buffer = renderer_->GetOrCreateOcclusionBuffer(shadowCamera, maxOccluderTriangles_, true);
-            
-            DrawOccluders(buffer, shadowOccluders_);
-            buffer->BuildDepthHierarchy();
+            buffer = renderer_->GetOcclusionBuffer(shadowCamera, true);
+            DrawOccluders(buffer, tempDrawables);
             useOcclusion = true;
             useOcclusion = true;
         }
         }
     }
     }
@@ -1400,7 +1385,7 @@ void View::SetupShadowCameras(LightQueryResult& query)
                 break;
                 break;
             
             
             // Setup the shadow camera for the split
             // Setup the shadow camera for the split
-            Camera* shadowCamera = renderer_->CreateShadowCamera();
+            Camera* shadowCamera = renderer_->GetShadowCamera();
             query.shadowCameras_[splits] = shadowCamera;
             query.shadowCameras_[splits] = shadowCamera;
             query.shadowNearSplits_[splits] = nearSplit;
             query.shadowNearSplits_[splits] = nearSplit;
             query.shadowFarSplits_[splits] = farSplit;
             query.shadowFarSplits_[splits] = farSplit;
@@ -1413,7 +1398,7 @@ void View::SetupShadowCameras(LightQueryResult& query)
     
     
     if (type == LIGHT_SPOT)
     if (type == LIGHT_SPOT)
     {
     {
-        Camera* shadowCamera = renderer_->CreateShadowCamera();
+        Camera* shadowCamera = renderer_->GetShadowCamera();
         query.shadowCameras_[0] = shadowCamera;
         query.shadowCameras_[0] = shadowCamera;
         Node* cameraNode = shadowCamera->GetNode();
         Node* cameraNode = shadowCamera->GetNode();
         
         
@@ -1430,7 +1415,7 @@ void View::SetupShadowCameras(LightQueryResult& query)
     {
     {
         for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
         for (unsigned i = 0; i < MAX_CUBEMAP_FACES; ++i)
         {
         {
-            Camera* shadowCamera = renderer_->CreateShadowCamera();
+            Camera* shadowCamera = renderer_->GetShadowCamera();
             query.shadowCameras_[i] = shadowCamera;
             query.shadowCameras_[i] = shadowCamera;
             Node* cameraNode = shadowCamera->GetNode();
             Node* cameraNode = shadowCamera->GetNode();
             
             

+ 0 - 4
Engine/Graphics/View.h

@@ -56,8 +56,6 @@ struct LightQueryResult
 {
 {
     /// Light.
     /// Light.
     Light* light_;
     Light* light_;
-    /// Threaded processing flag.
-    bool threaded_;
     /// Lit geometries.
     /// Lit geometries.
     PODVector<Drawable*> litGeometries_;
     PODVector<Drawable*> litGeometries_;
     /// Shadow casters.
     /// Shadow casters.
@@ -234,8 +232,6 @@ private:
     PODVector<Drawable*> threadedGeometries_;
     PODVector<Drawable*> threadedGeometries_;
     /// Occluder objects.
     /// Occluder objects.
     PODVector<Drawable*> occluders_;
     PODVector<Drawable*> occluders_;
-    /// Directional light shadow rendering occluders.
-    PODVector<Drawable*> shadowOccluders_;
     /// Depth minimum and maximum values for visible geometries.
     /// Depth minimum and maximum values for visible geometries.
     PODVector<GeometryDepthBounds> geometryDepthBounds_;
     PODVector<GeometryDepthBounds> geometryDepthBounds_;
     /// Lights.
     /// Lights.