d3d12converter: Add support for GPU-side external fence waiting

Ideally, GPU waiting should be scheduled just before executing command list.
But handling the case outside of converter is a bit complicated.
Under an assumption that constructed command list will be executed
immediately, schedules GPU-side waiting inside of conversion method
to simplify the flow.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6749>
This commit is contained in:
Seungha Yang 2024-04-27 19:46:51 +09:00 committed by GStreamer Marge Bot
parent c95725bb79
commit 2a14793ee1
8 changed files with 46 additions and 21 deletions

View file

@ -2149,11 +2149,16 @@ gst_d3d12_converter_check_needs_upload (GstD3D12Converter * self,
* @out_buf: a #GstBuffer
* @fence_data: a #GstD3D12FenceData
* @cl: a ID3D12GraphicsCommandList
* @queue: (allow-none): a ID3D12CommandQueue
*
* Records command list for conversion operation. converter will attach
* conversion command associated resources such as command allocator
* to @fence_data.
*
* If @queue is passed and @in_buf needs external fence wait,
* ID3D12CommandQueue::Wait() method for each external fence object
* will be executed in this method
*
* Returns: %TRUE if successful
*
* Since: 1.26
@ -2161,7 +2166,7 @@ gst_d3d12_converter_check_needs_upload (GstD3D12Converter * self,
gboolean
gst_d3d12_converter_convert_buffer (GstD3D12Converter * converter,
GstBuffer * in_buf, GstBuffer * out_buf, GstD3D12FenceData * fence_data,
ID3D12GraphicsCommandList * cl)
ID3D12GraphicsCommandList * cl, ID3D12CommandQueue * queue)
{
g_return_val_if_fail (GST_IS_D3D12_CONVERTER (converter), FALSE);
g_return_val_if_fail (GST_IS_BUFFER (in_buf), FALSE);
@ -2202,6 +2207,12 @@ gst_d3d12_converter_convert_buffer (GstD3D12Converter * converter,
auto ret = gst_d3d12_converter_execute (converter,
&in_frame, &out_frame, fence_data, cl);
if (ret && queue) {
gst_d3d12_frame_fence_gpu_wait (&in_frame, queue);
gst_d3d12_frame_fence_gpu_wait (&out_frame, queue);
}
gst_d3d12_frame_unmap (&in_frame);
gst_d3d12_frame_unmap (&out_frame);

View file

@ -164,7 +164,8 @@ gboolean gst_d3d12_converter_convert_buffer (GstD3D12Converter * conv
GstBuffer * in_buf,
GstBuffer * out_buf,
GstD3D12FenceData * fence_data,
ID3D12GraphicsCommandList * command_list);
ID3D12GraphicsCommandList * command_list,
ID3D12CommandQueue * queue);
GST_D3D12_API
gboolean gst_d3d12_converter_update_blend_state (GstD3D12Converter * converter,

View file

@ -1156,9 +1156,12 @@ gst_d3d12_compositor_preprare_func (GstVideoAggregatorPad * pad,
}
}
auto cq = gst_d3d12_device_get_command_queue (priv->ctx->device,
D3D12_COMMAND_LIST_TYPE_DIRECT);
auto cq_handle = gst_d3d12_command_queue_get_handle (cq);
if (!gst_d3d12_converter_convert_buffer (priv->ctx->conv,
buffer, self->priv->generated_output_buf, fence_data,
priv->ctx->cl.Get ())) {
priv->ctx->cl.Get (), cq_handle)) {
GST_ERROR_OBJECT (self, "Couldn't build command list");
gst_d3d12_fence_data_unref (fence_data);
return FALSE;

View file

@ -2010,8 +2010,12 @@ gst_d3d12_convert_transform (GstBaseTransform * trans, GstBuffer * inbuf,
gst_d3d12_fence_data_pool_acquire (priv->fence_data_pool, &fence_data);
gst_d3d12_fence_data_add_notify_mini_object (fence_data, gst_ca);
auto cq = gst_d3d12_device_get_command_queue (priv->ctx->device,
D3D12_COMMAND_LIST_TYPE_DIRECT);
auto cq_handle = gst_d3d12_command_queue_get_handle (cq);
if (!gst_d3d12_converter_convert_buffer (priv->ctx->conv,
inbuf, outbuf, fence_data, priv->ctx->cl.Get ())) {
inbuf, outbuf, fence_data, priv->ctx->cl.Get (), cq_handle)) {
GST_ERROR_OBJECT (self, "Couldn't build command list");
gst_d3d12_fence_data_unref (fence_data);
return GST_FLOW_ERROR;

View file

@ -1379,8 +1379,12 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self,
ptr_w, "src-height", ptr_h, "dest-x", ptr_x, "dest-y", ptr_y,
"dest-width", ptr_w, "dest-height", ptr_h, nullptr);
auto cq = gst_d3d12_device_get_command_queue (priv->device,
D3D12_COMMAND_LIST_TYPE_DIRECT);
auto cq_handle = gst_d3d12_command_queue_get_handle (cq);
if (!gst_d3d12_converter_convert_buffer (priv->mouse_blend,
priv->mouse_buf, buffer, fence_data, cl.Get ())) {
priv->mouse_buf, buffer, fence_data, cl.Get (), cq_handle)) {
GST_ERROR_OBJECT (self, "Couldn't build mouse blend command");
gst_d3d12_fence_data_unref (fence_data);
return FALSE;
@ -1392,7 +1396,7 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self,
"dest-width", ptr_w, "dest-height", ptr_h, nullptr);
if (!gst_d3d12_converter_convert_buffer (priv->mouse_xor_blend,
priv->mouse_xor_buf, buffer, fence_data, cl.Get ())) {
priv->mouse_xor_buf, buffer, fence_data, cl.Get (), nullptr)) {
GST_ERROR_OBJECT (self, "Couldn't build mouse blend command");
gst_d3d12_fence_data_unref (fence_data);
return FALSE;
@ -1406,10 +1410,6 @@ gst_d3d12_dxgi_capture_draw_mouse (GstD3D12DxgiCapture * self,
return FALSE;
}
auto cq = gst_d3d12_device_get_command_queue (priv->device,
D3D12_COMMAND_LIST_TYPE_DIRECT);
gst_d3d12_command_queue_execute_wait (cq, priv->shared_fence.Get (),
priv->fence_val);
ID3D12CommandList *cmd_list[] = { cl.Get () };
guint64 fence_val = 0;
@ -1480,15 +1480,13 @@ gst_d3d12_dxgi_capture_do_capture (GstD3D12DxgiCapture * capture,
return ret;
}
gst_d3d12_memory_set_external_fence (dmem, priv->shared_fence.Get (),
priv->fence_val);
if (draw_mouse && !gst_d3d12_dxgi_capture_draw_mouse (self, buffer, crop_box)) {
priv->WaitGPU ();
return GST_FLOW_ERROR;
}
/* Set external fence after drawing mouse.
* Otherwise converter will wait for fence value */
gst_d3d12_memory_set_external_fence (dmem, priv->shared_fence.Get (),
priv->fence_val);
return GST_FLOW_OK;
}

View file

@ -2203,7 +2203,8 @@ gst_d3d12_test_src_create (GstBaseSrc * bsrc, guint64 offset,
gst_d3d12_test_src_draw_pattern (self, pts, cl.Get ());
if (!gst_d3d12_converter_convert_buffer (priv->ctx->conv,
priv->ctx->render_buffer, convert_buffer, fence_data, cl.Get ())) {
priv->ctx->render_buffer, convert_buffer, fence_data, cl.Get (),
nullptr)) {
GST_ERROR_OBJECT (self, "Couldn't build convert command");
gst_clear_buffer (&convert_buffer);
gst_d3d12_fence_data_unref (fence_data);

View file

@ -1559,8 +1559,11 @@ gst_d3d12_window_set_buffer (GstD3D12Window * window, GstBuffer * buffer)
cl->ResourceBarrier (1, &barrier);
}
auto cq_handle = gst_d3d12_command_queue_get_handle (priv->ctx->queue);
if (!gst_d3d12_converter_convert_buffer (priv->ctx->conv,
priv->ctx->cached_buf, conv_outbuf, fence_data, cl.Get ())) {
priv->ctx->cached_buf, conv_outbuf, fence_data, cl.Get (),
cq_handle)) {
GST_ERROR_OBJECT (window, "Couldn't build convert command");
gst_d3d12_fence_data_unref (fence_data);
return GST_FLOW_ERROR;

View file

@ -454,10 +454,14 @@ gst_dwrite_d3d12_render_blend (GstDWriteRender * render, GstBuffer * layout_buf,
gboolean ret = TRUE;
GstBuffer *bgra_buf = nullptr;
auto cq = gst_d3d12_device_get_command_queue (priv->device,
D3D12_COMMAND_LIST_TYPE_DIRECT);
auto cq_handle = gst_d3d12_command_queue_get_handle (cq);
if (priv->direct_blend) {
GST_LOG_OBJECT (self, "Direct blend");
ret = gst_d3d12_converter_convert_buffer (priv->blend_conv,
layout_buf, output, fence_data, priv->cl.Get ());
layout_buf, output, fence_data, priv->cl.Get (), cq_handle);
} else {
GST_LOG_OBJECT (self, "Need conversion for blending");
@ -469,7 +473,7 @@ gst_dwrite_d3d12_render_blend (GstDWriteRender * render, GstBuffer * layout_buf,
if (ret) {
ret = gst_d3d12_converter_convert_buffer (priv->pre_conv,
output, bgra_buf, fence_data, priv->cl.Get ());
output, bgra_buf, fence_data, priv->cl.Get (), cq_handle);
}
if (ret) {
@ -486,7 +490,7 @@ gst_dwrite_d3d12_render_blend (GstDWriteRender * render, GstBuffer * layout_buf,
priv->cl->ResourceBarrier (1, &barrier);
ret = gst_d3d12_converter_convert_buffer (priv->blend_conv,
layout_buf, bgra_buf, fence_data, priv->cl.Get ());
layout_buf, bgra_buf, fence_data, priv->cl.Get (), nullptr);
}
if (ret) {
@ -517,7 +521,7 @@ gst_dwrite_d3d12_render_blend (GstDWriteRender * render, GstBuffer * layout_buf,
priv->cl->ResourceBarrier (barriers.size (), barriers.data ());
ret = gst_d3d12_converter_convert_buffer (priv->post_conv,
bgra_buf, output, fence_data, priv->cl.Get ());
bgra_buf, output, fence_data, priv->cl.Get (), nullptr);
}
gst_clear_buffer (&bgra_buf);