Skip to content

Commit 3c77c3f

Browse files
committed
Add assert to UploadBufferHandler to prevent usage during the Render functions
Add assert to UploadBufferHandler to prevent usage during the Render functions
1 parent 97c1cbe commit 3c77c3f

5 files changed

Lines changed: 35 additions & 0 deletions

File tree

Source/Renderer/Renderer/Renderer.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,9 @@ namespace Renderer
207207
virtual bool ShouldWaitForUpload() = 0;
208208
virtual void SetHasWaitedForUpload() = 0;
209209
virtual SemaphoreID GetUploadFinishedSemaphore() = 0;
210+
// Re-opens staging uploads for the new frame's Update phase. Call before any uploads, after
211+
// the previous frame's FlipFrame locked them. Uploads requested while locked assert.
212+
virtual void UnlockUploads() = 0;
210213

211214
[[nodiscard]] BufferID CreateBuffer(BufferID bufferID, BufferDesc& desc);
212215
[[nodiscard]] BufferID CreateAndFillBuffer(BufferID bufferID, BufferDesc desc, void* data, size_t dataSize); // Deletes the current BufferID if it's not invalid

Source/Renderer/Renderer/Renderers/Vulkan/Backend/UploadBufferHandlerVK.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,11 @@ namespace Renderer
115115
std::mutex submitMutex;
116116
SemaphoreID uploadFinishedSemaphore;
117117

118+
// An upload on the render-loop thread while locked would land a frame late, so it asserts.
119+
// Worker-thread (async streaming) uploads are exempt.
120+
std::atomic<bool> uploadsLocked = false;
121+
std::thread::id renderThreadID;
122+
118123
// These are copies of the barriers which needs to run on the main commandlist
119124
moodycamel::ConcurrentQueue<VkBufferMemoryBarrier> bufferMemoryBarriers;
120125
};
@@ -168,6 +173,11 @@ namespace Renderer
168173
{
169174
UploadBufferHandlerVKData* data = static_cast<UploadBufferHandlerVKData*>(_data);
170175

176+
// Per-frame submit point: lock until UnlockUploads() at the end of Render, and capture the
177+
// render-loop thread so the assert is scoped to it.
178+
data->renderThreadID = std::this_thread::get_id();
179+
data->uploadsLocked = true;
180+
171181
for (u32 i = 0; i < data->stagingBuffers.Num; i++)
172182
{
173183
StagingBuffer& stagingBuffer = data->stagingBuffers.Get(i);
@@ -293,6 +303,10 @@ namespace Renderer
293303

294304
UploadBufferHandlerVKData* data = static_cast<UploadBufferHandlerVKData*>(_data);
295305

306+
// Thread check first so worker-thread (async streaming) uploads short-circuit out.
307+
NC_ASSERT(!(std::this_thread::get_id() == data->renderThreadID && data->uploadsLocked),
308+
"UploadBufferHandlerVK : Staging upload requested after this frame's uploads were submitted (FlipFrame). Move it to the Update phase, before Render.");
309+
296310
void* mappedMemory = nullptr;
297311
StagingBufferID stagingBufferID;
298312

@@ -356,6 +370,10 @@ namespace Renderer
356370

357371
UploadBufferHandlerVKData* data = static_cast<UploadBufferHandlerVKData*>(_data);
358372

373+
// Thread check first so worker-thread (async streaming) uploads short-circuit out.
374+
NC_ASSERT(!(std::this_thread::get_id() == data->renderThreadID && data->uploadsLocked),
375+
"UploadBufferHandlerVK : Staging upload requested after this frame's uploads were submitted (FlipFrame). Move it to the Update phase, before Render.");
376+
359377
void* mappedMemory = nullptr;
360378
StagingBufferID stagingBufferID;
361379
size_t offset = Allocate(size, stagingBufferID, mappedMemory);
@@ -483,6 +501,13 @@ namespace Renderer
483501
data->needsWait = false;
484502
}
485503

504+
void UploadBufferHandlerVK::UnlockUploads()
505+
{
506+
// Called at the end of Render; the next frame's Update phase may upload again.
507+
UploadBufferHandlerVKData* data = static_cast<UploadBufferHandlerVKData*>(_data);
508+
data->uploadsLocked = false;
509+
}
510+
486511
size_t UploadBufferHandlerVK::Allocate(size_t size, StagingBufferID& stagingBufferID, void*& mappedMemory)
487512
{
488513
UploadBufferHandlerVKData* data = static_cast<UploadBufferHandlerVKData*>(_data);

Source/Renderer/Renderer/Renderers/Vulkan/Backend/UploadBufferHandlerVK.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace Renderer
4646
SemaphoreID GetUploadFinishedSemaphore();
4747
bool ShouldWaitForUpload();
4848
void SetHasWaitedForUpload();
49+
void UnlockUploads();
4950
private:
5051
size_t Allocate(size_t size, StagingBufferID& stagingBufferID, void*& mappedMemory);
5152
void ExecuteStagingBuffer(VkCommandBuffer commandBuffer, StagingBuffer& stagingBuffer);

Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1997,6 +1997,11 @@ namespace Renderer
19971997
return _uploadBufferHandler->GetUploadFinishedSemaphore();
19981998
}
19991999

2000+
void RendererVK::UnlockUploads()
2001+
{
2002+
_uploadBufferHandler->UnlockUploads();
2003+
}
2004+
20002005
void RendererVK::CopyBuffer(BufferID dstBuffer, u64 dstOffset, BufferID srcBuffer, u64 srcOffset, u64 range)
20012006
{
20022007
_uploadBufferHandler->CopyBufferToBuffer(dstBuffer, dstOffset, srcBuffer, srcOffset, range);

Source/Renderer/Renderer/Renderers/Vulkan/RendererVK.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ namespace Renderer
175175
[[nodiscard]] bool ShouldWaitForUpload() override;
176176
void SetHasWaitedForUpload() override;
177177
[[nodiscard]] SemaphoreID GetUploadFinishedSemaphore() override;
178+
void UnlockUploads() override;
178179

179180
// Uses the upload handler to schedule it for next frames command list
180181
void CopyBuffer(BufferID dstBuffer, u64 dstOffset, BufferID srcBuffer, u64 srcOffset, u64 range) override;

0 commit comments

Comments
 (0)