diff --git a/Content/Editor/MaterialTemplates/Deformable.shader b/Content/Editor/MaterialTemplates/Deformable.shader
index 044f7184c..ace304e68 100644
--- a/Content/Editor/MaterialTemplates/Deformable.shader
+++ b/Content/Editor/MaterialTemplates/Deformable.shader
@@ -374,4 +374,18 @@ void PS_Depth(PixelInput input)
#endif
}
+#if _PS_QuadOverdraw
+
+#include "./Flax/Editor/QuadOverdraw.hlsl"
+
+// Pixel Shader function for Quad Overdraw Pass (editor-only)
+[earlydepthstencil]
+META_PS(USE_EDITOR, FEATURE_LEVEL_SM5)
+void PS_QuadOverdraw(float4 svPos : SV_Position, uint primId : SV_PrimitiveID)
+{
+ DoQuadOverdraw(svPos, primId);
+}
+
+#endif
+
@9
diff --git a/Content/Editor/MaterialTemplates/Particle.shader b/Content/Editor/MaterialTemplates/Particle.shader
index 726ad225a..a3736a53e 100644
--- a/Content/Editor/MaterialTemplates/Particle.shader
+++ b/Content/Editor/MaterialTemplates/Particle.shader
@@ -694,4 +694,18 @@ void PS_Depth(PixelInput input)
#endif
}
+#if _PS_QuadOverdraw
+
+#include "./Flax/Editor/QuadOverdraw.hlsl"
+
+// Pixel Shader function for Quad Overdraw Pass (editor-only)
+[earlydepthstencil]
+META_PS(USE_EDITOR, FEATURE_LEVEL_SM5)
+void PS_QuadOverdraw(float4 svPos : SV_Position, uint primId : SV_PrimitiveID)
+{
+ DoQuadOverdraw(svPos, primId);
+}
+
+#endif
+
@9
diff --git a/Content/Editor/MaterialTemplates/Surface.shader b/Content/Editor/MaterialTemplates/Surface.shader
index fe9223dce..cf6e00e36 100644
--- a/Content/Editor/MaterialTemplates/Surface.shader
+++ b/Content/Editor/MaterialTemplates/Surface.shader
@@ -594,7 +594,7 @@ void ClipLODTransition(PixelInput input)
// Pixel Shader function for Depth Pass
META_PS(true, FEATURE_LEVEL_ES2)
void PS_Depth(PixelInput input)
-{
+{
#if USE_DITHERED_LOD_TRANSITION
// LOD masking
ClipLODTransition(input);
@@ -615,4 +615,18 @@ void PS_Depth(PixelInput input)
#endif
}
+#if _PS_QuadOverdraw
+
+#include "./Flax/Editor/QuadOverdraw.hlsl"
+
+// Pixel Shader function for Quad Overdraw Pass (editor-only)
+[earlydepthstencil]
+META_PS(USE_EDITOR, FEATURE_LEVEL_SM5)
+void PS_QuadOverdraw(float4 svPos : SV_Position, uint primId : SV_PrimitiveID)
+{
+ DoQuadOverdraw(svPos, primId);
+}
+
+#endif
+
@9
diff --git a/Content/Editor/MaterialTemplates/Terrain.shader b/Content/Editor/MaterialTemplates/Terrain.shader
index a7172e381..1326bd0eb 100644
--- a/Content/Editor/MaterialTemplates/Terrain.shader
+++ b/Content/Editor/MaterialTemplates/Terrain.shader
@@ -458,4 +458,18 @@ void PS_Depth(PixelInput input)
#endif
}
+#if _PS_QuadOverdraw
+
+#include "./Flax/Editor/QuadOverdraw.hlsl"
+
+// Pixel Shader function for Quad Overdraw Pass (editor-only)
+[earlydepthstencil]
+META_PS(USE_EDITOR, FEATURE_LEVEL_SM5)
+void PS_QuadOverdraw(float4 svPos : SV_Position, uint primId : SV_PrimitiveID)
+{
+ DoQuadOverdraw(svPos, primId);
+}
+
+#endif
+
@9
diff --git a/Content/Shaders/Editor/QuadOverdraw.flax b/Content/Shaders/Editor/QuadOverdraw.flax
new file mode 100644
index 000000000..dbce04d1c
--- /dev/null
+++ b/Content/Shaders/Editor/QuadOverdraw.flax
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b44265c808f5d662a4b27dd0fe59974ea1e7c7ad5a76d95a558291ff88429a2b
+size 1448
diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs
index 9fe45eecc..78f7417ef 100644
--- a/Source/Editor/Viewport/EditorViewport.cs
+++ b/Source/Editor/Viewport/EditorViewport.cs
@@ -1399,6 +1399,7 @@ namespace FlaxEditor.Viewport
new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders"),
new ViewModeOptions(ViewMode.LODPreview, "LOD Preview"),
new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"),
+ new ViewModeOptions(ViewMode.QuadOverdraw, "Quad Overdraw"),
};
private void WidgetCamSpeedShowHide(Control cm)
diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h
index eed42ba27..2c1ce286d 100644
--- a/Source/Engine/Graphics/Enums.h
+++ b/Source/Engine/Graphics/Enums.h
@@ -689,6 +689,12 @@ API_ENUM(Attributes="Flags") enum class DrawPass : int32
///
MotionVectors = 1 << 4,
+ ///
+ /// The debug quad overdraw rendering (editor-only).
+ ///
+ API_ENUM(Attributes="HideInEditor")
+ QuadOverdraw = 1 << 20,
+
///
/// The default set of draw passes for the scene objects.
///
@@ -823,6 +829,11 @@ API_ENUM() enum class ViewMode
/// Draw material shaders complexity to visualize performance of pixels rendering.
///
MaterialComplexity = 22,
+
+ ///
+ /// Draw geometry overdraw to visualize performance of pixels rendering.
+ ///
+ QuadOverdraw = 23,
};
///
diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp
index e904dc9fa..17dee07c2 100644
--- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.cpp
@@ -40,7 +40,7 @@ PACK_STRUCT(struct DeferredMaterialShaderData {
DrawPass DeferredMaterialShader::GetDrawModes() const
{
- return DrawPass::Depth | DrawPass::GBuffer | DrawPass::MotionVectors;
+ return DrawPass::Depth | DrawPass::GBuffer | DrawPass::MotionVectors | DrawPass::QuadOverdraw;
}
bool DeferredMaterialShader::CanUseLightmap() const
@@ -195,6 +195,17 @@ bool DeferredMaterialShader::Load()
psDesc.PS = _shader->GetPS("PS_GBuffer");
_cache.DefaultSkinned.Init(psDesc);
+#if USE_EDITOR
+ // Quad Overdraw
+ psDesc.VS = _shader->GetVS("VS");
+ psDesc.PS = _shader->GetPS("PS_QuadOverdraw");
+ _cache.QuadOverdraw.Init(psDesc);
+ psDesc.VS = _shader->GetVS("VS", 1);
+ _cacheInstanced.Depth.Init(psDesc);
+ psDesc.VS = _shader->GetVS("VS_Skinned");
+ _cache.QuadOverdrawSkinned.Init(psDesc);
+#endif
+
// Motion Vectors pass
psDesc.DepthWriteEnable = false;
psDesc.DepthTestEnable = true;
diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.h b/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
index b8886769d..2f3e8caf0 100644
--- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
@@ -21,6 +21,10 @@ private:
PipelineStateCache MotionVectors;
PipelineStateCache MotionVectorsSkinned;
PipelineStateCache MotionVectorsSkinnedPerBone;
+#if USE_EDITOR
+ PipelineStateCache QuadOverdraw;
+ PipelineStateCache QuadOverdrawSkinned;
+#endif
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass, const bool useLightmap, const bool useSkinning, const bool perBoneMotionBlur)
{
@@ -32,6 +36,10 @@ private:
return useLightmap ? &DefaultLightmap : (useSkinning ? &DefaultSkinned : &Default);
case DrawPass::MotionVectors:
return useSkinning ? (perBoneMotionBlur ? &MotionVectorsSkinnedPerBone : &MotionVectorsSkinned) : &MotionVectors;
+#if USE_EDITOR
+ case DrawPass::QuadOverdraw:
+ return useSkinning ? &QuadOverdrawSkinned : &QuadOverdraw;
+#endif
default:
return nullptr;
}
@@ -46,6 +54,10 @@ private:
DepthSkinned.Release();
MotionVectors.Release();
MotionVectorsSkinned.Release();
+#if USE_EDITOR
+ QuadOverdraw.Release();
+ QuadOverdrawSkinned.Release();
+#endif
}
};
diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp
index 1c967bf34..d881627d9 100644
--- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.cpp
@@ -128,7 +128,7 @@ void DeformableMaterialShader::Unload()
bool DeformableMaterialShader::Load()
{
- _drawModes = DrawPass::Depth;
+ _drawModes = DrawPass::Depth | DrawPass::QuadOverdraw;
auto psDesc = GPUPipelineState::Description::Default;
psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == 0;
psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == 0;
@@ -140,6 +140,13 @@ bool DeformableMaterialShader::Load()
psDesc.HS = _shader->GetHS("HS");
psDesc.DS = _shader->GetDS("DS");
}
+
+#if USE_EDITOR
+ // Quad Overdraw
+ psDesc.VS = _shader->GetVS("VS_SplineModel");
+ psDesc.PS = _shader->GetPS("PS_QuadOverdraw");
+ _cache.QuadOverdraw.Init(psDesc);
+#endif
if (_info.BlendMode == MaterialBlendMode::Opaque)
{
diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.h b/Source/Engine/Graphics/Materials/DeformableMaterialShader.h
index c3040ded3..a046fc14e 100644
--- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.h
@@ -15,6 +15,9 @@ private:
{
PipelineStateCache Default;
PipelineStateCache Depth;
+#if USE_EDITOR
+ PipelineStateCache QuadOverdraw;
+#endif
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass)
{
@@ -25,6 +28,10 @@ private:
case DrawPass::GBuffer:
case DrawPass::Forward:
return &Default;
+#if USE_EDITOR
+ case DrawPass::QuadOverdraw:
+ return &QuadOverdraw;
+#endif
default:
return nullptr;
}
@@ -34,6 +41,9 @@ private:
{
Default.Release();
Depth.Release();
+#if USE_EDITOR
+ QuadOverdraw.Release();
+#endif
}
};
diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp
index 94f57e725..563c6cb00 100644
--- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.cpp
@@ -154,7 +154,7 @@ void ForwardMaterialShader::Unload()
bool ForwardMaterialShader::Load()
{
- _drawModes = DrawPass::Depth | DrawPass::Forward;
+ _drawModes = DrawPass::Depth | DrawPass::Forward | DrawPass::QuadOverdraw;
auto psDesc = GPUPipelineState::Description::Default;
psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == 0;
@@ -168,6 +168,17 @@ bool ForwardMaterialShader::Load()
psDesc.DS = _shader->GetDS("DS");
}
+#if USE_EDITOR
+ // Quad Overdraw
+ psDesc.VS = _shader->GetVS("VS");
+ psDesc.PS = _shader->GetPS("PS_QuadOverdraw");
+ _cache.QuadOverdraw.Init(psDesc);
+ psDesc.VS = _shader->GetVS("VS", 1);
+ _cacheInstanced.Depth.Init(psDesc);
+ psDesc.VS = _shader->GetVS("VS_Skinned");
+ _cache.QuadOverdrawSkinned.Init(psDesc);
+#endif
+
// Check if use transparent distortion pass
if (_shader->HasShader("PS_Distortion"))
{
diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.h b/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
index dd053717f..cfbe0bda1 100644
--- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
@@ -19,6 +19,10 @@ private:
PipelineStateCache DepthSkinned;
PipelineStateCache Distortion;
PipelineStateCache DistortionSkinned;
+#if USE_EDITOR
+ PipelineStateCache QuadOverdraw;
+ PipelineStateCache QuadOverdrawSkinned;
+#endif
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass, const bool useSkinning)
{
@@ -30,6 +34,10 @@ private:
return useSkinning ? &DistortionSkinned : &Distortion;
case DrawPass::Forward:
return useSkinning ? &DefaultSkinned : &Default;
+#if USE_EDITOR
+ case DrawPass::QuadOverdraw:
+ return useSkinning ? &QuadOverdrawSkinned : &QuadOverdraw;
+#endif
default:
return nullptr;
}
diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp
index 77251e803..bc5748f56 100644
--- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.cpp
@@ -201,7 +201,7 @@ void ParticleMaterialShader::Unload()
bool ParticleMaterialShader::Load()
{
- _drawModes = DrawPass::Depth | DrawPass::Forward;
+ _drawModes = DrawPass::Depth | DrawPass::Forward | DrawPass::QuadOverdraw;
GPUPipelineState::Description psDesc = GPUPipelineState::Description::Default;
psDesc.DepthTestEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthTest) == 0;
psDesc.DepthWriteEnable = (_info.FeaturesFlags & MaterialFeaturesFlags::DisableDepthWrite) == 0;
@@ -210,6 +210,17 @@ bool ParticleMaterialShader::Load()
auto vsMesh = _shader->GetVS("VS_Model");
auto vsRibbon = _shader->GetVS("VS_Ribbon");
+#if USE_EDITOR
+ // Quad Overdraw
+ psDesc.PS = _shader->GetPS("PS_QuadOverdraw");
+ psDesc.VS = vsSprite;
+ _cacheSprite.QuadOverdraw.Init(psDesc);
+ psDesc.VS = vsMesh;
+ _cacheModel.QuadOverdraw.Init(psDesc);
+ psDesc.VS = vsRibbon;
+ _cacheRibbon.QuadOverdraw.Init(psDesc);
+#endif
+
// Check if use transparent distortion pass
if (_shader->HasShader("PS_Distortion"))
{
diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.h b/Source/Engine/Graphics/Materials/ParticleMaterialShader.h
index 28a52ddf5..69e406749 100644
--- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.h
@@ -16,6 +16,9 @@ private:
PipelineStateCache Default;
PipelineStateCache Depth;
PipelineStateCache Distortion;
+#if USE_EDITOR
+ PipelineStateCache QuadOverdraw;
+#endif
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass)
{
@@ -27,6 +30,8 @@ private:
return &Distortion;
case DrawPass::Forward:
return &Default;
+ case DrawPass::QuadOverdraw:
+ return &QuadOverdraw;
default:
return nullptr;
}
@@ -37,6 +42,9 @@ private:
Default.Release();
Depth.Release();
Distortion.Release();
+#if USE_EDITOR
+ QuadOverdraw.Release();
+#endif
}
};
diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp
index f728bac97..cecf081bd 100644
--- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.cpp
@@ -183,6 +183,12 @@ bool TerrainMaterialShader::Load()
// GBuffer Pass with lightmap (use pixel shader permutation for USE_LIGHTMAP=1)
psDesc.PS = _shader->GetPS("PS_GBuffer", 1);
_cache.DefaultLightmap.Init(psDesc);
+
+#if USE_EDITOR
+ // Quad Overdraw
+ psDesc.PS = _shader->GetPS("PS_QuadOverdraw");
+ _cache.QuadOverdraw.Init(psDesc);
+#endif
// Depth Pass
psDesc.CullMode = CullMode::TwoSided;
diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.h b/Source/Engine/Graphics/Materials/TerrainMaterialShader.h
index 519233807..cf4f4fce0 100644
--- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.h
@@ -16,6 +16,9 @@ private:
PipelineStateCache Default;
PipelineStateCache DefaultLightmap;
PipelineStateCache Depth;
+#if USE_EDITOR
+ PipelineStateCache QuadOverdraw;
+#endif
FORCE_INLINE PipelineStateCache* GetPS(const DrawPass pass, const bool useLightmap)
{
@@ -25,6 +28,10 @@ private:
return &Depth;
case DrawPass::GBuffer:
return useLightmap ? &DefaultLightmap : &Default;
+#if USE_EDITOR
+ case DrawPass::QuadOverdraw:
+ return &QuadOverdraw;
+#endif
default:
return nullptr;
}
@@ -35,6 +42,9 @@ private:
Default.Release();
DefaultLightmap.Release();
Depth.Release();
+#if USE_EDITOR
+ QuadOverdraw.Release();
+#endif
}
};
diff --git a/Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp b/Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp
new file mode 100644
index 000000000..4d450422f
--- /dev/null
+++ b/Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp
@@ -0,0 +1,158 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+#if USE_EDITOR
+
+#include "QuadOverdrawPass.h"
+#include "Engine/Engine/Time.h"
+#include "Engine/Content/Content.h"
+#include "Engine/Content/Assets/Material.h"
+#include "Engine/Level/Actors/Decal.h"
+#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/Shaders/GPUShader.h"
+#include "Engine/Graphics/RenderTask.h"
+#include "Engine/Graphics/RenderBuffers.h"
+#include "Engine/Graphics/RenderTargetPool.h"
+#include "Engine/Renderer/RenderList.h"
+
+void QuadOverdrawPass::Render(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer)
+{
+ if (checkIfSkipPass())
+ {
+ context->Clear(lightBuffer, Color(0, Math::Sin(Time::Draw.UnscaledTime.GetTotalSeconds() * 5.0f) * 0.5f + 0.5f, 0, 1.0f));
+ return;
+ }
+ PROFILE_GPU_CPU("Quad Overdraw");
+
+ // Setup resources
+ const int32 width = renderContext.Buffers->GetWidth();
+ const int32 height = renderContext.Buffers->GetHeight();
+ auto tempDesc = GPUTextureDescription::New2D(width >> 1, height >> 1, PixelFormat::R32_UInt, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess);
+ auto lockTexture = RenderTargetPool::Get(tempDesc);
+ auto overdrawTexture = RenderTargetPool::Get(tempDesc);
+ auto liveCountTexture = RenderTargetPool::Get(tempDesc);
+
+ // Clear buffers
+ uint32 clearValueUINT[4] = { 0 };
+ clearValueUINT[0] = 0xffffffff;
+ context->ClearUA(lockTexture, clearValueUINT);
+ clearValueUINT[0] = 0x00000000;
+ context->ClearUA(overdrawTexture, clearValueUINT);
+ context->ClearUA(liveCountTexture, clearValueUINT);
+ context->ClearDepth(*renderContext.Buffers->DepthBuffer);
+
+ // Draw quad overdraw stats into UAVs
+ context->BindUA(0, lockTexture->View());
+ context->BindUA(1, overdrawTexture->View());
+ context->BindUA(2, liveCountTexture->View());
+ DrawCall drawCall;
+ Platform::MemoryClear(&drawCall, sizeof(DrawCall));
+ drawCall.PerInstanceRandom = 1.0f;
+ MaterialBase::BindParameters bindParams(context, renderContext, drawCall);
+ renderContext.View.Pass = DrawPass::QuadOverdraw;
+ context->SetRenderTarget(*renderContext.Buffers->DepthBuffer, (GPUTextureView*)nullptr);
+ renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::GBuffer);
+ auto boxModel = Content::LoadAsyncInternal(TEXT("Engine/Models/SimpleBox"));
+ auto defaultMaterial = GPUDevice::Instance->GetDefaultMaterial();
+ if (boxModel && boxModel->CanBeRendered() && defaultMaterial && defaultMaterial->IsReady())
+ {
+ // Draw decals
+ for (int32 i = 0; i < renderContext.List->Decals.Count(); i++)
+ {
+ const auto decal = renderContext.List->Decals[i];
+ ASSERT(decal && decal->Material);
+ decal->GetWorld(&drawCall.World);
+ drawCall.ObjectPosition = drawCall.World.GetTranslation();
+ drawCall.PerInstanceRandom = decal->GetPerInstanceRandom();
+ defaultMaterial->Bind(bindParams);
+ boxModel->Render(context);
+ }
+ }
+ renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::GBufferNoDecals);
+ auto skyModel = Content::LoadAsyncInternal(TEXT("Engine/Models/Sphere"));
+ auto skyMaterial = Content::LoadAsyncInternal(TEXT("Engine/SkyboxMaterial"));
+ if (renderContext.List->Sky && skyModel && skyModel->CanBeRendered() && skyMaterial && skyMaterial->IsReady())
+ {
+ // Draw sky
+ auto box = skyModel->GetBox();
+ Matrix m1, m2;
+ Matrix::Scaling(renderContext.View.Far / (box.GetSize().Y * 0.5f) * 0.95f, m1);
+ Matrix::CreateWorld(renderContext.View.Position, Vector3::Up, Vector3::Backward, m2);
+ m1 *= m2;
+ drawCall.World = m1;
+ drawCall.ObjectPosition = drawCall.World.GetTranslation();
+ drawCall.WorldDeterminantSign = Math::FloatSelect(drawCall.World.RotDeterminant(), 1, -1);
+ skyMaterial->Bind(bindParams);
+ skyModel->Render(context);
+ }
+ GPUTexture* depthBuffer = renderContext.Buffers->DepthBuffer;
+ GPUTextureView* readOnlyDepthBuffer = depthBuffer->View();
+ if (depthBuffer->GetDescription().Flags & GPUTextureFlags::ReadOnlyDepthView)
+ readOnlyDepthBuffer = depthBuffer->ViewReadOnlyDepth();
+ context->ResetSR();
+ context->ResetRenderTarget();
+ context->SetRenderTarget(readOnlyDepthBuffer, (GPUTextureView*)nullptr);
+ renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::Forward);
+ renderContext.List->ExecuteDrawCalls(renderContext, DrawCallsListType::Distortion);
+ // TODO: draw volumetric particles
+ context->ResetRenderTarget();
+ context->ResetUA();
+ context->ResetSR();
+
+ // Convert stats into debug colors
+ context->BindSR(0, overdrawTexture->View());
+ context->SetRenderTarget(lightBuffer);
+ context->SetState(_ps);
+ context->DrawFullscreenTriangle();
+
+ // Free resources
+ RenderTargetPool::Release(liveCountTexture);
+ RenderTargetPool::Release(overdrawTexture);
+ RenderTargetPool::Release(lockTexture);
+}
+
+String QuadOverdrawPass::ToString() const
+{
+ return TEXT("QuadOverdrawPass");
+}
+
+void QuadOverdrawPass::Dispose()
+{
+ // Base
+ RendererPass::Dispose();
+
+ SAFE_DELETE_GPU_RESOURCE(_ps);
+ _shader = nullptr;
+}
+
+bool QuadOverdrawPass::setupResources()
+{
+ if (GPUDevice::Instance->GetFeatureLevel() < FeatureLevel::SM5)
+ return true;
+
+ if (!_shader)
+ {
+ _shader = Content::LoadAsyncInternal(TEXT("Shaders/Editor/QuadOverdraw"));
+ if (!_shader)
+ return true;
+#if COMPILE_WITH_DEV_ENV
+ _shader.Get()->OnReloading.Bind(this);
+#endif
+ }
+ if (!_shader->IsLoaded())
+ return true;
+ const auto shader = _shader->GetShader();
+
+ GPUPipelineState::Description psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle;
+ if (!_ps)
+ _ps = GPUDevice::Instance->CreatePipelineState();
+ if (!_ps->IsValid())
+ {
+ psDesc.PS = shader->GetPS("PS");
+ if (_ps->Init(psDesc))
+ return true;
+ }
+
+ return false;
+}
+
+#endif
diff --git a/Source/Engine/Renderer/Editor/QuadOverdrawPass.h b/Source/Engine/Renderer/Editor/QuadOverdrawPass.h
new file mode 100644
index 000000000..5d1cc6140
--- /dev/null
+++ b/Source/Engine/Renderer/Editor/QuadOverdrawPass.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+#pragma once
+
+#if USE_EDITOR
+
+#include "../RendererPass.h"
+
+class GPUContext;
+class GPUTextureView;
+class GPUPipelineState;
+struct RenderContext;
+
+///
+/// Rendering geometry overdraw to visualize performance of pixels rendering in editor.
+///
+class QuadOverdrawPass : public RendererPass
+{
+private:
+
+ AssetReference _shader;
+ GPUPipelineState* _ps = nullptr;
+
+#if COMPILE_WITH_DEV_ENV
+ void OnShaderReloading(Asset* obj)
+ {
+ _ps->ReleaseGPU();
+ invalidateResources();
+ }
+#endif
+
+public:
+
+ void Render(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer);
+
+ // [RendererPass]
+ String ToString() const override;
+ void Dispose() override;
+
+protected:
+
+ // [RendererPass]
+ bool setupResources() override;
+};
+
+#endif
diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp
index f974d1898..fe90a3560 100644
--- a/Source/Engine/Renderer/Renderer.cpp
+++ b/Source/Engine/Renderer/Renderer.cpp
@@ -30,6 +30,7 @@
#include "Engine/Level/Level.h"
#if USE_EDITOR
#include "Editor/Editor.h"
+#include "Editor/QuadOverdrawPass.h"
#endif
#if USE_EDITOR
@@ -80,6 +81,9 @@ bool RendererService::Init()
PassList.Add(TAA::Instance());
PassList.Add(SMAA::Instance());
PassList.Add(HistogramPass::Instance());
+#if USE_EDITOR
+ PassList.Add(QuadOverdrawPass::Instance());
+#endif
// Skip when using Null renderer
if (GPUDevice::Instance->GetRendererType() == RendererType::Null)
@@ -320,6 +324,19 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext)
auto tempDesc = GPUTextureDescription::New2D(renderContext.Buffers->GetWidth(), renderContext.Buffers->GetHeight(), PixelFormat::R11G11B10_Float);
auto lightBuffer = RenderTargetPool::Get(tempDesc);
+#if USE_EDITOR
+ if (renderContext.View.Mode == ViewMode::QuadOverdraw)
+ {
+ QuadOverdrawPass::Instance()->Render(renderContext, context, lightBuffer->View());
+ context->ResetRenderTarget();
+ context->SetRenderTarget(task->GetOutputView());
+ context->SetViewportAndScissors(task->GetOutputViewport());
+ context->Draw(lightBuffer);
+ RenderTargetPool::Release(lightBuffer);
+ return;
+ }
+#endif
+
// Fill GBuffer
GBufferPass::Instance()->Fill(renderContext, lightBuffer->View());
diff --git a/Source/Shaders/Editor/QuadOverdraw.hlsl b/Source/Shaders/Editor/QuadOverdraw.hlsl
new file mode 100644
index 000000000..12e9ba9a5
--- /dev/null
+++ b/Source/Shaders/Editor/QuadOverdraw.hlsl
@@ -0,0 +1,48 @@
+// [Quad Overdraw implementation based on https://blog.selfshadow.com/2012/11/12/counting-quads/ by Stephen Hill]
+#ifndef __QUAD_OVERDRAW__
+#define __QUAD_OVERDRAW__
+
+RWTexture2D lockUAV : register(u0);
+RWTexture2D overdrawUAV : register(u1);
+RWTexture2D liveCountUAV : register(u2);
+
+void DoQuadOverdraw(float4 svPos, uint primId)
+{
+ uint2 quad = svPos.xy * 0.5;
+ uint prevID;
+ uint unlockedID = 0xffffffff;
+ bool processed = false;
+ int lockCount = 0;
+ int pixelCount = 0;
+
+ for (int i = 0; i < 64; i++)
+ {
+ if (!processed)
+ InterlockedCompareExchange(lockUAV[quad], unlockedID, primId, prevID);
+ [branch]
+ if (prevID == unlockedID)
+ {
+ if (++lockCount == 4)
+ {
+ // Retrieve live pixel count (minus 1) in quad
+ InterlockedAnd(liveCountUAV[quad], 0, pixelCount);
+
+ // Unlock for other quads
+ InterlockedExchange(lockUAV[quad], unlockedID, prevID);
+ }
+ processed = true;
+ }
+ if (prevID == primId && !processed)
+ {
+ InterlockedAdd(liveCountUAV[quad], 1);
+ processed = true;
+ }
+ }
+
+ if (lockCount)
+ {
+ InterlockedAdd(overdrawUAV[quad], 1);
+ }
+}
+
+#endif
diff --git a/Source/Shaders/Editor/QuadOverdraw.shader b/Source/Shaders/Editor/QuadOverdraw.shader
new file mode 100644
index 000000000..49859da2e
--- /dev/null
+++ b/Source/Shaders/Editor/QuadOverdraw.shader
@@ -0,0 +1,34 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+#include "./Flax/Common.hlsl"
+
+// [Quad Overdraw implementation based on https://blog.selfshadow.com/2012/11/12/counting-quads/ by Stephen Hill]
+
+Texture2D overdrawSRV : register(t0);
+
+float4 ToColour(uint v)
+{
+ const uint nbColours = 10;
+ const float4 colours[nbColours] =
+ {
+ float4(0, 0, 0, 255),
+ float4(2, 147, 25, 255),
+ float4(0, 255, 149, 255),
+ float4(0, 255, 253, 255),
+ float4(142, 250, 0, 255),
+ float4(225, 251, 0, 255),
+ float4(225, 147, 0, 255),
+ float4(225, 38, 0, 255),
+ float4(148, 17, 0, 255),
+ float4(255, 255, 255, 255)
+ };
+ return colours[min(v, nbColours - 1)] / 255.0;
+}
+
+META_PS(true, FEATURE_LEVEL_ES2)
+float4 PS(float4 svPos : SV_POSITION) : SV_Target
+{
+ uint2 quad = svPos.xy * 0.5;
+ uint overdraw = overdrawSRV[quad];
+ return ToColour(overdraw);
+}