diff --git a/src/gallium/drivers/d3d12/d3d12_context.h b/src/gallium/drivers/d3d12/d3d12_context.h index 6a161806aad..4f53232e91b 100644 --- a/src/gallium/drivers/d3d12/d3d12_context.h +++ b/src/gallium/drivers/d3d12/d3d12_context.h @@ -336,6 +336,11 @@ d3d12_context_set_queue_priority_manager(struct pipe_context *ctx, struct d3d12_ int d3d12_video_encoder_set_max_async_queue_depth(struct pipe_context *ctx, uint32_t max_async_depth); +int +d3d12_video_encoder_get_last_slice_completion_fence(struct pipe_video_codec *codec, + void *feedback, + pipe_fence_handle **last_slice_completion_fence); + bool d3d12_enable_fake_so_buffers(struct d3d12_context *ctx, unsigned factor); diff --git a/src/gallium/drivers/d3d12/d3d12_interop_public.h b/src/gallium/drivers/d3d12/d3d12_interop_public.h index b4da22e4e53..27ece99261c 100644 --- a/src/gallium/drivers/d3d12/d3d12_interop_public.h +++ b/src/gallium/drivers/d3d12/d3d12_interop_public.h @@ -189,6 +189,26 @@ struct d3d12_interop_device_info1 { * Returns int (0 for success, error code otherwise) */ int (*set_video_encoder_max_async_queue_depth)(struct pipe_context *context, uint32_t max_async_queue_depth); + + /* + * Function pointer to get the last slice completion fence for a video encoder, + * which may happen before the entire frame is complete, including the stats. + * If this function is NULL, the driver does not support getting the last slice completion fence. + * + * Parameters: + * - pipe_video_codec*: codec to query + * - void*: feedback data to provide to the driver to indicate the frame feedback + * from which to get the last slice completion fence returned by + * pipe_video_codec::encode_bitstream/encode_bitstream_sliced. + * - pipe_fence_handle**: pointer to a fence handle to be filled in by the driver + * + * The caller must call pipe_video_codec::destroy_fence to destroy the returned fence handle + * + * Returns int (0 for success, error code otherwise) + */ + int (*get_video_enc_last_slice_completion_fence)(struct pipe_video_codec *codec, + void *feedback, + struct pipe_fence_handle **fence); }; #ifdef __cplusplus diff --git a/src/gallium/drivers/d3d12/d3d12_screen.cpp b/src/gallium/drivers/d3d12/d3d12_screen.cpp index f569c60ee67..d30d1b4cce3 100644 --- a/src/gallium/drivers/d3d12/d3d12_screen.cpp +++ b/src/gallium/drivers/d3d12/d3d12_screen.cpp @@ -1162,6 +1162,7 @@ d3d12_interop_query_device_info(struct pipe_screen *pscreen, uint32_t data_size, d3d12_interop_device_info1 *info1 = (d3d12_interop_device_info1 *)data; info1->set_context_queue_priority_manager = d3d12_context_set_queue_priority_manager; info1->set_video_encoder_max_async_queue_depth = d3d12_video_encoder_set_max_async_queue_depth; + info1->get_video_enc_last_slice_completion_fence = d3d12_video_encoder_get_last_slice_completion_fence; return sizeof(*info1); } diff --git a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp index a87ae6bee45..03691f80644 100644 --- a/src/gallium/drivers/d3d12/d3d12_video_enc.cpp +++ b/src/gallium/drivers/d3d12/d3d12_video_enc.cpp @@ -5018,3 +5018,39 @@ d3d12_video_encoder_fence_wait(struct pipe_video_codec *codec, // ret != 0 -> Encode completed return wait_res ? 1 : 0; } + +int +d3d12_video_encoder_get_last_slice_completion_fence(struct pipe_video_codec *codec, + void *feedback, + pipe_fence_handle **last_slice_completion_fence) +{ + struct d3d12_video_encoder *pD3D12Enc = (struct d3d12_video_encoder *) codec; + assert(pD3D12Enc); + + if (!pD3D12Enc || !feedback || !last_slice_completion_fence) { + return -1; + } + + struct d3d12_fence *feedback_fence = (struct d3d12_fence *) feedback; + uint64_t requested_metadata_fence = feedback_fence->value; + size_t current_metadata_slot = static_cast(requested_metadata_fence % pD3D12Enc->m_MaxMetadataBuffersCount); + + // Check if the requested metadata is valid + if ((pD3D12Enc->m_fenceValue - requested_metadata_fence) > pD3D12Enc->m_MaxMetadataBuffersCount) { + debug_printf("[d3d12_video_encoder_get_last_slice_completion_fence] Requested metadata for fence %" PRIu64 " at current fence %" PRIu64 + " is too far back in time for the ring buffer of size %" PRIu64 "\n", + requested_metadata_fence, + pD3D12Enc->m_fenceValue, + static_cast(pD3D12Enc->m_MaxMetadataBuffersCount)); + return -1; + } + + // Get the last slice completion fence for this frame + if (pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_LastSliceFence) { + d3d12_fence_reference((struct d3d12_fence **)last_slice_completion_fence, + pD3D12Enc->m_spEncodedFrameMetadata[current_metadata_slot].m_LastSliceFence.get()); + return 0; + } + + return -1; +} \ No newline at end of file