mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 06:58:56 +00:00
d3d12videosink: Use device's main direct queue
The idea of using separate command queue per videosink was that swapchain is bound to a command queue and we need to flush the command queue when window size is changed. But the separate queue does not seem to improve performance a lot. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6838>
This commit is contained in:
parent
c051982c0f
commit
4d779d7de8
3 changed files with 65 additions and 48 deletions
|
@ -1144,8 +1144,9 @@ gst_d3d12_video_sink_show_frame (GstVideoSink * sink, GstBuffer * buf)
|
||||||
{
|
{
|
||||||
auto self = GST_D3D12_VIDEO_SINK (sink);
|
auto self = GST_D3D12_VIDEO_SINK (sink);
|
||||||
auto priv = self->priv;
|
auto priv = self->priv;
|
||||||
|
auto sync = gst_base_sink_get_sync (GST_BASE_SINK_CAST (sink));
|
||||||
|
|
||||||
auto ret = gst_d3d12_window_present (priv->window);
|
auto ret = gst_d3d12_window_present (priv->window, sync);
|
||||||
if (ret == GST_D3D12_WINDOW_FLOW_CLOSED) {
|
if (ret == GST_D3D12_WINDOW_FLOW_CLOSED) {
|
||||||
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
|
||||||
("Output window was closed"), (nullptr));
|
("Output window was closed"), (nullptr));
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <wrl.h>
|
#include <wrl.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <queue>
|
||||||
|
|
||||||
/* *INDENT-OFF* */
|
/* *INDENT-OFF* */
|
||||||
using namespace Microsoft::WRL;
|
using namespace Microsoft::WRL;
|
||||||
|
@ -94,18 +95,7 @@ struct DeviceContext
|
||||||
event_handle = CreateEventEx (nullptr, nullptr, 0, EVENT_ALL_ACCESS);
|
event_handle = CreateEventEx (nullptr, nullptr, 0, EVENT_ALL_ACCESS);
|
||||||
device = (GstD3D12Device *) gst_object_ref (dev);
|
device = (GstD3D12Device *) gst_object_ref (dev);
|
||||||
|
|
||||||
D3D12_COMMAND_QUEUE_DESC queue_desc = { };
|
|
||||||
queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
|
||||||
queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
|
||||||
|
|
||||||
auto device_handle = gst_d3d12_device_get_device_handle (device);
|
auto device_handle = gst_d3d12_device_get_device_handle (device);
|
||||||
queue = gst_d3d12_command_queue_new (device_handle,
|
|
||||||
&queue_desc, D3D12_FENCE_FLAG_NONE, BACK_BUFFER_COUNT * 2);
|
|
||||||
if (!queue) {
|
|
||||||
GST_ERROR_OBJECT (device, "Couldn't create command queue");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ca_pool = gst_d3d12_command_allocator_pool_new (device_handle,
|
ca_pool = gst_d3d12_command_allocator_pool_new (device_handle,
|
||||||
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
||||||
if (!ca_pool) {
|
if (!ca_pool) {
|
||||||
|
@ -122,7 +112,6 @@ struct DeviceContext
|
||||||
|
|
||||||
CloseHandle (event_handle);
|
CloseHandle (event_handle);
|
||||||
|
|
||||||
gst_clear_object (&queue);
|
|
||||||
gst_clear_object (&ca_pool);
|
gst_clear_object (&ca_pool);
|
||||||
gst_clear_buffer (&cached_buf);
|
gst_clear_buffer (&cached_buf);
|
||||||
gst_clear_object (&conv);
|
gst_clear_object (&conv);
|
||||||
|
@ -133,10 +122,39 @@ struct DeviceContext
|
||||||
|
|
||||||
void WaitGpu ()
|
void WaitGpu ()
|
||||||
{
|
{
|
||||||
if (!queue)
|
if (!device)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gst_d3d12_command_queue_fence_wait (queue, G_MAXUINT64, event_handle);
|
gst_d3d12_device_fence_wait (device, D3D12_COMMAND_LIST_TYPE_DIRECT,
|
||||||
|
G_MAXUINT64, event_handle);
|
||||||
|
prev_fence_val = { };
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean BeforeRendering ()
|
||||||
|
{
|
||||||
|
UINT64 fence_val_to_wait = 0;
|
||||||
|
gboolean ret = TRUE;
|
||||||
|
|
||||||
|
while (prev_fence_val.size () > BACK_BUFFER_COUNT) {
|
||||||
|
fence_val_to_wait = prev_fence_val.front ();
|
||||||
|
prev_fence_val.pop ();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fence_val_to_wait) {
|
||||||
|
auto completed = gst_d3d12_device_get_completed_value (device,
|
||||||
|
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
||||||
|
if (completed < fence_val_to_wait) {
|
||||||
|
ret = gst_d3d12_device_fence_wait (device,
|
||||||
|
D3D12_COMMAND_LIST_TYPE_DIRECT, fence_val_to_wait, event_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AfterRendering ()
|
||||||
|
{
|
||||||
|
prev_fence_val.push (fence_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
ComPtr<ID3D12GraphicsCommandList> cl;
|
ComPtr<ID3D12GraphicsCommandList> cl;
|
||||||
|
@ -148,9 +166,9 @@ struct DeviceContext
|
||||||
GstD3D12OverlayCompositor *comp = nullptr;
|
GstD3D12OverlayCompositor *comp = nullptr;
|
||||||
GstBuffer *cached_buf = nullptr;
|
GstBuffer *cached_buf = nullptr;
|
||||||
GstD3D12Device *device = nullptr;
|
GstD3D12Device *device = nullptr;
|
||||||
GstD3D12CommandQueue *queue = nullptr;
|
|
||||||
GstD3D12CommandAllocatorPool *ca_pool = nullptr;
|
GstD3D12CommandAllocatorPool *ca_pool = nullptr;
|
||||||
UINT64 fence_val = 0;
|
UINT64 fence_val = 0;
|
||||||
|
std::queue<UINT64> prev_fence_val;
|
||||||
HANDLE event_handle;
|
HANDLE event_handle;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
};
|
};
|
||||||
|
@ -1236,7 +1254,7 @@ gst_d3d12_window_on_resize (GstD3D12Window * self)
|
||||||
if (priv->ctx->cached_buf) {
|
if (priv->ctx->cached_buf) {
|
||||||
ret = gst_d3d12_window_set_buffer (self, priv->ctx->cached_buf);
|
ret = gst_d3d12_window_set_buffer (self, priv->ctx->cached_buf);
|
||||||
if (ret == GST_FLOW_OK)
|
if (ret == GST_FLOW_OK)
|
||||||
ret = gst_d3d12_window_present (self);
|
ret = gst_d3d12_window_present (self, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1311,8 +1329,9 @@ gst_d3d12_window_prepare (GstD3D12Window * window, GstD3D12Device * device,
|
||||||
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
|
||||||
|
|
||||||
auto factory = gst_d3d12_device_get_factory_handle (device);
|
auto factory = gst_d3d12_device_get_factory_handle (device);
|
||||||
|
auto queue = gst_d3d12_device_get_command_queue (device,
|
||||||
auto cq = gst_d3d12_command_queue_get_handle (ctx->queue);
|
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
||||||
|
auto cq = gst_d3d12_command_queue_get_handle (queue);
|
||||||
|
|
||||||
ComPtr < IDXGISwapChain1 > swapchain;
|
ComPtr < IDXGISwapChain1 > swapchain;
|
||||||
hr = factory->CreateSwapChainForHwnd (cq, priv->hwnd,
|
hr = factory->CreateSwapChainForHwnd (cq, priv->hwnd,
|
||||||
|
@ -1559,7 +1578,9 @@ gst_d3d12_window_set_buffer (GstD3D12Window * window, GstBuffer * buffer)
|
||||||
cl->ResourceBarrier (1, &barrier);
|
cl->ResourceBarrier (1, &barrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cq_handle = gst_d3d12_command_queue_get_handle (priv->ctx->queue);
|
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,
|
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 (),
|
||||||
|
@ -1610,28 +1631,14 @@ gst_d3d12_window_set_buffer (GstD3D12Window * window, GstBuffer * buffer)
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
guint64 max_fence_val = 0;
|
if (!priv->ctx->BeforeRendering ()) {
|
||||||
auto num_mem = gst_buffer_n_memory (priv->ctx->cached_buf);
|
GST_ERROR_OBJECT (window, "Couldn't wait fence value");
|
||||||
for (guint i = 0; i < num_mem; i++) {
|
gst_d3d12_fence_data_unref (fence_data);
|
||||||
mem = (GstD3D12Memory *) gst_buffer_peek_memory (priv->ctx->cached_buf, 0);
|
return GST_FLOW_ERROR;
|
||||||
if (mem->fence_value > max_fence_val)
|
|
||||||
max_fence_val = mem->fence_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
max_fence_val = MAX (max_fence_val, overlay_fence_val);
|
|
||||||
auto completed = gst_d3d12_device_get_completed_value (priv->ctx->device,
|
|
||||||
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
|
||||||
|
|
||||||
if (completed < max_fence_val) {
|
|
||||||
auto device_queue = gst_d3d12_device_get_command_queue (priv->ctx->device,
|
|
||||||
D3D12_COMMAND_LIST_TYPE_DIRECT);
|
|
||||||
auto fence = gst_d3d12_command_queue_get_fence_handle (device_queue);
|
|
||||||
gst_d3d12_command_queue_execute_wait (priv->ctx->queue, fence,
|
|
||||||
max_fence_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ID3D12CommandList *cmd_list[] = { cl.Get () };
|
ID3D12CommandList *cmd_list[] = { cl.Get () };
|
||||||
hr = gst_d3d12_command_queue_execute_command_lists (priv->ctx->queue,
|
hr = gst_d3d12_command_queue_execute_command_lists (cq,
|
||||||
1, cmd_list, &priv->ctx->fence_val);
|
1, cmd_list, &priv->ctx->fence_val);
|
||||||
if (!gst_d3d12_result (hr, priv->ctx->device)) {
|
if (!gst_d3d12_result (hr, priv->ctx->device)) {
|
||||||
GST_ERROR_OBJECT (window, "Signal failed");
|
GST_ERROR_OBJECT (window, "Signal failed");
|
||||||
|
@ -1639,16 +1646,17 @@ gst_d3d12_window_set_buffer (GstD3D12Window * window, GstBuffer * buffer)
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
gst_d3d12_command_queue_set_notify (priv->ctx->queue, priv->ctx->fence_val,
|
gst_d3d12_command_queue_set_notify (cq, priv->ctx->fence_val,
|
||||||
fence_data, (GDestroyNotify) gst_d3d12_fence_data_unref);
|
fence_data, (GDestroyNotify) gst_d3d12_fence_data_unref);
|
||||||
|
|
||||||
priv->backbuf_rendered = TRUE;
|
priv->backbuf_rendered = TRUE;
|
||||||
|
priv->ctx->AfterRendering ();
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
GstFlowReturn
|
GstFlowReturn
|
||||||
gst_d3d12_window_present (GstD3D12Window * window)
|
gst_d3d12_window_present (GstD3D12Window * window, gboolean sync)
|
||||||
{
|
{
|
||||||
auto priv = window->priv;
|
auto priv = window->priv;
|
||||||
|
|
||||||
|
@ -1665,20 +1673,27 @@ gst_d3d12_window_present (GstD3D12Window * window)
|
||||||
|
|
||||||
if (priv->backbuf_rendered) {
|
if (priv->backbuf_rendered) {
|
||||||
DXGI_PRESENT_PARAMETERS params = { };
|
DXGI_PRESENT_PARAMETERS params = { };
|
||||||
|
UINT present_flag = sync ? 0 : DXGI_PRESENT_DO_NOT_WAIT;
|
||||||
|
|
||||||
if (!priv->first_present) {
|
if (!priv->first_present) {
|
||||||
params.DirtyRectsCount = 1;
|
params.DirtyRectsCount = 1;
|
||||||
params.pDirtyRects = &priv->dirty_rect;
|
params.pDirtyRects = &priv->dirty_rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto hr = priv->ctx->swapchain->Present1 (0,
|
|
||||||
DXGI_PRESENT_DO_NOT_WAIT, ¶ms);
|
|
||||||
|
|
||||||
priv->first_present = FALSE;
|
priv->first_present = FALSE;
|
||||||
priv->backbuf_rendered = FALSE;
|
priv->backbuf_rendered = FALSE;
|
||||||
if (hr != DXGI_ERROR_WAS_STILL_DRAWING &&
|
|
||||||
!gst_d3d12_result (hr, window->device))
|
auto hr = priv->ctx->swapchain->Present1 (0, present_flag, ¶ms);
|
||||||
GST_WARNING_OBJECT (window, "Present return 0x%x", (guint) hr);
|
switch (hr) {
|
||||||
|
case DXGI_ERROR_DEVICE_REMOVED:
|
||||||
|
case DXGI_ERROR_INVALID_CALL:
|
||||||
|
case E_OUTOFMEMORY:
|
||||||
|
gst_d3d12_result (hr, window->device);
|
||||||
|
return GST_FLOW_ERROR;
|
||||||
|
default:
|
||||||
|
/* Ignore other return code */
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
|
|
@ -62,7 +62,8 @@ void gst_d3d12_window_unlock_stop (GstD3D12Window * window);
|
||||||
GstFlowReturn gst_d3d12_window_set_buffer (GstD3D12Window * window,
|
GstFlowReturn gst_d3d12_window_set_buffer (GstD3D12Window * window,
|
||||||
GstBuffer * buffer);
|
GstBuffer * buffer);
|
||||||
|
|
||||||
GstFlowReturn gst_d3d12_window_present (GstD3D12Window * window);
|
GstFlowReturn gst_d3d12_window_present (GstD3D12Window * window,
|
||||||
|
gboolean sync);
|
||||||
|
|
||||||
void gst_d3d12_window_set_render_rect (GstD3D12Window * window,
|
void gst_d3d12_window_set_render_rect (GstD3D12Window * window,
|
||||||
const GstVideoRectangle * rect);
|
const GstVideoRectangle * rect);
|
||||||
|
|
Loading…
Reference in a new issue