d3d12: Read the fence in SubmitAndAcquireFence while submitLock is held
Build (All) / Create test plan (push) Canceled after 0s
Build (All) / level1 (push) Canceled after 0s
Build (All) / level2 (push) Canceled after 0s

Once the lock is released, another thread can clean up the completed
command buffer, return it to the pool and resubmit it with a different
fence before we read d3d12CommandBuffer->inFlightFence, handing the
caller a fence it doesn't own (or NULL).
This commit is contained in:
William Horvath
2026-09-02 13:03:04 -07:00
committed by Sam Lantinga
parent d8451e52d5
commit f443c429c6
+18 -4
View File
@@ -7920,8 +7920,9 @@ static bool D3D12_INTERNAL_CleanCommandBuffer(
return true;
}
static bool D3D12_Submit(
SDL_GPUCommandBuffer *commandBuffer)
static bool D3D12_INTERNAL_Submit(
SDL_GPUCommandBuffer *commandBuffer,
SDL_GPUFence **fence)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
D3D12Renderer *renderer = d3d12CommandBuffer->renderer;
@@ -7999,6 +8000,12 @@ static bool D3D12_Submit(
return false;
}
// Return the fence while submitLock is held, another thread could
// recycle this command buffer as soon as the lock is released.
if (fence) {
*fence = (SDL_GPUFence *)d3d12CommandBuffer->inFlightFence;
}
// Mark that a fence should be signaled after command list execution
res = ID3D12CommandQueue_Signal(
renderer->commandQueue,
@@ -8097,15 +8104,22 @@ static bool D3D12_Submit(
return result;
}
static bool D3D12_Submit(
SDL_GPUCommandBuffer *commandBuffer)
{
return D3D12_INTERNAL_Submit(commandBuffer, NULL);
}
static SDL_GPUFence *D3D12_SubmitAndAcquireFence(
SDL_GPUCommandBuffer *commandBuffer)
{
D3D12CommandBuffer *d3d12CommandBuffer = (D3D12CommandBuffer *)commandBuffer;
SDL_GPUFence *fence = NULL;
d3d12CommandBuffer->autoReleaseFence = false;
if (!D3D12_Submit(commandBuffer)) {
if (!D3D12_INTERNAL_Submit(commandBuffer, &fence)) {
return NULL;
}
return (SDL_GPUFence *)d3d12CommandBuffer->inFlightFence;
return fence;
}
static bool D3D12_Cancel(