d3d12frame: Extract external fence from memory and wait helper function

Adding gst_d3d12_frame_fence_{gpu,cpu}_wait() methods

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6749>
This commit is contained in:
Seungha Yang 2024-04-27 23:29:40 +09:00 committed by GStreamer Marge Bot
parent 478e49dd73
commit 87f43c25cc
2 changed files with 145 additions and 1 deletions

View file

@ -27,6 +27,12 @@
#include "gstd3d12-private.h"
#include <string.h>
#include <directx/d3dx12.h>
#include <vector>
#include <wrl.h>
/* *INDENT-OFF* */
using namespace Microsoft::WRL;
/* *INDENT-ON* */
#ifndef GST_DISABLE_GST_DEBUG
#define GST_CAT_DEFAULT ensure_debug_category()
@ -90,7 +96,7 @@ gst_d3d12_frame_map (GstD3D12Frame * frame, const GstVideoInfo * info,
for (guint i = 0; i < num_mem; i++) {
auto mem = gst_buffer_peek_memory (buffer, i);
if (!gst_is_d3d12_memory (mem)) {
GST_WARNING ("memory %u is not a d3d12 memory", i);
GST_LOG ("memory %u is not a d3d12 memory", i);
return FALSE;
}
@ -217,6 +223,9 @@ gst_d3d12_frame_map (GstD3D12Frame * frame, const GstVideoInfo * info,
rtv_handle.Offset (rtv_inc_size);
}
gst_d3d12_memory_get_external_fence (dmem, &frame->fence[plane_idx].fence,
&frame->fence[plane_idx].fence_value);
plane_idx++;
}
}
@ -266,6 +275,11 @@ gst_d3d12_frame_unmap (GstD3D12Frame * frame)
{
g_return_if_fail (frame);
for (guint i = 0; i < G_N_ELEMENTS (frame->fence); i++) {
if (frame->fence[i].fence)
frame->fence[i].fence->Release ();
}
for (guint i = 0; i < G_N_ELEMENTS (frame->map); i++) {
auto mem = frame->map[i].memory;
if (!mem)
@ -337,6 +351,12 @@ gst_d3d12_frame_copy (GstD3D12Frame * dest, const GstD3D12Frame * src,
gst_d3d12_fence_data_add_notify_mini_object (fence_data,
gst_buffer_ref (src->buffer));
auto cq = gst_d3d12_device_get_command_queue (src->device,
D3D12_COMMAND_LIST_TYPE_DIRECT);
auto cq_handle = gst_d3d12_command_queue_get_handle (cq);
gst_d3d12_frame_fence_gpu_wait (src, cq_handle);
gst_d3d12_frame_fence_gpu_wait (dest, cq_handle);
return gst_d3d12_device_copy_texture_region (dest->device,
GST_VIDEO_INFO_N_PLANES (&dest->info), args, fence_data,
nullptr, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, fence_value);
@ -383,6 +403,113 @@ gst_d3d12_frame_copy_plane (GstD3D12Frame * dest, const GstD3D12Frame * src,
gst_d3d12_fence_data_add_notify_mini_object (fence_data,
gst_buffer_ref (src->buffer));
auto cq = gst_d3d12_device_get_command_queue (src->device,
D3D12_COMMAND_LIST_TYPE_DIRECT);
auto cq_handle = gst_d3d12_command_queue_get_handle (cq);
if (src->fence[plane].fence)
cq_handle->Wait (src->fence[plane].fence, src->fence[plane].fence_value);
if (dest->fence[plane].fence)
cq_handle->Wait (dest->fence[plane].fence, dest->fence[plane].fence_value);
return gst_d3d12_device_copy_texture_region (dest->device, 1, &args,
fence_data, nullptr, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, fence_value);
}
/**
* gst_d3d12_frame_fence_gpu_wait:
* @frame: a #GstD3D12Frame
* @queue: a ID3D12CommandQueue
*
* Executes ID3D12CommandQueue::Wait() if external fence exists
*
* Returns: %TRUE on success.
*
* Since: 1.26
*/
gboolean
gst_d3d12_frame_fence_gpu_wait (const GstD3D12Frame * frame,
ID3D12CommandQueue * queue)
{
g_return_val_if_fail (frame, FALSE);
g_return_val_if_fail (GST_IS_D3D12_DEVICE (frame->device), FALSE);
g_return_val_if_fail (queue, FALSE);
ID3D12Fence *last_fence = nullptr;
guint64 last_fence_val = 0;
for (guint i = 0; i < G_N_ELEMENTS (frame->fence); i++) {
if (frame->fence[i].fence) {
if (frame->fence[i].fence == last_fence &&
frame->fence[i].fence_value <= last_fence_val) {
continue;
}
last_fence = frame->fence[i].fence;
last_fence_val = frame->fence[i].fence_value;
auto hr = queue->Wait (frame->fence[i].fence,
frame->fence[i].fence_value);
if (!gst_d3d12_result (hr, frame->device))
return FALSE;
}
}
return TRUE;
}
/**
* gst_d3d12_frame_fence_cpu_wait:
* @frame: a #GstD3D12Frame
*
* Waits for external fence objects
*
* Returns: %TRUE on success.
*
* Since: 1.26
*/
gboolean
gst_d3d12_frame_fence_cpu_wait (const GstD3D12Frame * frame)
{
g_return_val_if_fail (frame, FALSE);
g_return_val_if_fail (GST_IS_D3D12_DEVICE (frame->device), FALSE);
ID3D12Fence *last_fence = nullptr;
guint64 last_fence_val = 0;
std::vector < ID3D12Fence * >fences;
std::vector < UINT64 > fence_vals;
for (guint i = 0; i < G_N_ELEMENTS (frame->fence); i++) {
if (frame->fence[i].fence) {
if (frame->fence[i].fence == last_fence &&
frame->fence[i].fence_value <= last_fence_val) {
continue;
}
last_fence = frame->fence[i].fence;
last_fence_val = frame->fence[i].fence_value;
fences.push_back (frame->fence[i].fence);
fence_vals.push_back (frame->fence[i].fence_value);
}
}
if (fences.empty ())
return TRUE;
ComPtr < ID3D12Device1 > device1;
auto device = gst_d3d12_device_get_device_handle (frame->device);
auto hr = device->QueryInterface (IID_PPV_ARGS (&device1));
if (SUCCEEDED (hr)) {
hr = device1->SetEventOnMultipleFenceCompletion (fences.data (),
fence_vals.data (), fences.size (), D3D12_MULTIPLE_FENCE_WAIT_FLAG_ALL,
nullptr);
} else {
for (size_t i = 0; i < fences.size (); i++) {
hr = fences[i]->SetEventOnCompletion (fence_vals[i], nullptr);
if (FAILED (hr))
break;
}
}
return gst_d3d12_result (hr, frame->device);
}

View file

@ -25,6 +25,8 @@
G_BEGIN_DECLS
typedef struct _GstD3D12FrameFence GstD3D12FrameFence;
/**
* GstD3D12FrameMapFlags:
* @GST_D3D12_FRAME_MAP_FLAG_NONE: No flags
@ -42,6 +44,12 @@ typedef enum
DEFINE_ENUM_FLAG_OPERATORS (GstD3D12FrameMapFlags);
struct _GstD3D12FrameFence
{
ID3D12Fence *fence;
guint64 fence_value;
};
/**
* GstD3D12Frame:
* @info: the #GstVideoInfo
@ -53,6 +61,7 @@ DEFINE_ENUM_FLAG_OPERATORS (GstD3D12FrameMapFlags);
* @data: pointers to the plane data
* @subresource_index: subresource index of the plane
* @plane_rect: plane rectangle
* @fence: external fences
* @srv_desc_handle: shader resource view descriptor handle
* @rtb_desc_handle: render target view descriptor handle
*
@ -72,6 +81,7 @@ struct _GstD3D12Frame
ID3D12Resource *data[GST_VIDEO_MAX_PLANES];
guint subresource_index[GST_VIDEO_MAX_PLANES];
D3D12_RECT plane_rect[GST_VIDEO_MAX_PLANES];
GstD3D12FrameFence fence[GST_VIDEO_MAX_PLANES];
D3D12_CPU_DESCRIPTOR_HANDLE srv_desc_handle[GST_VIDEO_MAX_PLANES];
D3D12_CPU_DESCRIPTOR_HANDLE rtv_desc_handle[GST_VIDEO_MAX_PLANES];
@ -100,5 +110,12 @@ gboolean gst_d3d12_frame_copy_plane (GstD3D12Frame * dest,
guint plane,
guint64 * fence_value);
GST_D3D12_API
gboolean gst_d3d12_frame_fence_gpu_wait (const GstD3D12Frame * frame,
ID3D12CommandQueue * queue);
GST_D3D12_API
gboolean gst_d3d12_frame_fence_cpu_wait (const GstD3D12Frame * frame);
G_END_DECLS