From e4c9d57ddf53e50287157e7910fcf27a27d7812e Mon Sep 17 00:00:00 2001 From: Silvio Vilerino Date: Thu, 23 Apr 2026 11:43:10 -0400 Subject: [PATCH] d3d12: Flush stale video encode wait registrations when reusing ID3D12Fence objects Reviewed-by: Pohsiang (John) Hsu Part-of: --- src/gallium/drivers/d3d12/d3d12_video_enc.cpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index 6664c8f8a06..51ee7f299d0 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -4149,7 +4149,39 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].ppSubregionSizes[i] = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pspSubregionSizes[i].Get(); if (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pspSubregionFences[i] == nullptr) + { hr = pD3D12Enc->m_pD3D12Screen->dev->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pspSubregionFences[i])); + if (FAILED(hr)) { + debug_printf("CreateFence failed with HR %x\n", (unsigned)hr); + pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED; + pD3D12Enc->m_spEncodedFrameMetadata[d3d12_video_encoder_metadata_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED; + assert(false); + return; + } + } + else if (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].ppSubregionFenceValues[i] > 0) + { + // The ID3D12Fence objects in pspSubregionFences are reused across frames, but the + // d3d12_fence wrappers (pSubregionPipeFences) are recreated each frame via + // d3d12_create_fence_raw which calls SetEventOnCompletion. When a fence was never + // GPU-signaled (e.g. AUTO slice mode in prev frame produced fewer slices than allocated), + // the previous SetEventOnCompletion registration remains orphaned inside the ID3D12Fence. + // CloseHandle on the event handle (in destroy_fence) does NOT unregister it. + // CPU-signal to (new_value - 1) to flush any stale registration without + // satisfying the upcoming new one. + // At this point, the previous frame is guaranteed to be completed since when + // reusing current_metadata_slot, we only pick slots for frames that are already + // fully completed signaled (i.e. completed) as per the logic in d3d12_video_encoder_begin_frame. + hr = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pspSubregionFences[i]->Signal( + pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].ppSubregionFenceValues[i] - 1); + if (FAILED(hr)) { + debug_printf("ID3D12Fence::Signal failed with HR %x\n", (unsigned)hr); + pD3D12Enc->m_inflightResourcesPool[d3d12_video_encoder_pool_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED; + pD3D12Enc->m_spEncodedFrameMetadata[d3d12_video_encoder_metadata_current_index(pD3D12Enc)].encode_result = PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED; + assert(false); + return; + } + } pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].ppSubregionFences[i] = pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pspSubregionFences[i].Get(); pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].pSubregionPipeFences[i].reset(