From a5af8866dfd43144c5b8112c3ae125752340144b Mon Sep 17 00:00:00 2001 From: Silvio Vilerino Date: Fri, 17 Oct 2025 08:32:54 -0400 Subject: [PATCH] p_video_codec::encode_bitstream_sliced: Add last_slice_completion_fence for PIPE_VIDEO_SLICE_MODE_AUTO Reviewed-by: Ruijing Dong Reviewed-by: Pohsiang (John) Hsu Part-of: --- src/gallium/drivers/d3d12/d3d12_video_enc.cpp | 5 +++++ src/gallium/drivers/d3d12/d3d12_video_enc.h | 2 ++ src/gallium/frontends/mediafoundation/context.h | 1 + src/gallium/frontends/mediafoundation/encode.cpp | 1 + .../frontends/mediafoundation/mftransform.cpp | 14 +++++++++++++- src/gallium/include/pipe/p_video_codec.h | 14 ++++++++++++-- 6 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index 01a4caf2f05..73cfae1bbb5 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -3095,6 +3095,7 @@ d3d12_video_encoder_encode_bitstream_sliced(struct pipe_video_codec *codec, unsigned num_slice_objects, struct pipe_resource **slice_destinations, struct pipe_fence_handle **slice_fences, + struct pipe_fence_handle **last_slice_completion_fence, void **feedback) { struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; @@ -3109,6 +3110,7 @@ d3d12_video_encoder_encode_bitstream_sliced(struct pipe_video_codec *codec, num_slice_objects, slice_destinations, slice_fences, + last_slice_completion_fence, feedback); } @@ -3119,11 +3121,13 @@ d3d12_video_encoder_encode_bitstream(struct pipe_video_codec * codec, void ** feedback) { struct pipe_fence_handle *slice_fences = NULL; + struct pipe_fence_handle *last_slice_completion_fence = NULL; d3d12_video_encoder_encode_bitstream_impl(codec, source, 1 /*num_slice_objects*/, &destination /*slice_destinations*/, &slice_fences, + &last_slice_completion_fence, feedback); } @@ -3133,6 +3137,7 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, unsigned num_slice_objects, struct pipe_resource **slice_destinations, struct pipe_fence_handle **slice_fences, + [[maybe_unused]] struct pipe_fence_handle **last_slice_completion_fence, void **feedback) { struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.h b/src/gallium/drivers/d3d12/d3d12_video_enc.h index d4ff33491cb..d1a37495f6f 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.h +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.h @@ -120,6 +120,7 @@ d3d12_video_encoder_encode_bitstream_sliced(struct pipe_video_codec *codec, unsigned num_slice_objects, struct pipe_resource **slice_destinations, struct pipe_fence_handle **slice_fences, + struct pipe_fence_handle **last_slice_completion_fence, void **feedback); void @@ -128,6 +129,7 @@ d3d12_video_encoder_encode_bitstream_impl(struct pipe_video_codec *codec, unsigned num_slice_objects, struct pipe_resource **slice_destinations, struct pipe_fence_handle **slice_fences, + struct pipe_fence_handle **last_slice_completion_fence, void **feedback); void diff --git a/src/gallium/frontends/mediafoundation/context.h b/src/gallium/frontends/mediafoundation/context.h index ef0bb9f11f0..8b04442dd6a 100644 --- a/src/gallium/frontends/mediafoundation/context.h +++ b/src/gallium/frontends/mediafoundation/context.h @@ -38,6 +38,7 @@ typedef class DX12EncodeContext struct pipe_fence_handle *pAsyncFence = NULL; std::vector pOutputBitRes; std::vector pSliceFences; + struct pipe_fence_handle * pLastSliceFence; D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM_NOTIFICATION_MODE sliceNotificationMode = D3D12_VIDEO_ENCODER_COMPRESSED_BITSTREAM_NOTIFICATION_MODE_FULL_FRAME; pipe_resource *pPipeResourceQPMapStats = nullptr; diff --git a/src/gallium/frontends/mediafoundation/encode.cpp b/src/gallium/frontends/mediafoundation/encode.cpp index 2ee1e6aa45a..467b56be2ba 100644 --- a/src/gallium/frontends/mediafoundation/encode.cpp +++ b/src/gallium/frontends/mediafoundation/encode.cpp @@ -574,6 +574,7 @@ CDX12EncHMFT::PrepareForEncode( IMFSample *pSample, LPDX12EncodeContext *ppDX12E pDX12EncodeContext->pOutputBitRes.resize( num_output_buffers, NULL ); pDX12EncodeContext->pSliceFences.resize( num_output_buffers, NULL ); + pDX12EncodeContext->pLastSliceFence = NULL; for( uint32_t slice_idx = 0; slice_idx < num_output_buffers; slice_idx++ ) { if( ( slice_idx > 0 ) && !m_EncoderCapabilities.m_HWSupportSlicedFences.bits.multiple_buffers_required ) diff --git a/src/gallium/frontends/mediafoundation/mftransform.cpp b/src/gallium/frontends/mediafoundation/mftransform.cpp index ac9f10c7a7c..95e564f113a 100644 --- a/src/gallium/frontends/mediafoundation/mftransform.cpp +++ b/src/gallium/frontends/mediafoundation/mftransform.cpp @@ -1211,7 +1211,6 @@ CDX12EncHMFT::xThreadProc( void *pCtx ) pDX12EncodeContext->pSliceFences[slice_idx], OS_TIMEOUT_INFINITE ) != 0; assert( fenceWaitResult ); - pThis->m_pPipeVideoCodec->destroy_fence( pThis->m_pPipeVideoCodec, pDX12EncodeContext->pSliceFences[slice_idx] ); if( fenceWaitResult ) { unsigned codec_unit_metadata_count = 0u; @@ -1261,6 +1260,18 @@ CDX12EncHMFT::xThreadProc( void *pCtx ) } } + // Cleanup fences + for (unsigned slice_idx = 0; slice_idx < pDX12EncodeContext->pSliceFences.size(); slice_idx++) + { + if (pDX12EncodeContext->pSliceFences[slice_idx]) + pThis->m_pPipeVideoCodec->destroy_fence( pThis->m_pPipeVideoCodec, pDX12EncodeContext->pSliceFences[slice_idx] ); + } + if (pDX12EncodeContext->pLastSliceFence) + { + pThis->m_pPipeVideoCodec->destroy_fence( pThis->m_pPipeVideoCodec, pDX12EncodeContext->pLastSliceFence ); + pDX12EncodeContext->pLastSliceFence = nullptr; + } + memset( pDX12EncodeContext->pSliceFences.data(), 0, pDX12EncodeContext->pSliceFences.size() * sizeof( pipe_fence_handle * ) ); @@ -2203,6 +2214,7 @@ CDX12EncHMFT::ProcessInput( DWORD dwInputStreamIndex, IMFSample *pSample, DWORD static_cast( pDX12EncodeContext->pOutputBitRes.size() ), pDX12EncodeContext->pOutputBitRes.data(), pDX12EncodeContext->pSliceFences.data(), // driver outputs the fences + &pDX12EncodeContext->pLastSliceFence, // driver outputs the last slice fence &pDX12EncodeContext->pAsyncCookie ); } else diff --git a/src/gallium/include/pipe/p_video_codec.h b/src/gallium/include/pipe/p_video_codec.h index 06f24c6f3ae..34326d8ce2a 100644 --- a/src/gallium/include/pipe/p_video_codec.h +++ b/src/gallium/include/pipe/p_video_codec.h @@ -105,13 +105,22 @@ struct pipe_video_codec * * num_slice_objects indicates the number of elements in the input * array slice_destinations and indicates the number of outputs expected - * in slice_fences + * in slice_fences. For PIPE_VIDEO_SLICE_MODE_AUTO where slice count is + * unknown, num_slice_objects must be PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME * * The frame NALs are attached to the first slice buffer * Any packed slice header (e.g SVC NAL prefix) is attached to each slice buffer * * get_feedback information/stats is still only available after full frame - * completion is signaled (e.g pipe_picture_desc::fence) + * completion is signaled (e.g pipe_picture_desc::out_fence) + * + * last_slice_completion_fence signals when all slices complete, which may happen + * before pipe_picture_desc::out_fence signals, given that includes all GPU work + * submitted for the frame including get_feedback information/stats processing. + * For PIPE_VIDEO_SLICE_MODE_AUTO where num_slice_objects is equal to the + * PIPE_VIDEO_CAP_ENC_MAX_SLICES_PER_FRAME, this fence tells the frontend + * when to stop waiting for slice_fences[] without needing to wait for + * full frame completion. * * Driver reports support for this function used with different codecs/profiles * in PIPE_VIDEO_CAP_ENC_SLICED_NOTIFICATIONS, frontend must check before using it. @@ -121,6 +130,7 @@ struct pipe_video_codec unsigned num_slice_objects, struct pipe_resource **slice_destinations, struct pipe_fence_handle **slice_fences, + struct pipe_fence_handle **last_slice_completion_fence, void **feedback);