Skip to content

Commit f5335e8

Browse files
committed
Add instance buffer recreation handling in Renderer
This gets windows to run out of the box.
1 parent 786c5cd commit f5335e8

File tree

3 files changed

+46
-22
lines changed

3 files changed

+46
-22
lines changed

attachments/simple_engine/renderer.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,7 @@ class Renderer
827827
// Thread-safe: enqueue entities that need GPU-side resource preallocation.
828828
// The actual Vulkan work will be performed on the render thread at the frame-start safe point.
829829
void EnqueueEntityPreallocationBatch(const std::vector<Entity *> &entities);
830+
void EnqueueInstanceBufferRecreation(Entity *entity);
830831

831832
/**
832833
* @brief Recreate the instance buffer for an entity that had its instances cleared.
@@ -1197,10 +1198,11 @@ class Renderer
11971198
void ProcessPendingMeshUploads();
11981199

11991200
// --- Pending entity GPU preallocation (enqueued by scene loader thread; executed on render thread) ---
1200-
std::mutex pendingEntityPreallocMutex;
1201+
std::mutex pendingEntityPreallocMutex;
12011202
std::vector<Entity *> pendingEntityPrealloc;
1202-
std::atomic<bool> pendingEntityPreallocQueued{false};
1203-
void ProcessPendingEntityPreallocations();
1203+
std::vector<Entity *> pendingInstanceBufferRecreations;
1204+
std::atomic<bool> pendingEntityPreallocQueued{false};
1205+
void ProcessPendingEntityPreallocations();
12041206

12051207
// Descriptor set layouts (declared before pools and sets)
12061208
vk::raii::DescriptorSetLayout descriptorSetLayout = nullptr;

attachments/simple_engine/renderer_resources.cpp

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,46 +1772,68 @@ void Renderer::EnqueueEntityPreallocationBatch(const std::vector<Entity *> &enti
17721772
pendingEntityPreallocQueued.store(true, std::memory_order_relaxed);
17731773
}
17741774

1775+
void Renderer::EnqueueInstanceBufferRecreation(Entity *entity)
1776+
{
1777+
if (!entity)
1778+
return;
1779+
{
1780+
std::lock_guard<std::mutex> lk(pendingEntityPreallocMutex);
1781+
pendingInstanceBufferRecreations.push_back(entity);
1782+
}
1783+
pendingEntityPreallocQueued.store(true, std::memory_order_relaxed);
1784+
}
1785+
17751786
void Renderer::ProcessPendingEntityPreallocations()
17761787
{
17771788
if (!pendingEntityPreallocQueued.load(std::memory_order_relaxed))
17781789
return;
17791790

1780-
std::vector<Entity *> toProcess;
1791+
std::vector<Entity *> toPreallocate;
1792+
std::vector<Entity *> toRecreateInstances;
17811793
{
17821794
std::lock_guard<std::mutex> lk(pendingEntityPreallocMutex);
1783-
if (pendingEntityPrealloc.empty())
1795+
if (pendingEntityPrealloc.empty() && pendingInstanceBufferRecreations.empty())
17841796
{
17851797
pendingEntityPreallocQueued.store(false, std::memory_order_relaxed);
17861798
return;
17871799
}
1788-
toProcess.swap(pendingEntityPrealloc);
1800+
toPreallocate.swap(pendingEntityPrealloc);
1801+
toRecreateInstances.swap(pendingInstanceBufferRecreations);
17891802
pendingEntityPreallocQueued.store(false, std::memory_order_relaxed);
17901803
}
17911804

1792-
// De-dup to avoid repeated work if loader enqueues overlapping batches
1793-
std::sort(toProcess.begin(), toProcess.end());
1794-
toProcess.erase(std::unique(toProcess.begin(), toProcess.end()), toProcess.end());
1805+
// De-dup preallocations
1806+
std::sort(toPreallocate.begin(), toPreallocate.end());
1807+
toPreallocate.erase(std::unique(toPreallocate.begin(), toPreallocate.end()), toPreallocate.end());
17951808

17961809
std::vector<Entity *> batch;
1797-
batch.reserve(toProcess.size());
1798-
for (Entity *e : toProcess)
1810+
batch.reserve(toPreallocate.size());
1811+
for (Entity *e : toPreallocate)
17991812
{
18001813
if (!e || !e->IsActive())
18011814
continue;
1802-
// Only preallocate for entities that actually have renderable mesh data
18031815
if (!e->GetComponent<MeshComponent>())
18041816
continue;
18051817
batch.push_back(e);
18061818
}
1807-
if (batch.empty())
1808-
return;
18091819

1810-
// Execute GPU resource creation on the render thread at the safe point.
1811-
// Keep failures non-fatal so loading can continue; we'll retry on subsequent frames.
1812-
if (!preAllocateEntityResourcesBatch(batch))
1820+
if (!batch.empty())
1821+
{
1822+
if (!preAllocateEntityResourcesBatch(batch))
1823+
{
1824+
std::cerr << "Warning: batch entity GPU preallocation failed; will retry" << std::endl;
1825+
}
1826+
}
1827+
1828+
// Process instance buffer recreations
1829+
for (Entity *e : toRecreateInstances)
18131830
{
1814-
std::cerr << "Warning: batch entity GPU preallocation failed; will retry" << std::endl;
1831+
if (!e || !e->IsActive())
1832+
continue;
1833+
if (!recreateInstanceBuffer(e))
1834+
{
1835+
std::cerr << "Warning: failed to recreate instance buffer for entity " << e->GetName() << std::endl;
1836+
}
18151837
}
18161838
}
18171839

attachments/simple_engine/scene_loading.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -496,9 +496,9 @@ bool LoadGLTFModel(Engine *engine, const std::string &modelPath,
496496

497497
// Recreate the GPU instance buffer with a single identity instance
498498
// The old buffer still had multiple instances, so we need to update it
499-
if (renderer && !renderer->recreateInstanceBuffer(nodeEntity))
499+
if (renderer)
500500
{
501-
std::cerr << "[Animation] Failed to recreate instance buffer for reused entity" << std::endl;
501+
renderer->EnqueueInstanceBufferRecreation(nodeEntity);
502502
}
503503
}
504504
}
@@ -546,9 +546,9 @@ bool LoadGLTFModel(Engine *engine, const std::string &modelPath,
546546
}
547547

548548
// Pre-allocate resources for this new entity
549-
if (renderer && !renderer->preAllocateEntityResources(nodeEntity))
549+
if (renderer)
550550
{
551-
std::cerr << "[Animation] Failed to pre-allocate resources for " << entityName << std::endl;
551+
renderer->EnqueueEntityPreallocationBatch({nodeEntity});
552552
}
553553

554554
std::cout << "[Animation] Created new entity '" << entityName << "' for node " << nodeIndex << std::endl;

0 commit comments

Comments
 (0)