Fix Global Surface Atlas defragmentation flicker when atlas it nearly full

This commit is contained in:
Wojtek Figat
2024-03-26 16:50:58 +01:00
parent 06a35da0a8
commit 5c356ec22a

View File

@@ -79,10 +79,7 @@ struct GlobalSurfaceAtlasTile : RectPack<GlobalSurfaceAtlasTile, uint16>
} }
void OnInsert(class GlobalSurfaceAtlasCustomBuffer* buffer, void* actorObject, int32 tileIndex); void OnInsert(class GlobalSurfaceAtlasCustomBuffer* buffer, void* actorObject, int32 tileIndex);
void OnFree(GlobalSurfaceAtlasCustomBuffer* buffer);
void OnFree()
{
}
}; };
struct GlobalSurfaceAtlasObject struct GlobalSurfaceAtlasObject
@@ -135,6 +132,7 @@ public:
int32 Resolution = 0; int32 Resolution = 0;
uint64 LastFrameAtlasInsertFail = 0; uint64 LastFrameAtlasInsertFail = 0;
uint64 LastFrameAtlasDefragmentation = 0; uint64 LastFrameAtlasDefragmentation = 0;
int32 AtlasPixelsUsed = 0;
GPUTexture* AtlasDepth = nullptr; GPUTexture* AtlasDepth = nullptr;
GPUTexture* AtlasEmissive = nullptr; GPUTexture* AtlasEmissive = nullptr;
GPUTexture* AtlasGBuffer0 = nullptr; GPUTexture* AtlasGBuffer0 = nullptr;
@@ -170,6 +168,7 @@ public:
CulledObjectsCounterIndex = -1; CulledObjectsCounterIndex = -1;
CulledObjectsUsageHistory.Clear(); CulledObjectsUsageHistory.Clear();
LastFrameAtlasDefragmentation = Engine::FrameCount; LastFrameAtlasDefragmentation = Engine::FrameCount;
AtlasPixelsUsed = 0;
SAFE_DELETE(AtlasTiles); SAFE_DELETE(AtlasTiles);
Objects.Clear(); Objects.Clear();
Lights.Clear(); Lights.Clear();
@@ -230,6 +229,12 @@ public:
void GlobalSurfaceAtlasTile::OnInsert(GlobalSurfaceAtlasCustomBuffer* buffer, void* actorObject, int32 tileIndex) void GlobalSurfaceAtlasTile::OnInsert(GlobalSurfaceAtlasCustomBuffer* buffer, void* actorObject, int32 tileIndex)
{ {
buffer->Objects[actorObject].Tiles[tileIndex] = this; buffer->Objects[actorObject].Tiles[tileIndex] = this;
buffer->AtlasPixelsUsed += (int32)Width * (int32)Height;
}
void GlobalSurfaceAtlasTile::OnFree(GlobalSurfaceAtlasCustomBuffer* buffer)
{
buffer->AtlasPixelsUsed -= (int32)Width * (int32)Height;
} }
String GlobalSurfaceAtlasPass::ToString() const String GlobalSurfaceAtlasPass::ToString() const
@@ -422,9 +427,10 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
else else
{ {
// Perform atlas defragmentation if needed // Perform atlas defragmentation if needed
// TODO: track atlas used vs free ratio to skip defragmentation if it's nearly full (then maybe auto resize up?) constexpr float maxUsageToDefrag = 0.8f;
if (currentFrame - surfaceAtlasData.LastFrameAtlasInsertFail < 10 && if (currentFrame - surfaceAtlasData.LastFrameAtlasInsertFail < 10 &&
currentFrame - surfaceAtlasData.LastFrameAtlasDefragmentation > 60) currentFrame - surfaceAtlasData.LastFrameAtlasDefragmentation > 60 &&
(float)surfaceAtlasData.AtlasPixelsUsed / (resolution * resolution) < maxUsageToDefrag)
{ {
surfaceAtlasData.ClearObjects(); surfaceAtlasData.ClearObjects();
} }
@@ -516,7 +522,7 @@ bool GlobalSurfaceAtlasPass::Render(RenderContext& renderContext, GPUContext* co
for (auto& tile : it->Value.Tiles) for (auto& tile : it->Value.Tiles)
{ {
if (tile) if (tile)
tile->Free(); tile->Free(&surfaceAtlasData);
} }
surfaceAtlasData.Objects.Remove(it); surfaceAtlasData.Objects.Remove(it);
} }
@@ -1217,7 +1223,7 @@ void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, con
// Skip too small surfaces // Skip too small surfaces
if (object && object->Tiles[tileIndex]) if (object && object->Tiles[tileIndex])
{ {
object->Tiles[tileIndex]->Free(); object->Tiles[tileIndex]->Free(&surfaceAtlasData);
object->Tiles[tileIndex] = nullptr; object->Tiles[tileIndex] = nullptr;
} }
continue; continue;
@@ -1240,7 +1246,7 @@ void GlobalSurfaceAtlasPass::RasterizeActor(Actor* actor, void* actorObject, con
anyTile = true; anyTile = true;
continue; continue;
} }
object->Tiles[tileIndex]->Free(); object->Tiles[tileIndex]->Free(&surfaceAtlasData);
} }
// Insert tile into atlas // Insert tile into atlas