Add dirty tiles clearing before mesh rasterization to Global Surface Atlas
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user