Add Graphics.GI.Dump command for profiling DDGI/GlobalSDF
This commit is contained in:
@@ -153,6 +153,13 @@ public:
|
||||
// Gets the normalized 0-1 progress of the Global Illumination lighting bounces convergence (0 = no GI, 1 = full GI convergence). Can be used to continue displaying loading screen after scene load to ensure indirect lighting has been evaluated. Non-zero value means GI has started to be calculated.
|
||||
API_FUNCTION(Attributes="DebugCommand(Hide=true)")
|
||||
static float GetConvergence(const RenderBuffers* buffers);
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
/// <summary>
|
||||
/// Dumps Global Illumination rendering info to the log (the next frame). Can be used to inspect DDGI, Global Surface Atlas and Global SDF memory and usage (for optimization). Prints info about the number of probes, cascades and draw state.
|
||||
/// </summary>
|
||||
API_FUNCTION(Attributes="DebugCommand") static void Dump();
|
||||
#endif
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/Engine/Units.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Core/Utilities.h"
|
||||
#include "Engine/Debug/DebugDraw.h"
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Graphics/GPUDevice.h"
|
||||
@@ -121,6 +122,7 @@ public:
|
||||
int32 ProbeRaysCount = 0;
|
||||
int32 ProbesCountTotal = 0;
|
||||
int32 FramesSinceClear = 0;
|
||||
uint32 MemoryUsage = 0;
|
||||
Int3 ProbeCounts = Int3::Zero;
|
||||
GPUTexture* ProbesTrace = nullptr; // Probes ray tracing: (RGB: hit radiance, A: hit distance)
|
||||
GPUTexture* ProbesData = nullptr; // Probes data: (RGB: probe-space offset, A: state/data)
|
||||
@@ -218,6 +220,29 @@ float Graphics::GI::GetConvergence(const RenderBuffers* buffers)
|
||||
return result;
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
uint64 DumpGIFrame = MAX_uint64;
|
||||
|
||||
void Graphics::GI::Dump()
|
||||
{
|
||||
DumpGIFrame = Engine::FrameCount + 1;
|
||||
}
|
||||
|
||||
void UpdateGIDump(const RenderBuffers* buffers, DDGICustomBuffer& ddgiData)
|
||||
{
|
||||
if (DumpGIFrame != Engine::FrameCount)
|
||||
return;
|
||||
|
||||
LOG(Info, "DDGI:");
|
||||
LOG(Info, " > Cascades: {}, Probes: {}, Ray Limit: {}", ddgiData.CascadesCount, ddgiData.ProbesCountTotal, ddgiData.ProbeRaysCount);
|
||||
LOG(Info, " > Memory Usage: {}", Utilities::BytesToText(ddgiData.MemoryUsage));
|
||||
GlobalSurfaceAtlasPass::Dump(buffers);
|
||||
GlobalSignDistanceFieldPass::Instance()->Dump(buffers);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
String DynamicDiffuseGlobalIlluminationPass::ToString() const
|
||||
{
|
||||
return TEXT("DynamicDiffuseGlobalIlluminationPass");
|
||||
@@ -469,6 +494,7 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
|
||||
INIT_BUFFER(StatsRead, "DDGI.StatsRead");
|
||||
#endif
|
||||
#undef INIT_BUFFER
|
||||
ddgiData.MemoryUsage = memUsage;
|
||||
LOG(Info, "Dynamic Diffuse Global Illumination probes: {0}, memory usage: {1} MB", probesCountTotal, memUsage / (1024 * 1024));
|
||||
clear = true;
|
||||
}
|
||||
@@ -756,6 +782,10 @@ bool DynamicDiffuseGlobalIlluminationPass::RenderInner(RenderContext& renderCont
|
||||
#endif
|
||||
}
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
UpdateGIDump(renderContext.Buffers, ddgiData);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -173,6 +173,7 @@ public:
|
||||
float ResolutionInv;
|
||||
int32 AtlasPixelsTotal = 0;
|
||||
int32 AtlasPixelsUsed = 0;
|
||||
uint32 MemoryUsage = 0;
|
||||
uint64 LastFrameAtlasInsertFail = 0;
|
||||
uint64 LastFrameAtlasDefragmentation = 0;
|
||||
GPUTexture* AtlasDepth = nullptr;
|
||||
@@ -999,6 +1000,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
||||
return true;
|
||||
memUsage += surfaceAtlasData.ChunksBuffer->GetMemoryUsage();
|
||||
}
|
||||
surfaceAtlasData.MemoryUsage = memUsage;
|
||||
LOG(Info, "Global Surface Atlas resolution: {0}, memory usage: {1} MB", resolution, memUsage / (1024 * 1024));
|
||||
|
||||
context->Clear(surfaceAtlasData.AtlasLighting->View(), Color::Transparent);
|
||||
@@ -1355,8 +1357,10 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
|
||||
if (surfaceAtlasData.CulledObjectsBuffer->GetSize() < objectsBufferCapacity)
|
||||
{
|
||||
const auto desc = GPUBufferDescription::Raw(objectsBufferCapacity, GPUBufferFlags::UnorderedAccess | GPUBufferFlags::ShaderResource);
|
||||
surfaceAtlasData.MemoryUsage -= surfaceAtlasData.CulledObjectsBuffer->GetSize();
|
||||
if (surfaceAtlasData.CulledObjectsBuffer->Init(desc))
|
||||
return true;
|
||||
surfaceAtlasData.MemoryUsage += desc.Size;
|
||||
}
|
||||
objectsBufferCapacity = surfaceAtlasData.CulledObjectsBuffer->GetSize();
|
||||
ZoneValue(objectsBufferCapacity / 1024); // CulledObjectsBuffer size in kB
|
||||
@@ -1817,6 +1821,29 @@ void GlobalSurfaceAtlasPass::RenderDebug(RenderContext& renderContext, GPUContex
|
||||
|
||||
#endif
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
#include "Engine/Core/Utilities.h"
|
||||
|
||||
void GlobalSurfaceAtlasPass::Dump(const RenderBuffers* buffers)
|
||||
{
|
||||
auto surfaceAtlasDataPtr = buffers->FindCustomBuffer<GlobalSurfaceAtlasCustomBuffer>(TEXT("GlobalSurfaceAtlas"));
|
||||
if (!surfaceAtlasDataPtr)
|
||||
return;
|
||||
auto& surfaceAtlasData = *surfaceAtlasDataPtr;
|
||||
LOG(Info, "Global Surface Atlas:");
|
||||
LOG(Info, " > Resolution: {}, Usage: {}%", surfaceAtlasData.Resolution, (int32)((float)surfaceAtlasData.AtlasPixelsUsed / surfaceAtlasData.AtlasPixelsTotal * 100));
|
||||
uint32 memoryUsage = surfaceAtlasData.MemoryUsage;
|
||||
if (surfaceAtlasData.ObjectsBuffer.GetBuffer())
|
||||
memoryUsage += surfaceAtlasData.ObjectsBuffer.GetBuffer()->GetSize();
|
||||
if (surfaceAtlasData.ObjectsListBuffer.GetBuffer())
|
||||
memoryUsage += surfaceAtlasData.ObjectsListBuffer.GetBuffer()->GetSize();
|
||||
LOG(Info, " > Memory Usage: {}", Utilities::BytesToText(memoryUsage));
|
||||
LOG(Info, " > Objects: {}, Tiles: {}, Lights: {}", surfaceAtlasData.Objects.Count(), surfaceAtlasData.Atlas.Count(), surfaceAtlasData.Lights.Count());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void GlobalSurfaceAtlasPass::GetCullingData(Vector4& cullingPosDistance) const
|
||||
{
|
||||
cullingPosDistance = _surfaceAtlasData->CullingPosDistance;
|
||||
|
||||
@@ -97,6 +97,11 @@ public:
|
||||
void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output);
|
||||
#endif
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
// Dumps the info to the log.
|
||||
static void Dump(const RenderBuffers* buffers);
|
||||
#endif
|
||||
|
||||
// Gets the culling view position (xyz) and view distance (w)
|
||||
void GetCullingData(Vector4& cullingPosDistance) const;
|
||||
|
||||
|
||||
@@ -367,6 +367,10 @@ public:
|
||||
auto& cascade = Cascades[cascadeIndex];
|
||||
cascade.Index = cascadeIndex;
|
||||
cascade.Dirty = !useCache || RenderTools::ShouldUpdateCascade(FrameIndex, cascadeIndex, cascadesCount, maxCascadeUpdatesPerFrame, updateEveryFrame);
|
||||
#if COMPILE_WITH_PROFILER
|
||||
extern uint64 DumpGIFrame;
|
||||
cascade.Dirty |= DumpGIFrame == Engine::FrameCount; // Force update of all cascades when dumping info (to collect dynamic objects)
|
||||
#endif
|
||||
cascade.DirtyDynamicOnly = useCache && !cascade.Dirty && cascade.DynamicDirtyChunks.HasItems() && cascade.VoxelSize > 0.0f && !DebugOverdraw && GLOBAL_SDF_DYNAMIC_UPDATES;
|
||||
cascade.Draw = cascade.Dirty || cascade.DirtyDynamicOnly;
|
||||
if (!cascade.Draw)
|
||||
@@ -1276,6 +1280,59 @@ void GlobalSignDistanceFieldPass::RenderDebug(RenderContext& renderContext, GPUC
|
||||
|
||||
#endif
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
|
||||
#include "Engine/Core/Utilities.h"
|
||||
#include "Engine/Engine/Units.h"
|
||||
|
||||
extern uint64 DumpGIFrame;
|
||||
|
||||
void GlobalSignDistanceFieldPass::Dump(const RenderBuffers* buffers) const
|
||||
{
|
||||
auto sdfDataPtr = buffers->FindCustomBuffer<GlobalSignDistanceFieldCustomBuffer>(TEXT("GlobalSignDistanceField"));
|
||||
if (!sdfDataPtr)
|
||||
return;
|
||||
auto& sdfData = *sdfDataPtr;
|
||||
LOG(Info, "Global SDF:");
|
||||
LOG(Info, " > Cascades: {}, Resolution: {}", sdfData.Cascades.Count(), sdfData.Resolution);
|
||||
uint32 memoryUsage = sdfData.Texture->GetMemoryUsage() + sdfData.TextureMip->GetMemoryUsage();
|
||||
if (_objectsBuffer && _objectsBuffer->GetBuffer())
|
||||
memoryUsage += _objectsBuffer->GetBuffer()->GetSize();
|
||||
LOG(Info, " > Memory Usage: {}", Utilities::BytesToText(memoryUsage));
|
||||
for (int32 i = 0; i < sdfData.Cascades.Count(); i++)
|
||||
{
|
||||
const auto& cascade = sdfData.Cascades[i];
|
||||
LOG(Info, " > Cascade {}, range: {}m", i, UNITS_TO_METERS(cascade.Extent));
|
||||
if (cascade.VoxelSize < METERS_TO_UNITS(1))
|
||||
LOG(Info, " > Voxel size: {} cm", Utilities::RoundTo2DecimalPlaces(UNITS_TO_METERS(cascade.VoxelSize) * 100));
|
||||
else
|
||||
LOG(Info, " > Voxel size: {} m", Utilities::RoundTo2DecimalPlaces(UNITS_TO_METERS(cascade.VoxelSize)));
|
||||
LOG(Info, " > Chunks: {} ({} static, {} dynamic)", cascade.NonEmptyChunks.Count(), cascade.StaticChunks.Count(), cascade.NonEmptyChunks.Count() - cascade.StaticChunks.Count());
|
||||
LOG(Info, " > Objects: {}", cascade.RasterizeObjects.Count());
|
||||
}
|
||||
|
||||
// Dynamic objects cause frequent chunk updates so list them when profiling content
|
||||
HashSet<Actor*> dynamicObjects;
|
||||
for (const auto& cascade : sdfData.Cascades)
|
||||
{
|
||||
for (const auto& object : cascade.RasterizeObjects)
|
||||
{
|
||||
if (!GLOBAL_SDF_ACTOR_IS_STATIC(object.Actor))
|
||||
dynamicObjects.Add(object.Actor);
|
||||
}
|
||||
}
|
||||
LOG(Info, " > Dynamic objects: {}", dynamicObjects.Count());
|
||||
if (dynamicObjects.HasItems())
|
||||
{
|
||||
for (auto& e : dynamicObjects)
|
||||
{
|
||||
LOG(Info, " > '{}'", e.Item->GetNamePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void GlobalSignDistanceFieldPass::GetCullingData(BoundingBox& bounds) const
|
||||
{
|
||||
auto& cascade = *CurrentCascade.Get();
|
||||
|
||||
@@ -80,6 +80,11 @@ public:
|
||||
void RenderDebug(RenderContext& renderContext, GPUContext* context, GPUTexture* output);
|
||||
#endif
|
||||
|
||||
#if COMPILE_WITH_PROFILER
|
||||
// Dumps the info to the log.
|
||||
void Dump(const RenderBuffers* buffers) const;
|
||||
#endif
|
||||
|
||||
void GetCullingData(BoundingBox& bounds) const;
|
||||
|
||||
// Rasterize Model SDF into the Global SDF. Call it from actor Draw() method during DrawPass::GlobalSDF.
|
||||
|
||||
Reference in New Issue
Block a user