Add dirty tiles clearing before mesh rasterization to Global Surface Atlas

This commit is contained in:
Wojciech Figat
2022-04-05 17:22:45 +02:00
parent 5fc9cb154b
commit 60d6e6b9ce
3 changed files with 74 additions and 4 deletions

View File

@@ -20,7 +20,7 @@
#define GLOBAL_SURFACE_ATLAS_OBJECT_SIZE (1) #define GLOBAL_SURFACE_ATLAS_OBJECT_SIZE (1)
#define GLOBAL_SURFACE_ATLAS_OBJECT_STRIDE (16 * GLOBAL_SURFACE_ATLAS_OBJECT_SIZE) #define GLOBAL_SURFACE_ATLAS_OBJECT_STRIDE (16 * GLOBAL_SURFACE_ATLAS_OBJECT_SIZE)
#define GLOBAL_SURFACE_ATLAS_TILE_PADDING 1 // 1px padding to prevent color bleeding between tiles #define GLOBAL_SURFACE_ATLAS_TILE_PADDING 1 // 1px padding to prevent color bleeding between tiles
#define GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_TILES_REDRAW 1 // Forces to redraw all object tiles every frame #define GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_TILES_REDRAW 0 // Forces to redraw all object tiles every frame
#define GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_DRAW_OBJECTS 0 // Debug draws object bounds on redraw (and tile draw projection locations) #define GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_DRAW_OBJECTS 0 // Debug draws object bounds on redraw (and tile draw projection locations)
#if GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_DRAW_OBJECTS #if GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_DRAW_OBJECTS
@@ -38,6 +38,11 @@ PACK_STRUCT(struct Data0
GlobalSurfaceAtlasPass::GlobalSurfaceAtlasData GlobalSurfaceAtlas; GlobalSurfaceAtlasPass::GlobalSurfaceAtlasData GlobalSurfaceAtlas;
}); });
PACK_STRUCT(struct AtlasTileVertex
{
Half2 Position;
});
struct GlobalSurfaceAtlasTile : RectPack<GlobalSurfaceAtlasTile, uint16> struct GlobalSurfaceAtlasTile : RectPack<GlobalSurfaceAtlasTile, uint16>
{ {
GlobalSurfaceAtlasTile(uint16 x, uint16 y, uint16 width, uint16 height) GlobalSurfaceAtlasTile(uint16 x, uint16 y, uint16 width, uint16 height)
@@ -138,6 +143,17 @@ bool GlobalSurfaceAtlasPass::setupResources()
if (_psDebug->Init(psDesc)) if (_psDebug->Init(psDesc))
return true; return true;
} }
if (!_psClear)
{
_psClear = device->CreatePipelineState();
psDesc.DepthTestEnable = true;
psDesc.DepthWriteEnable = true;
psDesc.DepthFunc = ComparisonFunc::Always;
psDesc.VS = shader->GetVS("VS_Clear");
psDesc.PS = shader->GetPS("PS_Clear");
if (_psClear->Init(psDesc))
return true;
}
return false; return false;
} }
@@ -146,6 +162,7 @@ bool GlobalSurfaceAtlasPass::setupResources()
void GlobalSurfaceAtlasPass::OnShaderReloading(Asset* obj) void GlobalSurfaceAtlasPass::OnShaderReloading(Asset* obj)
{ {
SAFE_DELETE_GPU_RESOURCE(_psClear);
SAFE_DELETE_GPU_RESOURCE(_psDebug); SAFE_DELETE_GPU_RESOURCE(_psDebug);
invalidateResources(); invalidateResources();
} }
@@ -157,7 +174,9 @@ void GlobalSurfaceAtlasPass::Dispose()
RendererPass::Dispose(); RendererPass::Dispose();
// Cleanup // Cleanup
SAFE_DELETE(_vertexBuffer);
SAFE_DELETE(_objectsBuffer); SAFE_DELETE(_objectsBuffer);
SAFE_DELETE_GPU_RESOURCE(_psClear);
SAFE_DELETE_GPU_RESOURCE(_psDebug); SAFE_DELETE_GPU_RESOURCE(_psDebug);
_cb0 = nullptr; _cb0 = nullptr;
_shader = nullptr; _shader = nullptr;
@@ -208,6 +227,8 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
surfaceAtlasData.Resolution = resolution; surfaceAtlasData.Resolution = resolution;
LOG(Info, "Global Surface Atlas resolution: {0}, memory usage: {1} MB", resolution, memUsage / 1024 / 1024); LOG(Info, "Global Surface Atlas resolution: {0}, memory usage: {1} MB", resolution, memUsage / 1024 / 1024);
} }
if (!_vertexBuffer)
_vertexBuffer = New<DynamicVertexBuffer>(0u, (uint32)sizeof(AtlasTileVertex), TEXT("GlobalSurfaceAtlas.VertexBuffer"));
// Add objects into the atlas // Add objects into the atlas
if (_objectsBuffer) if (_objectsBuffer)
@@ -223,7 +244,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
const uint16 maxTileResolution = 128; // Maximum size (in texels) of the tile in atlas const uint16 maxTileResolution = 128; // Maximum size (in texels) of the tile in atlas
const uint16 tileResolutionAlignment = 8; // Alignment to snap (down) tiles resolution which allows to reuse atlas slots once object gets resizes/replaced by other object const uint16 tileResolutionAlignment = 8; // Alignment to snap (down) tiles resolution which allows to reuse atlas slots once object gets resizes/replaced by other object
const float minObjectRadius = 20.0f; // Skip too small objects const float minObjectRadius = 20.0f; // Skip too small objects
const float tileTexelsPerWorldUnit = 1.0f / 4.0f; // Scales the tiles resolution const float tileTexelsPerWorldUnit = 1.0f / 10.0f; // Scales the tiles resolution
const float distanceScalingStart = 2000.0f; // Distance from camera at which the tiles resolution starts to be scaled down const float distanceScalingStart = 2000.0f; // Distance from camera at which the tiles resolution starts to be scaled down
const float distanceScalingEnd = 5000.0f; // Distance from camera at which the tiles resolution end to be scaled down const float distanceScalingEnd = 5000.0f; // Distance from camera at which the tiles resolution end to be scaled down
const float distanceScaling = 0.1f; // The scale for tiles at distanceScalingEnd and further away const float distanceScaling = 0.1f; // The scale for tiles at distanceScalingEnd and further away
@@ -376,7 +397,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
PROFILE_GPU_CPU("Clear"); PROFILE_GPU_CPU("Clear");
if (noCache || GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_TILES_REDRAW) if (noCache || GLOBAL_SURFACE_ATLAS_DEBUG_FORCE_TILES_REDRAW)
{ {
/// Full-atlas hardware clear // Full-atlas hardware clear
context->ClearDepth(depthBuffer); context->ClearDepth(depthBuffer);
context->Clear(targetBuffers[0], Color::Transparent); context->Clear(targetBuffers[0], Color::Transparent);
context->Clear(targetBuffers[1], Color::Transparent); context->Clear(targetBuffers[1], Color::Transparent);
@@ -385,7 +406,36 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
} }
else else
{ {
// TODO: clear all dirt tiles in a single draw call (software) // Per-tile clear (with a single draw call)
_vertexBuffer->Clear();
_vertexBuffer->Data.EnsureCapacity(_dirtyObjectsBuffer.Count() * 6 * sizeof(AtlasTileVertex));
const Vector2 posToClipMul(2.0f / resolution, -2.0f / resolution);
const Vector2 posToClipAdd(-1.0f, 1.0f);
for (const auto& e : _dirtyObjectsBuffer)
{
const auto& object = *e.Second;
for (int32 tileIndex = 0; tileIndex < 6; tileIndex++)
{
auto* tile = object.Tiles[tileIndex];
if (!tile)
continue;
Vector2 minPos((float)tile->X, (float)tile->Y), maxPos((float)(tile->X + tile->Width), (float)(tile->Y + tile->Height));
Half2 min(minPos * posToClipMul + posToClipAdd), max(maxPos * posToClipMul + posToClipAdd);
auto* quad = _vertexBuffer->WriteReserve<AtlasTileVertex>(6);
quad[0] = { { max } };
quad[1] = { { min.X, max.Y } };
quad[2] = { { min } };
quad[3] = quad[2];
quad[4] = { { max.X, min.Y } };
quad[5] = quad[0];
}
}
_vertexBuffer->Flush(context);
auto vb = _vertexBuffer->GetBuffer();
context->SetState(_psClear);
context->SetViewportAndScissors(Viewport(0, 0, resolution, resolution));
context->BindVB(ToSpan(&vb, 1));
context->DrawInstanced(_vertexBuffer->Data.Count() / sizeof(AtlasTileVertex), 1);
} }
} }
renderContextTiles.List->DrawCallsLists[(int32)DrawCallsListType::GBuffer].CanUseInstancing = false; renderContextTiles.List->DrawCallsLists[(int32)DrawCallsListType::GBuffer].CanUseInstancing = false;

View File

@@ -27,10 +27,12 @@ public:
private: private:
bool _supported = false; bool _supported = false;
AssetReference<Shader> _shader; AssetReference<Shader> _shader;
GPUPipelineState* _psClear = nullptr;
GPUPipelineState* _psDebug = nullptr; GPUPipelineState* _psDebug = nullptr;
GPUConstantBuffer* _cb0 = nullptr; GPUConstantBuffer* _cb0 = nullptr;
// Rasterization cache // Rasterization cache
class DynamicVertexBuffer* _vertexBuffer = nullptr;
class DynamicTypedBuffer* _objectsBuffer = nullptr; class DynamicTypedBuffer* _objectsBuffer = nullptr;
Array<Pair<Actor*, struct GlobalSurfaceAtlasObject*>> _dirtyObjectsBuffer; Array<Pair<Actor*, struct GlobalSurfaceAtlasObject*>> _dirtyObjectsBuffer;

View File

@@ -15,6 +15,24 @@ GlobalSDFData GlobalSDF;
GlobalSurfaceAtlasData GlobalSurfaceAtlas; GlobalSurfaceAtlasData GlobalSurfaceAtlas;
META_CB_END META_CB_END
// Vertex shader for Global Surface Atlas software clearing
META_VS(true, FEATURE_LEVEL_SM5)
META_VS_IN_ELEMENT(POSITION, 0, R16G16_FLOAT, 0, ALIGN, PER_VERTEX, 0, true)
float4 VS_Clear(float2 Position : POSITION0) : SV_Position
{
return float4(Position, 1, 1);
}
// Pixel shader for Global Surface Atlas software clearing
META_PS(true, FEATURE_LEVEL_SM5)
void PS_Clear(out float4 Light : SV_Target0, out float4 RT0 : SV_Target1, out float4 RT1 : SV_Target2, out float4 RT2 : SV_Target3)
{
Light = float4(0, 0, 0, 0);
RT0 = float4(0, 0, 0, 0);
RT1 = float4(0, 0, 0, 0);
RT2 = float4(1, 0, 0, 0);
}
#ifdef _PS_Debug #ifdef _PS_Debug
Texture3D<float> GlobalSDFTex[4] : register(t0); Texture3D<float> GlobalSDFTex[4] : register(t0);