From 1af5ec84928e1697036608d79dae043a19de27d3 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 7 Oct 2021 14:59:06 +0200 Subject: [PATCH] Add Quad Overdraw debug view mode --- .../MaterialTemplates/Deformable.shader | 14 ++ .../Editor/MaterialTemplates/Particle.shader | 14 ++ .../Editor/MaterialTemplates/Surface.shader | 16 +- .../Editor/MaterialTemplates/Terrain.shader | 14 ++ Content/Shaders/Editor/QuadOverdraw.flax | 3 + Source/Editor/Viewport/EditorViewport.cs | 1 + Source/Engine/Graphics/Enums.h | 11 ++ .../Materials/DeferredMaterialShader.cpp | 13 +- .../Materials/DeferredMaterialShader.h | 12 ++ .../Materials/DeformableMaterialShader.cpp | 9 +- .../Materials/DeformableMaterialShader.h | 10 ++ .../Materials/ForwardMaterialShader.cpp | 13 +- .../Materials/ForwardMaterialShader.h | 8 + .../Materials/ParticleMaterialShader.cpp | 13 +- .../Materials/ParticleMaterialShader.h | 8 + .../Materials/TerrainMaterialShader.cpp | 6 + .../Materials/TerrainMaterialShader.h | 10 ++ .../Renderer/Editor/QuadOverdrawPass.cpp | 158 ++++++++++++++++++ .../Engine/Renderer/Editor/QuadOverdrawPass.h | 46 +++++ Source/Engine/Renderer/Renderer.cpp | 17 ++ Source/Shaders/Editor/QuadOverdraw.hlsl | 48 ++++++ Source/Shaders/Editor/QuadOverdraw.shader | 34 ++++ 22 files changed, 473 insertions(+), 5 deletions(-) create mode 100644 Content/Shaders/Editor/QuadOverdraw.flax create mode 100644 Source/Engine/Renderer/Editor/QuadOverdrawPass.cpp create mode 100644 Source/Engine/Renderer/Editor/QuadOverdrawPass.h create mode 100644 Source/Shaders/Editor/QuadOverdraw.hlsl create mode 100644 Source/Shaders/Editor/QuadOverdraw.shader 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); +}