diff --git a/Content/Editor/DebugMaterials/Single Color Decal.flax b/Content/Editor/DebugMaterials/Single Color Decal.flax new file mode 100644 index 000000000..253c2ccfa --- /dev/null +++ b/Content/Editor/DebugMaterials/Single Color Decal.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:371052df4841d57e2c456efaea81d78724be7cae79877501842380a1da70aa11 +size 7822 diff --git a/Content/Editor/DebugMaterials/Single Color Particle.flax b/Content/Editor/DebugMaterials/Single Color Particle.flax new file mode 100644 index 000000000..47bf1fb98 --- /dev/null +++ b/Content/Editor/DebugMaterials/Single Color Particle.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aff628df99046827a82ff8feba7b1f9ab1f3f7f5ea12bc061f984422062db5fb +size 31040 diff --git a/Content/Editor/DebugMaterials/Single Color Surface Additive.flax b/Content/Editor/DebugMaterials/Single Color Surface Additive.flax new file mode 100644 index 000000000..d1f9e22af --- /dev/null +++ b/Content/Editor/DebugMaterials/Single Color Surface Additive.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:380dfd7f69fa61dd662e8c3d7524683135168fd2b4a7e72226dd7d96bb5bbee6 +size 30512 diff --git a/Content/Editor/DebugMaterials/Single Color Surface.flax b/Content/Editor/DebugMaterials/Single Color Surface.flax new file mode 100644 index 000000000..cb4d0baf3 --- /dev/null +++ b/Content/Editor/DebugMaterials/Single Color Surface.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:24a7914a0e0a5e1db0a0fa30fd423e8c4eb3ea9a5688ac5c73749e2738ab5d29 +size 29912 diff --git a/Content/Editor/DebugMaterials/Single Color Terrain.flax b/Content/Editor/DebugMaterials/Single Color Terrain.flax new file mode 100644 index 000000000..4ecd49132 --- /dev/null +++ b/Content/Editor/DebugMaterials/Single Color Terrain.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f93e989cd3cac252512c1400155ead3b5a888717c57f25612a4d96014e1d19ad +size 21156 diff --git a/Content/Shaders/Editor/MaterialComplexity.flax b/Content/Shaders/Editor/MaterialComplexity.flax new file mode 100644 index 000000000..0a7c52be3 --- /dev/null +++ b/Content/Shaders/Editor/MaterialComplexity.flax @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:918e4e2e6ecc2a50951b663254b2b57bc8828e4be37b7a601435d82ca2ca6ff6 +size 1336 diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index fa35eda94..9fe45eecc 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -1398,6 +1398,7 @@ namespace FlaxEditor.Viewport new ViewModeOptions(ViewMode.VertexColors, "Vertex Colors"), new ViewModeOptions(ViewMode.PhysicsColliders, "Physics Colliders"), new ViewModeOptions(ViewMode.LODPreview, "LOD Preview"), + new ViewModeOptions(ViewMode.MaterialComplexity, "Material Complexity"), }; private void WidgetCamSpeedShowHide(Control cm) diff --git a/Source/Engine/Graphics/Enums.h b/Source/Engine/Graphics/Enums.h index 6ab7abdf7..eed42ba27 100644 --- a/Source/Engine/Graphics/Enums.h +++ b/Source/Engine/Graphics/Enums.h @@ -818,6 +818,11 @@ API_ENUM() enum class ViewMode /// Draw Level Of Detail number as colors to debug LOD switches. /// LODPreview = 21, + + /// + /// Draw material shaders complexity to visualize performance of pixels rendering. + /// + MaterialComplexity = 22, }; /// diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index 18c1b5da0..f4ef475b4 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -56,6 +56,23 @@ bool GPUPipelineState::Init(const Description& desc) CHECK_STAGE(PS); #undef CHECK_STAGE +#if USE_EDITOR + // Estimate somehow performance cost of this pipeline state for the content profiling + const int32 textureLookupCost = 20; + const int32 tessCost = 300; + Complexity = Utilities::CountBits(_meta.UsedSRsMask) * textureLookupCost; + if (desc.PS) + Complexity += desc.PS->GetBindings().InstructionsCount; + if (desc.HS || desc.DS) + Complexity += tessCost; + if (desc.DepthWriteEnable) + Complexity += 5; + if (desc.DepthTestEnable) + Complexity += 5; + if (desc.BlendMode.BlendEnable) + Complexity += 20; +#endif + return false; } diff --git a/Source/Engine/Graphics/GPUPipelineState.h b/Source/Engine/Graphics/GPUPipelineState.h index 5e7609876..3290b8fb2 100644 --- a/Source/Engine/Graphics/GPUPipelineState.h +++ b/Source/Engine/Graphics/GPUPipelineState.h @@ -120,6 +120,9 @@ public: /// Description DebugDesc; #endif +#if USE_EDITOR + int32 Complexity; +#endif public: diff --git a/Source/Engine/Graphics/Materials/MaterialInfo.h b/Source/Engine/Graphics/Materials/MaterialInfo.h index f3fc4fa67..cdd3d5965 100644 --- a/Source/Engine/Graphics/Materials/MaterialInfo.h +++ b/Source/Engine/Graphics/Materials/MaterialInfo.h @@ -49,6 +49,9 @@ API_ENUM() enum class MaterialDomain : byte /// The particle shader used for volumetric effects rendering such as Volumetric Fog. /// VolumeParticle = 7, + + API_ENUM(Attributes="HideInEditor") + MAX }; /// diff --git a/Source/Engine/Renderer/Editor/LODPreview.cpp b/Source/Engine/Renderer/Editor/LODPreview.cpp index cdbbc4135..27faf5d47 100644 --- a/Source/Engine/Renderer/Editor/LODPreview.cpp +++ b/Source/Engine/Renderer/Editor/LODPreview.cpp @@ -11,19 +11,20 @@ #include "Engine/Graphics/Shaders/GPUConstantBuffer.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Renderer/DrawCall.h" +#include "Engine/Renderer/RenderList.h" -PACK_STRUCT(struct LODPreviewMaterialShaderData { +PACK_STRUCT(struct SingleColorShaderData { Matrix ViewProjectionMatrix; Matrix WorldMatrix; Color Color; - Vector3 WorldInvScale; + Vector3 Dummy0; float LODDitherFactor; }); LODPreviewMaterialShader::LODPreviewMaterialShader() { - _ps = GPUDevice::Instance->CreatePipelineState(); - _shader = Content::LoadAsyncInternal(TEXT("Shaders/Editor/LODPreview")); + _psModel.CreatePipelineStates(); + _shader = Content::LoadAsyncInternal(TEXT("Shaders/Editor/SingleColor")); if (!_shader) return; #if COMPILE_WITH_DEV_ENV @@ -35,7 +36,7 @@ LODPreviewMaterialShader::LODPreviewMaterialShader() void LODPreviewMaterialShader::OnShaderReloading(Asset* obj) { - _ps->ReleaseGPU(); + _psModel.Release(); } #endif @@ -50,6 +51,12 @@ bool LODPreviewMaterialShader::IsReady() const return _shader && _shader->IsLoaded(); } +bool LODPreviewMaterialShader::CanUseInstancing(InstancingHandler& handler) const +{ + handler = { SurfaceDrawCallHandler::GetHash, SurfaceDrawCallHandler::CanBatch, SurfaceDrawCallHandler::WriteDrawCall, }; + return true; +} + DrawPass LODPreviewMaterialShader::GetDrawModes() const { return DrawPass::GBuffer; @@ -61,12 +68,14 @@ void LODPreviewMaterialShader::Bind(BindParameters& params) auto& drawCall = *params.FirstDrawCall; auto shader = _shader->GetShader(); auto cb = shader->GetCB(0); - if (!_ps->IsValid()) + const int32 psIndex = params.DrawCallsCount == 1 ? 0 : 1; + auto ps = _psModel[psIndex]; + if (!ps->IsValid()) { auto psDesc = GPUPipelineState::Description::Default; - psDesc.VS = shader->GetVS("VS"); - psDesc.PS = shader->GetPS("PS"); - _ps->Init(psDesc); + psDesc.VS = shader->GetVS("VS_Model", psIndex); + psDesc.PS = shader->GetPS("PS_GBuffer"); + ps->Init(psDesc); } // Find the LOD that produced this draw call @@ -96,17 +105,11 @@ void LODPreviewMaterialShader::Bind(BindParameters& params) // Bind if (cb && cb->GetSize()) { - ASSERT(cb->GetSize() == sizeof(LODPreviewMaterialShaderData)); - LODPreviewMaterialShaderData data; + ASSERT_LOW_LAYER(cb->GetSize() == sizeof(SingleColorShaderData)); + SingleColorShaderData data; Matrix::Transpose(params.RenderContext.View.Frustum.GetMatrix(), data.ViewProjectionMatrix); Matrix::Transpose(drawCall.World, data.WorldMatrix); - const float scaleX = Vector3(drawCall.World.M11, drawCall.World.M12, drawCall.World.M13).Length(); - const float scaleY = Vector3(drawCall.World.M21, drawCall.World.M22, drawCall.World.M23).Length(); - const float scaleZ = Vector3(drawCall.World.M31, drawCall.World.M32, drawCall.World.M33).Length(); - data.WorldInvScale = Vector3( - scaleX > 0.00001f ? 1.0f / scaleX : 0.0f, - scaleY > 0.00001f ? 1.0f / scaleY : 0.0f, - scaleZ > 0.00001f ? 1.0f / scaleZ : 0.0f); + data.LODDitherFactor = drawCall.Surface.LODDitherFactor; const Color colors[MODEL_MAX_LODS] = { Color::White, Color::Red, @@ -117,11 +120,10 @@ void LODPreviewMaterialShader::Bind(BindParameters& params) }; ASSERT(lodIndex < MODEL_MAX_LODS); data.Color = colors[lodIndex]; - data.LODDitherFactor = drawCall.Surface.LODDitherFactor; context->UpdateCB(cb, &data); context->BindCB(0, cb); } - context->SetState(_ps); + context->SetState(ps); } #endif diff --git a/Source/Engine/Renderer/Editor/LODPreview.h b/Source/Engine/Renderer/Editor/LODPreview.h index c5ab05f1e..ef25b71a1 100644 --- a/Source/Engine/Renderer/Editor/LODPreview.h +++ b/Source/Engine/Renderer/Editor/LODPreview.h @@ -6,8 +6,8 @@ #include "Engine/Content/AssetReference.h" #include "Engine/Content/Assets/Shader.h" -#include "Engine/Content/Assets/Texture.h" #include "Engine/Graphics/Materials/IMaterial.h" +#include "Engine/Graphics/GPUPipelineStatePermutations.h" class GPUPipelineState; @@ -19,7 +19,7 @@ class LODPreviewMaterialShader : public IMaterial private: AssetReference _shader; - GPUPipelineState* _ps = nullptr; + GPUPipelineStatePermutations<2> _psModel; MaterialInfo _info; public: @@ -40,6 +40,7 @@ public: // [IMaterial] const MaterialInfo& GetInfo() const override; bool IsReady() const override; + bool CanUseInstancing(InstancingHandler& handler) const override; DrawPass GetDrawModes() const override; void Bind(BindParameters& params) override; }; diff --git a/Source/Engine/Renderer/Editor/MaterialComplexity.cpp b/Source/Engine/Renderer/Editor/MaterialComplexity.cpp new file mode 100644 index 000000000..f5019ed0b --- /dev/null +++ b/Source/Engine/Renderer/Editor/MaterialComplexity.cpp @@ -0,0 +1,228 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#if USE_EDITOR + +#include "MaterialComplexity.h" +#include "Engine/Core/Types/Variant.h" +#include "Engine/Content/Content.h" +#include "Engine/Content/Assets/Model.h" +#include "Engine/Profiler/Profiler.h" +#include "Engine/Level/Actors/Decal.h" +#include "Engine/Graphics/GPUContext.h" +#include "Engine/Graphics/GPUDevice.h" +#include "Engine/Graphics/GPUPipelineState.h" +#include "Engine/Graphics/Shaders/GPUShader.h" +#include "Engine/Graphics/Textures/GPUTexture.h" +#include "Engine/Graphics/RenderTask.h" +#include "Engine/Graphics/RenderBuffers.h" +#include "Engine/Renderer/DrawCall.h" +#include "Engine/Renderer/RenderList.h" +#include "Engine/Renderer/Lightmaps.h" + +// The limit for maximum material complexity (estimated based on shader textures, instructions and GPU stages usage). +#define COMPLEXITY_LIMIT 1700 + +const MaterialInfo& MaterialComplexityMaterialShader::WrapperShader::GetInfo() const +{ + if (MaterialAsset) + return MaterialAsset->GetInfo(); + return Info; +} + +bool MaterialComplexityMaterialShader::WrapperShader::IsReady() const +{ + return MaterialAsset && MaterialAsset->IsReady(); +} + +bool MaterialComplexityMaterialShader::WrapperShader::CanUseInstancing(InstancingHandler& handler) const +{ + return MaterialAsset && MaterialAsset->CanUseInstancing(handler); +} + +DrawPass MaterialComplexityMaterialShader::WrapperShader::GetDrawModes() const +{ + return MaterialAsset->GetDrawModes(); +} + +void MaterialComplexityMaterialShader::WrapperShader::Bind(BindParameters& params) +{ + auto& drawCall = *params.FirstDrawCall; + + // Get original material from the draw call + IMaterial* material = nullptr; + switch (Domain) + { + case MaterialDomain::Surface: + case MaterialDomain::Terrain: + material = *(IMaterial**)&drawCall.Surface.Lightmap; + break; + case MaterialDomain::Particle: + material = *(IMaterial**)&drawCall.ObjectPosition; + break; + case MaterialDomain::Decal: + material = drawCall.Material; + break; + } + + // Disable lightmaps + const auto lightmapsEnable = EnableLightmapsUsage; + EnableLightmapsUsage = false; + + // Estimate the shader complexity + ASSERT_LOW_LAYER(material && material->IsReady()); + material->Bind(params); + GPUPipelineState* materialPs = params.GPUContext->GetState(); + const float complexity = (float)Math::Min(materialPs->Complexity, COMPLEXITY_LIMIT) / COMPLEXITY_LIMIT; + + // Draw with custom color + const Color color(complexity, complexity, complexity, 1.0f); + MaterialAsset->SetParameterValue(TEXT("Color"), Variant(color)); + MaterialAsset->Bind(params); + + EnableLightmapsUsage = lightmapsEnable; +} + +MaterialComplexityMaterialShader::MaterialComplexityMaterialShader() +{ + _shader = Content::LoadAsyncInternal(TEXT("Shaders/Editor/MaterialComplexity")); + + // Initialize material wrappers table with separate materials for each material domain type and shader configuration +#define INIT_WRAPPER(i, domain, asset) _wrappers[i].Domain = MaterialDomain::domain; _wrappers[i].MaterialAsset = Content::LoadAsyncInternal(TEXT(asset)) + INIT_WRAPPER(0, Surface, "Editor/DebugMaterials/Single Color Surface"); + INIT_WRAPPER(1, Surface, "Editor/DebugMaterials/Single Color Surface Additive"); + INIT_WRAPPER(2, Terrain, "Editor/DebugMaterials/Single Color Terrain"); + INIT_WRAPPER(3, Particle, "Editor/DebugMaterials/Single Color Particle"); + INIT_WRAPPER(4, Decal, "Editor/DebugMaterials/Single Color Decal"); + // TODO: deformable splines rendering cost for complexity + // TODO: volumetric fog particles rendering cost for complexity +#undef INIT_WRAPPER +} + +void MaterialComplexityMaterialShader::DebugOverrideDrawCallsMaterial(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer) +{ + // Cache 'ready' state for wrappers + bool isReady[ARRAY_COUNT(_wrappers) + 1]; + for (int32 i = 0; i < ARRAY_COUNT(_wrappers); i++) + isReady[i] = _wrappers[i].IsReady(); + isReady[ARRAY_COUNT(_wrappers)] = false; + + // Override all draw calls + for (auto& e : renderContext.List->DrawCalls) + DebugOverrideDrawCallsMaterial(e, isReady); + for (auto& e : renderContext.List->BatchedDrawCalls) + DebugOverrideDrawCallsMaterial(e.DrawCall, isReady); + + // Initialize background with complexity of the sky (uniform) + if (renderContext.List->Sky) + { + renderContext.List->Sky->ApplySky(context, renderContext, Matrix::Identity); + GPUPipelineState* materialPs = context->GetState(); + const float complexity = (float)Math::Min(materialPs->Complexity, COMPLEXITY_LIMIT) / COMPLEXITY_LIMIT; + context->Clear(lightBuffer, Color(complexity, complexity, complexity, 1.0f)); + renderContext.List->Sky = nullptr; + } +} + +void MaterialComplexityMaterialShader::Draw(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer) +{ + // Draw decals into Light buffer to include them into complexity drawing + auto& decals = renderContext.List->Decals; + auto boxModel = Content::LoadAsyncInternal(TEXT("Engine/Models/SimpleBox")); + auto& decalsWrapper = _wrappers[4]; + if (decals.HasItems() && boxModel && boxModel->CanBeRendered() && decalsWrapper.IsReady()) + { + PROFILE_GPU_CPU("Decals"); + DrawCall drawCall; + MaterialBase::BindParameters bindParams(context, renderContext, drawCall); + drawCall.WorldDeterminantSign = 1.0f; + context->SetRenderTarget(lightBuffer); + for (int32 i = 0; i < decals.Count(); i++) + { + const auto decal = decals[i]; + ASSERT(decal && decal->Material); + decal->GetWorld(&drawCall.World); + drawCall.ObjectPosition = drawCall.World.GetTranslation(); + drawCall.Material = decal->Material; + drawCall.PerInstanceRandom = decal->GetPerInstanceRandom(); + decalsWrapper.Bind(bindParams); + boxModel->Render(context); + } + context->ResetSR(); + } + + // Draw transparency into Light buffer to include it into complexity drawing + context->SetRenderTarget(*renderContext.Buffers->DepthBuffer, lightBuffer); + auto& distortionList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::Distortion]; + if (!distortionList.IsEmpty()) + { + PROFILE_GPU_CPU("Distortion"); + renderContext.View.Pass = DrawPass::Distortion; + renderContext.List->ExecuteDrawCalls(renderContext, distortionList); + } + auto& forwardList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::Forward]; + if (!forwardList.IsEmpty()) + { + PROFILE_GPU_CPU("Forward"); + renderContext.View.Pass = DrawPass::Forward; + renderContext.List->ExecuteDrawCalls(renderContext, forwardList); + } + + // Draw accumulated complexity into colors gradient + context->ResetRenderTarget(); + context->SetRenderTarget(renderContext.Task->GetOutputView()); + context->SetViewportAndScissors(renderContext.Task->GetOutputViewport()); + if (_shader && _shader->IsLoaded()) + { + if (!_ps) + { + _ps = GPUDevice::Instance->CreatePipelineState(); + auto psDesc = GPUPipelineState::Description::DefaultFullscreenTriangle; + psDesc.PS = _shader->GetShader()->GetPS("PS"); + _ps->Init(psDesc); + } + context->BindSR(0, lightBuffer); + context->SetState(_ps); + context->DrawFullscreenTriangle(); + return; + } + context->Draw(lightBuffer); +} + +void MaterialComplexityMaterialShader::DebugOverrideDrawCallsMaterial(DrawCall& drawCall, const bool isReady[ARRAY_COUNT(_wrappers) + 1]) +{ + auto domain = drawCall.Material->GetInfo().Domain; + auto wrapperIndex = ARRAY_COUNT(_wrappers); + switch (domain) + { + case MaterialDomain::Surface: + wrapperIndex = drawCall.Material->GetDrawModes() & DrawPass::Forward ? 1 : 0; + break; + case MaterialDomain::Terrain: + wrapperIndex = 2; + break; + case MaterialDomain::Particle: + wrapperIndex = 3; + break; + case MaterialDomain::Decal: + wrapperIndex = 4; + break; + } + if (isReady[wrapperIndex]) + { + // Override draw call material and cache original material for later + switch (domain) + { + case MaterialDomain::Surface: + case MaterialDomain::Terrain: + *(void**)&drawCall.Surface.Lightmap = drawCall.Material; + break; + case MaterialDomain::Particle: + case MaterialDomain::Decal: + *(void**)&drawCall.ObjectPosition = drawCall.Material; + break; + } + drawCall.Material = &_wrappers[wrapperIndex]; + } +} + +#endif diff --git a/Source/Engine/Renderer/Editor/MaterialComplexity.h b/Source/Engine/Renderer/Editor/MaterialComplexity.h new file mode 100644 index 000000000..9b4fe2fac --- /dev/null +++ b/Source/Engine/Renderer/Editor/MaterialComplexity.h @@ -0,0 +1,49 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#if USE_EDITOR + +#include "Engine/Content/AssetReference.h" +#include "Engine/Content/Assets/Material.h" +#include "Engine/Graphics/Materials/IMaterial.h" +#include "Engine/Content/Assets/Shader.h" + +class GPUPipelineState; + +/// +/// Rendering material shaders complexity to visualize performance of pixels rendering in editor. +/// +class MaterialComplexityMaterialShader +{ +private: + + class WrapperShader : public IMaterial + { + public: + MaterialInfo Info; + MaterialDomain Domain; + AssetReference MaterialAsset; + const MaterialInfo& GetInfo() const override; + bool IsReady() const override; + bool CanUseInstancing(InstancingHandler& handler) const override; + DrawPass GetDrawModes() const override; + void Bind(BindParameters& params) override; + }; + + WrapperShader _wrappers[5]; + AssetReference _shader; + GPUPipelineState* _ps = nullptr; + +public: + + MaterialComplexityMaterialShader(); + void DebugOverrideDrawCallsMaterial(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer); + void Draw(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer); + +private: + + void DebugOverrideDrawCallsMaterial(struct DrawCall& drawCall, const bool isReady[ARRAY_COUNT(_wrappers) + 1]); +}; + +#endif diff --git a/Source/Engine/Renderer/GBufferPass.cpp b/Source/Engine/Renderer/GBufferPass.cpp index fdefb237f..d948b4db6 100644 --- a/Source/Engine/Renderer/GBufferPass.cpp +++ b/Source/Engine/Renderer/GBufferPass.cpp @@ -6,6 +6,7 @@ #include "Engine/Renderer/Editor/VertexColors.h" #include "Engine/Renderer/Editor/LightmapUVsDensity.h" #include "Engine/Renderer/Editor/LODPreview.h" +#include "Engine/Renderer/Editor/MaterialComplexity.h" #endif #include "Engine/Core/Collections/Sorting.h" #include "Engine/Graphics/GPUDevice.h" @@ -93,6 +94,7 @@ void GBufferPass::Dispose() SAFE_DELETE(_lightmapUVsDensity); SAFE_DELETE(_vertexColors); SAFE_DELETE(_lodPreview); + SAFE_DELETE(_materialComplexity); #endif } @@ -100,7 +102,12 @@ void GBufferPass::Dispose() void DebugOverrideDrawCallsMaterial(RenderContext& renderContext, IMaterial* material) { - if (material->IsReady()) + if (!material->IsReady()) + return; + IMaterial::InstancingHandler handler; + const bool canUseInstancing = material->CanUseInstancing(handler); + const auto drawModes = material->GetDrawModes(); + if (drawModes & DrawPass::GBuffer) { auto& drawCallsList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::GBuffer]; for (int32 i : drawCallsList.Indices) @@ -111,11 +118,20 @@ void DebugOverrideDrawCallsMaterial(RenderContext& renderContext, IMaterial* mat drawCall.Material = material; } } - IMaterial::InstancingHandler handler; - if (!material->CanUseInstancing(handler)) + drawCallsList.CanUseInstancing &= canUseInstancing; + } + if (drawModes & DrawPass::GBuffer) + { + auto& drawCallsList = renderContext.List->DrawCallsLists[(int32)DrawCallsListType::GBufferNoDecals]; + for (int32 i : drawCallsList.Indices) { - drawCallsList.CanUseInstancing = false; + auto& drawCall = renderContext.List->DrawCalls[i]; + if (drawCall.Material->IsSurface()) + { + drawCall.Material = material; + } } + drawCallsList.CanUseInstancing &= canUseInstancing; } } @@ -178,6 +194,12 @@ void GBufferPass::Fill(RenderContext& renderContext, GPUTextureView* lightBuffer _lodPreview = New(); DebugOverrideDrawCallsMaterial(renderContext, _lodPreview); } + else if (renderContext.View.Mode == ViewMode::MaterialComplexity) + { + if (!_materialComplexity) + _materialComplexity = New(); + _materialComplexity->DebugOverrideDrawCallsMaterial(renderContext, context, lightBuffer); + } if (renderContext.View.Mode == ViewMode::PhysicsColliders) { context->ResetRenderTarget(); @@ -258,6 +280,15 @@ void GBufferPass::RenderDebug(RenderContext& renderContext) context->ResetSR(); } +#if USE_EDITOR + +void GBufferPass::DrawMaterialComplexity(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer) +{ + _materialComplexity->Draw(renderContext, context, lightBuffer); +} + +#endif + bool GBufferPass::IsDebugView(ViewMode mode) { switch (mode) diff --git a/Source/Engine/Renderer/GBufferPass.h b/Source/Engine/Renderer/GBufferPass.h index 7bb1c1eaf..d59a84099 100644 --- a/Source/Engine/Renderer/GBufferPass.h +++ b/Source/Engine/Renderer/GBufferPass.h @@ -19,6 +19,7 @@ private: class LightmapUVsDensityMaterialShader* _lightmapUVsDensity = nullptr; class VertexColorsMaterialShader* _vertexColors = nullptr; class LODPreviewMaterialShader* _lodPreview = nullptr; + class MaterialComplexityMaterialShader* _materialComplexity = nullptr; #endif public: @@ -36,6 +37,10 @@ public: /// The rendering context. void RenderDebug(RenderContext& renderContext); +#if USE_EDITOR + void DrawMaterialComplexity(RenderContext& renderContext, GPUContext* context, GPUTextureView* lightBuffer); +#endif + public: static bool IsDebugView(ViewMode mode); diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index f9dc824dd..f974d1898 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -326,7 +326,6 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext) // Check if debug emissive light if (renderContext.View.Mode == ViewMode::Emissive || renderContext.View.Mode == ViewMode::LightmapUVsDensity) { - // Render reflections debug view context->ResetRenderTarget(); context->SetRenderTarget(task->GetOutputView()); context->SetViewportAndScissors(task->GetOutputViewport()); @@ -334,6 +333,14 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext) RenderTargetPool::Release(lightBuffer); return; } +#if USE_EDITOR + if (renderContext.View.Mode == ViewMode::MaterialComplexity) + { + GBufferPass::Instance()->DrawMaterialComplexity(renderContext, context, lightBuffer->View()); + RenderTargetPool::Release(lightBuffer); + return; + } +#endif // Render motion vectors MotionBlurPass::Instance()->RenderMotionVectors(renderContext); diff --git a/Source/Shaders/Editor/MaterialComplexity.shader b/Source/Shaders/Editor/MaterialComplexity.shader new file mode 100644 index 000000000..3a84906bd --- /dev/null +++ b/Source/Shaders/Editor/MaterialComplexity.shader @@ -0,0 +1,33 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#include "./Flax/Common.hlsl" + +Texture2D Image : register(t0); + +META_PS(true, FEATURE_LEVEL_ES2) +float4 PS(Quad_VS2PS input) : SV_Target +{ + const float4 colors[4] = { + float4(0, 0.97f, 0.12f, 1), + float4(0.2f, 0.2f, 0.7f, 1), + float4(1, 0, 0, 1), + float4(1, 0.95f, 0.95f, 1) + }; + const float weights[4] = { + 0.0f, + 0.5f, + 0.8f, + 1.0f + }; + + float complexity = saturate(Image.Sample(SamplerPointClamp, input.TexCoord).r); + + float4 color; + if (complexity < weights[1]) + color = lerp(colors[0], colors[1], complexity / weights[1]); + else if (complexity < weights[2]) + color = lerp(colors[1], colors[2], (complexity - weights[1]) / (weights[2] - weights[1])); + else + color = lerp(colors[2], colors[3], (complexity - weights[2]) / (weights[3] - weights[2])); + return color; +}