fix: replace runtime waitIdle calls with a deletion queue

This commit is contained in:
2026-10-19 00:45:24 +02:00
parent 36341bb5e0
commit 997844eaa7
29 changed files with 290 additions and 101 deletions
+29 -31
View File
@@ -65,7 +65,6 @@ void GameRenderer::init(GfxDevice& gfxDevice, RenderResources& _resources, glm::
void GameRenderer::beginDrawing(GfxDevice& gfxDevice)
{
flushMaterialUpdates(gfxDevice);
meshDrawCommands.clear();
skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
lightCullingPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
@@ -175,15 +174,10 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
};
{
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Material Buffer Barrier");
vkutil::ScopedCmdLabel label(cmd, "Material Buffer Barrier", vkutil::labelColors::transfer);
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Material Updates");
vkutil::ScopedCmdLabel label(cmd, "Material Updates", vkutil::labelColors::transfer);
vkutil::bufferHostWriteToShaderReadBarrier(
cmd,
resources->materials().getMaterialDataBuffer().buffer,
0,
VK_WHOLE_SIZE
);
recordMaterialUpdates(cmd);
}
{
@@ -384,11 +378,6 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice)
{
VkDevice device = gfxDevice.getDevice();
if (device != VK_NULL_HANDLE)
{
vkDeviceWaitIdle(device);
}
if (skinningPipeline)
skinningPipeline->cleanup(gfxDevice);
@@ -541,25 +530,32 @@ void GameRenderer::setSkyboxTexture(ImageID skyboxImageId)
skyboxPipeline->setSkyboxImage(skyboxImageId);
}
void GameRenderer::flushMaterialUpdates(GfxDevice& gfxDevice)
void GameRenderer::recordMaterialUpdates(VkCommandBuffer cmd)
{
const VkBuffer materialBuffer = resources->materials().getMaterialDataBuffer().buffer;
if (!pendingMaterialUploads.empty())
{
// Material data is currently shared by all frame contexts. Wait before
// mutating it so an older in-flight frame cannot read the overwritten
// range. This can later be replaced with per-frame material buffers.
gfxDevice.waitIdle();
// Updates go through the command buffer instead of the mapped pointer: the
// copy then lands after earlier frames finished reading the old values,
// without the CPU having to wait for them.
vkutil::bufferShaderReadToTransferWriteBarrier(cmd, materialBuffer, 0, VK_WHOLE_SIZE);
for (MaterialID id : pendingMaterialUploads)
{
const MaterialData data = resources->materials().getMaterialData(id);
vkCmdUpdateBuffer(
cmd,
materialBuffer,
static_cast<VkDeviceSize>(id) * sizeof(MaterialData),
sizeof(MaterialData),
&data);
}
pendingMaterialUploads.clear();
}
for (MaterialID id : pendingMaterialUploads)
{
resources->materials().updateMaterialGPU(id);
gfxDevice.getMemoryManager().flushAllocation(
resources->materials().getMaterialDataBuffer(),
static_cast<VkDeviceSize>(id) * sizeof(MaterialData),
sizeof(MaterialData));
}
pendingMaterialUploads.clear();
// newly added materials are written through the mapped pointer, updates by the copies above
vkutil::bufferHostAndTransferWriteToShaderReadBarrier(cmd, materialBuffer, 0, VK_WHOLE_SIZE);
}
void GameRenderer::createDrawImage(GfxDevice& gfxDevice,
@@ -589,8 +585,9 @@ void GameRenderer::createDrawImage(GfxDevice& gfxDevice,
.samples = noMsaa,
};
// reuse the same id if creating again
drawImageId = resources->createImage(gfxDevice, createImageInfo, "draw image", nullptr, drawImageId);
// a fresh bindless slot, the old one may still be read by frames in flight
resources->destroyImage(drawImageId);
drawImageId = resources->createImage(gfxDevice, createImageInfo, "draw image");
if (firstCreate)
{
@@ -609,7 +606,8 @@ void GameRenderer::createDrawImage(GfxDevice& gfxDevice,
.samples = noMsaa,
};
depthImageId = resources->createImage(gfxDevice, createInfo, "depth image", nullptr, depthImageId);
resources->destroyImage(depthImageId);
depthImageId = resources->createImage(gfxDevice, createInfo, "depth image");
spdlog::info("Created depth image with id {}", depthImageId);
}
}