fix(rendering): wait all frame fences before freeing shared descriptor sets

deferAfterFrameFence only waits for one frame slot's fence, but shared
resources (material descriptor sets, vertex/index buffers) are bound by
both in-flight frames' command buffers. On AMD RADV this caused
vkFreeDescriptorSets errors and eventual SIGSEGV.

Add deferAfterAllFrameFences: queues to every frame slot with a shared
counter so cleanup runs exactly once, after the last slot is fenced.
Use it for WMO, terrain, water, and character model shared resources.
Per-frame bone sets keep using deferAfterFrameFence (already correct).

Also fix character renderer vertex format: R8G8B8A8_UINT -> _SINT to
match shader's ivec4 input (RADV validation rejects the mismatch).
This commit is contained in:
Kelsi 2026-04-03 19:48:43 -07:00
parent def821055b
commit 3ac8c4d95f
6 changed files with 31 additions and 10 deletions

View file

@ -246,7 +246,7 @@ bool CharacterRenderer::initialize(VkContext* ctx, VkDescriptorSetLayout perFram
std::vector<VkVertexInputAttributeDescription> charAttrs = {
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, position))},
{1, 0, VK_FORMAT_R8G8B8A8_UNORM, static_cast<uint32_t>(offsetof(CharVertexGPU, boneWeights))},
{2, 0, VK_FORMAT_R8G8B8A8_UINT, static_cast<uint32_t>(offsetof(CharVertexGPU, boneIndices))},
{2, 0, VK_FORMAT_R8G8B8A8_SINT, static_cast<uint32_t>(offsetof(CharVertexGPU, boneIndices))},
{3, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, normal))},
{4, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, texCoords))},
{5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, tangent))},
@ -492,7 +492,7 @@ void CharacterRenderer::destroyModelGPU(M2ModelGPU& gpuModel, bool defer) {
if (ib) vmaDestroyBuffer(alloc, ib, ibAlloc);
} else if (vb || ib) {
// Streaming path: in-flight command buffers may still reference these
vkCtx_->deferAfterFrameFence([alloc, vb, vbAlloc, ib, ibAlloc]() {
vkCtx_->deferAfterAllFrameFences([alloc, vb, vbAlloc, ib, ibAlloc]() {
if (vb) vmaDestroyBuffer(alloc, vb, vbAlloc);
if (ib) vmaDestroyBuffer(alloc, ib, ibAlloc);
});
@ -2663,7 +2663,7 @@ bool CharacterRenderer::initializeShadow(VkRenderPass shadowRenderPass) {
// Character vertex format (CharVertexGPU): stride = 56 bytes
// loc 0: vec3 aPos (R32G32B32_SFLOAT, offset 0)
// loc 1: vec4 aBoneWeights (R8G8B8A8_UNORM, offset 12)
// loc 2: ivec4 aBoneIndices (R8G8B8A8_UINT, offset 16)
// loc 2: ivec4 aBoneIndices (R8G8B8A8_SINT, offset 16)
// loc 3: vec2 aTexCoord (R32G32_SFLOAT, offset 32)
VkVertexInputBindingDescription vertBind{};
vertBind.binding = 0;
@ -2672,7 +2672,7 @@ bool CharacterRenderer::initializeShadow(VkRenderPass shadowRenderPass) {
std::vector<VkVertexInputAttributeDescription> vertAttrs = {
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, position))},
{1, 0, VK_FORMAT_R8G8B8A8_UNORM, static_cast<uint32_t>(offsetof(CharVertexGPU, boneWeights))},
{2, 0, VK_FORMAT_R8G8B8A8_UINT, static_cast<uint32_t>(offsetof(CharVertexGPU, boneIndices))},
{2, 0, VK_FORMAT_R8G8B8A8_SINT, static_cast<uint32_t>(offsetof(CharVertexGPU, boneIndices))},
{3, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, texCoords))},
};
@ -3336,7 +3336,7 @@ void CharacterRenderer::recreatePipelines() {
std::vector<VkVertexInputAttributeDescription> charAttrs = {
{0, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, position))},
{1, 0, VK_FORMAT_R8G8B8A8_UNORM, static_cast<uint32_t>(offsetof(CharVertexGPU, boneWeights))},
{2, 0, VK_FORMAT_R8G8B8A8_UINT, static_cast<uint32_t>(offsetof(CharVertexGPU, boneIndices))},
{2, 0, VK_FORMAT_R8G8B8A8_SINT, static_cast<uint32_t>(offsetof(CharVertexGPU, boneIndices))},
{3, 0, VK_FORMAT_R32G32B32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, normal))},
{4, 0, VK_FORMAT_R32G32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, texCoords))},
{5, 0, VK_FORMAT_R32G32B32A32_SFLOAT, static_cast<uint32_t>(offsetof(CharVertexGPU, tangent))},