mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
d3d11videosink: Add present signal
The "present" signal will be emitted just before the IDXGISwapChain::Present() call. The client can perform additional GPU operation with given GstD3D11Device object and ID3D11RenderTargetView handle. Or, the client can read back the scene to be displayed on window using the signal. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2923>
This commit is contained in:
parent
625e74100d
commit
470436d7e6
6 changed files with 86 additions and 9 deletions
|
@ -78,6 +78,7 @@ enum
|
||||||
{
|
{
|
||||||
/* signals */
|
/* signals */
|
||||||
SIGNAL_BEGIN_DRAW,
|
SIGNAL_BEGIN_DRAW,
|
||||||
|
SIGNAL_PRESENT,
|
||||||
|
|
||||||
/* actions */
|
/* actions */
|
||||||
SIGNAL_DRAW,
|
SIGNAL_DRAW,
|
||||||
|
@ -351,6 +352,31 @@ gst_d3d11_video_sink_class_init (GstD3D11VideoSinkClass * klass)
|
||||||
G_TYPE_BOOLEAN, 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT64,
|
G_TYPE_BOOLEAN, 4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT64,
|
||||||
G_TYPE_UINT64);
|
G_TYPE_UINT64);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstD3D11VideoSink::present
|
||||||
|
* @videosink: the #GstD3D11VideoSink
|
||||||
|
* @device: a #GstD3D11Device handle
|
||||||
|
* @render_target: a ID3D11RenderTargetView handle of swapchain's backbuffer
|
||||||
|
*
|
||||||
|
* Emitted just before presenting a texture via the IDXGISwapChain::Present.
|
||||||
|
* The client can perform additional rendering on the given @render_target,
|
||||||
|
* or can read the content already rendered on the swapchain's backbuffer.
|
||||||
|
*
|
||||||
|
* This signal will be emitted with gst_d3d11_device_lock() taken and
|
||||||
|
* client should perform GPU operation from the thread where this signal
|
||||||
|
* emitted.
|
||||||
|
*
|
||||||
|
* If a client wants to listen this signal, the client must connect this
|
||||||
|
* signal before the first present. Otherwise this signal will not be
|
||||||
|
* emitted.
|
||||||
|
*
|
||||||
|
* Since: 1.22
|
||||||
|
*/
|
||||||
|
gst_d3d11_video_sink_signals[SIGNAL_PRESENT] =
|
||||||
|
g_signal_new ("present", G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST, 0, nullptr, nullptr, nullptr,
|
||||||
|
G_TYPE_NONE, 2, GST_TYPE_D3D11_DEVICE, G_TYPE_POINTER);
|
||||||
|
|
||||||
element_class->set_context =
|
element_class->set_context =
|
||||||
GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_set_context);
|
GST_DEBUG_FUNCPTR (gst_d3d11_video_sink_set_context);
|
||||||
|
|
||||||
|
@ -763,6 +789,14 @@ gst_d3d11_video_mouse_key_event (GstD3D11Window * window, const gchar * event,
|
||||||
gst_navigation_send_event_simple (GST_NAVIGATION (self), mouse_event);
|
gst_navigation_send_event_simple (GST_NAVIGATION (self), mouse_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_d3d11_video_sink_present (GstD3D11Window * window, GstD3D11Device * device,
|
||||||
|
ID3D11RenderTargetView * rtv, GstD3D11VideoSink * self)
|
||||||
|
{
|
||||||
|
g_signal_emit (self, gst_d3d11_video_sink_signals[SIGNAL_PRESENT], 0,
|
||||||
|
device, rtv);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_d3d11_video_sink_start (GstBaseSink * sink)
|
gst_d3d11_video_sink_start (GstBaseSink * sink)
|
||||||
{
|
{
|
||||||
|
@ -784,6 +818,7 @@ static gboolean
|
||||||
gst_d3d11_video_sink_prepare_window (GstD3D11VideoSink * self)
|
gst_d3d11_video_sink_prepare_window (GstD3D11VideoSink * self)
|
||||||
{
|
{
|
||||||
GstD3D11WindowNativeType window_type = GST_D3D11_WINDOW_NATIVE_TYPE_HWND;
|
GstD3D11WindowNativeType window_type = GST_D3D11_WINDOW_NATIVE_TYPE_HWND;
|
||||||
|
gboolean emit_present = FALSE;
|
||||||
|
|
||||||
if (self->window)
|
if (self->window)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -847,11 +882,18 @@ done:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Emits present signal only if signal is connected for performance reason */
|
||||||
|
if (g_signal_has_handler_pending (self,
|
||||||
|
gst_d3d11_video_sink_signals[SIGNAL_PRESENT], 0, FALSE)) {
|
||||||
|
emit_present = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
g_object_set (self->window,
|
g_object_set (self->window,
|
||||||
"force-aspect-ratio", self->force_aspect_ratio,
|
"force-aspect-ratio", self->force_aspect_ratio,
|
||||||
"fullscreen-toggle-mode", self->fullscreen_toggle_mode,
|
"fullscreen-toggle-mode", self->fullscreen_toggle_mode,
|
||||||
"fullscreen", self->fullscreen,
|
"fullscreen", self->fullscreen,
|
||||||
"enable-navigation-events", self->enable_navigation_events, NULL);
|
"enable-navigation-events", self->enable_navigation_events,
|
||||||
|
"emit-present", emit_present, nullptr);
|
||||||
|
|
||||||
gst_d3d11_window_set_orientation (self->window, self->selected_method);
|
gst_d3d11_window_set_orientation (self->window, self->selected_method);
|
||||||
|
|
||||||
|
@ -859,6 +901,8 @@ done:
|
||||||
G_CALLBACK (gst_d3d11_video_sink_key_event), self);
|
G_CALLBACK (gst_d3d11_video_sink_key_event), self);
|
||||||
g_signal_connect (self->window, "mouse-event",
|
g_signal_connect (self->window, "mouse-event",
|
||||||
G_CALLBACK (gst_d3d11_video_mouse_key_event), self);
|
G_CALLBACK (gst_d3d11_video_mouse_key_event), self);
|
||||||
|
g_signal_connect (self->window, "present",
|
||||||
|
G_CALLBACK (gst_d3d11_video_sink_present), self);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,18 +54,20 @@ enum
|
||||||
PROP_FULLSCREEN,
|
PROP_FULLSCREEN,
|
||||||
PROP_WINDOW_HANDLE,
|
PROP_WINDOW_HANDLE,
|
||||||
PROP_RENDER_STATS,
|
PROP_RENDER_STATS,
|
||||||
|
PROP_EMIT_PRESENT,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
|
#define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE
|
||||||
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
#define DEFAULT_FORCE_ASPECT_RATIO TRUE
|
||||||
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
|
#define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE
|
||||||
#define DEFAULT_FULLSCREEN FALSE
|
#define DEFAULT_FULLSCREEN FALSE
|
||||||
#define DEFAULT_RENDER_STATS FALSE
|
#define DEFAULT_EMIT_PRESENT FALSE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
SIGNAL_KEY_EVENT,
|
SIGNAL_KEY_EVENT,
|
||||||
SIGNAL_MOUSE_EVENT,
|
SIGNAL_MOUSE_EVENT,
|
||||||
|
SIGNAL_PRESENT,
|
||||||
SIGNAL_LAST
|
SIGNAL_LAST
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -163,6 +165,11 @@ gst_d3d11_window_class_init (GstD3D11WindowClass * klass)
|
||||||
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
(GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
|
||||||
G_PARAM_STATIC_STRINGS)));
|
G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_EMIT_PRESENT,
|
||||||
|
g_param_spec_boolean ("emit-present", "Emit Present",
|
||||||
|
"Emit present signal", DEFAULT_EMIT_PRESENT,
|
||||||
|
(GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||||
|
|
||||||
d3d11_window_signals[SIGNAL_KEY_EVENT] =
|
d3d11_window_signals[SIGNAL_KEY_EVENT] =
|
||||||
g_signal_new ("key-event", G_TYPE_FROM_CLASS (klass),
|
g_signal_new ("key-event", G_TYPE_FROM_CLASS (klass),
|
||||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||||
|
@ -172,6 +179,11 @@ gst_d3d11_window_class_init (GstD3D11WindowClass * klass)
|
||||||
g_signal_new ("mouse-event", G_TYPE_FROM_CLASS (klass),
|
g_signal_new ("mouse-event", G_TYPE_FROM_CLASS (klass),
|
||||||
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
|
||||||
G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
|
G_TYPE_NONE, 4, G_TYPE_STRING, G_TYPE_INT, G_TYPE_DOUBLE, G_TYPE_DOUBLE);
|
||||||
|
|
||||||
|
d3d11_window_signals[SIGNAL_PRESENT] =
|
||||||
|
g_signal_new ("present", G_TYPE_FROM_CLASS (klass),
|
||||||
|
G_SIGNAL_RUN_LAST, 0, nullptr, nullptr, nullptr,
|
||||||
|
G_TYPE_NONE, 2, GST_TYPE_D3D11_DEVICE, G_TYPE_POINTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -181,7 +193,7 @@ gst_d3d11_window_init (GstD3D11Window * self)
|
||||||
self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS;
|
self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS;
|
||||||
self->fullscreen_toggle_mode = GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE;
|
self->fullscreen_toggle_mode = GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE;
|
||||||
self->fullscreen = DEFAULT_FULLSCREEN;
|
self->fullscreen = DEFAULT_FULLSCREEN;
|
||||||
self->render_stats = DEFAULT_RENDER_STATS;
|
self->emit_present = DEFAULT_EMIT_PRESENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -219,6 +231,9 @@ gst_d3d11_window_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_WINDOW_HANDLE:
|
case PROP_WINDOW_HANDLE:
|
||||||
self->external_handle = (guintptr) g_value_get_pointer (value);
|
self->external_handle = (guintptr) g_value_get_pointer (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_EMIT_PRESENT:
|
||||||
|
self->emit_present = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -244,6 +259,9 @@ gst_d3d11_window_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_FULLSCREEN:
|
case PROP_FULLSCREEN:
|
||||||
g_value_set_boolean (value, self->fullscreen);
|
g_value_set_boolean (value, self->fullscreen);
|
||||||
break;
|
break;
|
||||||
|
case PROP_EMIT_PRESENT:
|
||||||
|
g_value_set_boolean (value, self->emit_present);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -844,6 +862,17 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
|
||||||
return GST_FLOW_ERROR;
|
return GST_FLOW_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We use flip mode swapchain and will not redraw borders.
|
||||||
|
* So backbuffer should be cleared manually in order to remove artifact of
|
||||||
|
* previous client's rendering on present signal */
|
||||||
|
if (self->emit_present) {
|
||||||
|
const FLOAT clear_color[] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||||
|
ID3D11DeviceContext *context =
|
||||||
|
gst_d3d11_device_get_device_context_handle (self->device);
|
||||||
|
|
||||||
|
context->ClearRenderTargetView (rtv, clear_color);
|
||||||
|
}
|
||||||
|
|
||||||
crop_meta = gst_buffer_get_video_crop_meta (buffer);
|
crop_meta = gst_buffer_get_video_crop_meta (buffer);
|
||||||
if (crop_meta) {
|
if (crop_meta) {
|
||||||
input_rect.left = crop_meta->x;
|
input_rect.left = crop_meta->x;
|
||||||
|
@ -895,8 +924,13 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer,
|
||||||
if (self->allow_tearing && self->fullscreen)
|
if (self->allow_tearing && self->fullscreen)
|
||||||
present_flags |= DXGI_PRESENT_ALLOW_TEARING;
|
present_flags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||||
|
|
||||||
if (klass->present)
|
if (klass->present) {
|
||||||
|
if (self->emit_present) {
|
||||||
|
g_signal_emit (self, d3d11_window_signals[SIGNAL_PRESENT], 0,
|
||||||
|
self->device, rtv, nullptr);
|
||||||
|
}
|
||||||
ret = klass->present (self, present_flags);
|
ret = klass->present (self, present_flags);
|
||||||
|
}
|
||||||
|
|
||||||
self->first_present = FALSE;
|
self->first_present = FALSE;
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ struct _GstD3D11Window
|
||||||
GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode;
|
GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode;
|
||||||
gboolean requested_fullscreen;
|
gboolean requested_fullscreen;
|
||||||
gboolean fullscreen;
|
gboolean fullscreen;
|
||||||
gboolean render_stats;
|
gboolean emit_present;
|
||||||
|
|
||||||
GstVideoInfo info;
|
GstVideoInfo info;
|
||||||
GstVideoInfo render_info;
|
GstVideoInfo render_info;
|
||||||
|
|
|
@ -452,7 +452,7 @@ gst_d3d11_window_core_window_present (GstD3D11Window * window,
|
||||||
IDXGISwapChain1 *swap_chain = (IDXGISwapChain1 *) window->swap_chain;
|
IDXGISwapChain1 *swap_chain = (IDXGISwapChain1 *) window->swap_chain;
|
||||||
|
|
||||||
/* the first present should not specify dirty-rect */
|
/* the first present should not specify dirty-rect */
|
||||||
if (!window->first_present) {
|
if (!window->first_present && !window->emit_present) {
|
||||||
present_params.DirtyRectsCount = 1;
|
present_params.DirtyRectsCount = 1;
|
||||||
present_params.pDirtyRects = &window->render_rect;
|
present_params.pDirtyRects = &window->render_rect;
|
||||||
}
|
}
|
||||||
|
|
|
@ -442,7 +442,7 @@ gst_d3d11_window_swap_chain_panel_present (GstD3D11Window * window,
|
||||||
IDXGISwapChain1 *swap_chain = (IDXGISwapChain1 *) window->swap_chain;
|
IDXGISwapChain1 *swap_chain = (IDXGISwapChain1 *) window->swap_chain;
|
||||||
|
|
||||||
/* the first present should not specify dirty-rect */
|
/* the first present should not specify dirty-rect */
|
||||||
if (!window->first_present) {
|
if (!window->first_present && !window->emit_present) {
|
||||||
present_params.DirtyRectsCount = 1;
|
present_params.DirtyRectsCount = 1;
|
||||||
present_params.pDirtyRects = &window->render_rect;
|
present_params.pDirtyRects = &window->render_rect;
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,6 @@ struct _GstD3D11WindowWin32
|
||||||
GstD3D11WindowWin32OverlayState overlay_state;
|
GstD3D11WindowWin32OverlayState overlay_state;
|
||||||
|
|
||||||
HDC device_handle;
|
HDC device_handle;
|
||||||
gboolean first_present;
|
|
||||||
gboolean have_swapchain1;
|
gboolean have_swapchain1;
|
||||||
|
|
||||||
/* atomic */
|
/* atomic */
|
||||||
|
@ -1067,7 +1066,7 @@ gst_d3d11_window_win32_present (GstD3D11Window * window, guint present_flags)
|
||||||
DXGI_PRESENT_PARAMETERS present_params = { 0, };
|
DXGI_PRESENT_PARAMETERS present_params = { 0, };
|
||||||
|
|
||||||
/* the first present should not specify dirty-rect */
|
/* the first present should not specify dirty-rect */
|
||||||
if (!window->first_present) {
|
if (!window->first_present && !window->emit_present) {
|
||||||
present_params.DirtyRectsCount = 1;
|
present_params.DirtyRectsCount = 1;
|
||||||
present_params.pDirtyRects = &window->render_rect;
|
present_params.pDirtyRects = &window->render_rect;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue