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;
+}