Optimize Global SDF cascades updates intervals (max 1 cascade per frame)

This commit is contained in:
Wojtek Figat
2022-11-01 00:37:01 +01:00
parent 5f4aa39263
commit ec62763e87
3 changed files with 108 additions and 3 deletions

View File

@@ -489,6 +489,95 @@ int32 RenderTools::ComputeSkinnedModelLOD(const SkinnedModel* model, const Float
return 0;
}
void RenderTools::ComputeCascadeUpdateFrequency(int32 cascadeIndex, int32 cascadeCount, int32& updateFrequency, int32& updatePhrase, int32 updateMaxCountPerFrame)
{
switch (updateMaxCountPerFrame)
{
case 1: // 1 cascade update per frame
switch (cascadeIndex)
{
case 0: // Cascade 0
updateFrequency = 2;
updatePhrase = 0;
break;
case 1: // Cascade 1
updateFrequency = 4;
updatePhrase = 1;
break;
case 2: // Cascade 2
updateFrequency = 8;
updatePhrase = 3;
break;
default:
if (cascadeCount > 4)
{
if (cascadeIndex == 3)
{
// Cascade 3
updateFrequency = 16;
updatePhrase = 7;
}
else
{
// Other
updateFrequency = 16;
updatePhrase = 15;
}
}
else
{
// Cascade 3
updateFrequency = 8;
updatePhrase = 7;
}
}
break;
case 2: // 2 cascade2 update per frame
switch (cascadeIndex)
{
case 0: // Cascade 0
updateFrequency = 1;
updatePhrase = 0;
break;
case 1: // Cascade 1
updateFrequency = 2;
updatePhrase = 0;
break;
case 2: // Cascade 2
updateFrequency = 4;
updatePhrase = 1;
break;
default:
if (cascadeCount > 4)
{
if (cascadeIndex == 3)
{
// Cascade 3
updateFrequency = 8;
updatePhrase = 3;
}
else
{
// Other
updateFrequency = 8;
updatePhrase = 7;
}
}
else
{
// Cascade 3
updateFrequency = 4;
updatePhrase = 3;
}
}
break;
default: // Every frame
updateFrequency = 1;
updatePhrase = 1;
break;
}
}
int32 MipLevelsCount(int32 width, bool useMipLevels)
{
if (!useMipLevels)

View File

@@ -108,6 +108,17 @@ public:
const uint32 distanceI = *((uint32*)&distance);
return ((uint32)(-(int32)(distanceI >> 31)) | 0x80000000) ^ distanceI;
}
// Calculates the update frequency and phrase for the given cached data (eg. cascaded shadow map or global sdf cascade contents). Lower data indices are updated first and more frequent.
static void ComputeCascadeUpdateFrequency(int32 cascadeIndex, int32 cascadeCount, int32& updateFrequency, int32& updatePhrase, int32 updateMaxCountPerFrame = 1);
// Checks if cached data should be updated during the given frame.
FORCE_INLINE static bool ShouldUpdateCascade(int32 frameIndex, int32 cascadeIndex, int32 cascadeCount, int32 updateMaxCountPerFrame = 1, bool updateForce = false)
{
int32 updateFrequency, updatePhrase;
ComputeCascadeUpdateFrequency(cascadeIndex, cascadeCount, updateFrequency, updatePhrase, updateMaxCountPerFrame);
return (frameIndex % updateFrequency == updatePhrase) || updateForce;
}
};
// Calculate mip levels count for a texture 1D

View File

@@ -11,6 +11,7 @@
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderBuffers.h"
#include "Engine/Graphics/RenderTargetPool.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Level/Scene/SceneRendering.h"
#include "Engine/Level/Actors/StaticModel.h"
@@ -171,6 +172,7 @@ struct CascadeData
class GlobalSignDistanceFieldCustomBuffer : public RenderBuffers::CustomBuffer, public ISceneRenderingListener
{
public:
int32 FrameIndex = 0;
int32 Resolution = 0;
GPUTexture* Texture = nullptr;
GPUTexture* TextureMip = nullptr;
@@ -415,6 +417,7 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
{
sdfData.Cascades.Resize(cascadesCount);
sdfData.Resolution = resolution;
sdfData.FrameIndex = 0;
updated = true;
auto desc = GPUTextureDescription::New3D(resolution * cascadesCount, resolution, resolution, GLOBAL_SDF_FORMAT, GPUTextureFlags::ShaderResource | GPUTextureFlags::UnorderedAccess, 1);
{
@@ -489,14 +492,16 @@ bool GlobalSignDistanceFieldPass::Render(RenderContext& renderContext, GPUContex
auto& chunks = ChunksCache;
chunks.EnsureCapacity(rasterizeChunks * rasterizeChunks, false);
bool anyDraw = false;
const uint64 cascadeFrequencies[] = { 2, 3, 5, 11 };
//const uint64 cascadeFrequencies[] = { 1, 1, 1, 1 };
const bool updateEveryFrame = false; // true if update all cascades every frame
const int32 maxCascadeUpdatesPerFrame = 1; // maximum cascades to update at a single frame
GPUTextureView* textureView = sdfData.Texture->ViewVolume();
GPUTextureView* textureMipView = sdfData.TextureMip->ViewVolume();
if (sdfData.FrameIndex++ > 128)
sdfData.FrameIndex = 0;
for (int32 cascadeIndex = 0; cascadeIndex < cascadesCount; cascadeIndex++)
{
// Reduce frequency of the updates
if (useCache && (Engine::FrameCount % cascadeFrequencies[cascadeIndex]) != 0)
if (useCache && !RenderTools::ShouldUpdateCascade(sdfData.FrameIndex, cascadeIndex, cascadesCount, maxCascadeUpdatesPerFrame, updateEveryFrame))
continue;
auto& cascade = sdfData.Cascades[cascadeIndex];
const float cascadeDistance = distanceExtent * cascadesDistanceScales[cascadeIndex];