diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp index ff0695f073..7140b30ac0 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11videosink.cpp @@ -78,6 +78,7 @@ enum { /* signals */ SIGNAL_BEGIN_DRAW, + SIGNAL_PRESENT, /* actions */ 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_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 = 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); } +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 gst_d3d11_video_sink_start (GstBaseSink * sink) { @@ -784,6 +818,7 @@ static gboolean gst_d3d11_video_sink_prepare_window (GstD3D11VideoSink * self) { GstD3D11WindowNativeType window_type = GST_D3D11_WINDOW_NATIVE_TYPE_HWND; + gboolean emit_present = FALSE; if (self->window) return TRUE; @@ -847,11 +882,18 @@ done: 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, "force-aspect-ratio", self->force_aspect_ratio, "fullscreen-toggle-mode", self->fullscreen_toggle_mode, "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); @@ -859,6 +901,8 @@ done: G_CALLBACK (gst_d3d11_video_sink_key_event), self); g_signal_connect (self->window, "mouse-event", 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; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp index 58063d3704..95276981e4 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp @@ -54,18 +54,20 @@ enum PROP_FULLSCREEN, PROP_WINDOW_HANDLE, PROP_RENDER_STATS, + PROP_EMIT_PRESENT, }; #define DEFAULT_ENABLE_NAVIGATION_EVENTS TRUE #define DEFAULT_FORCE_ASPECT_RATIO TRUE #define DEFAULT_FULLSCREEN_TOGGLE_MODE GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE #define DEFAULT_FULLSCREEN FALSE -#define DEFAULT_RENDER_STATS FALSE +#define DEFAULT_EMIT_PRESENT FALSE enum { SIGNAL_KEY_EVENT, SIGNAL_MOUSE_EVENT, + SIGNAL_PRESENT, SIGNAL_LAST }; @@ -163,6 +165,11 @@ gst_d3d11_window_class_init (GstD3D11WindowClass * klass) (GParamFlags) (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | 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] = g_signal_new ("key-event", G_TYPE_FROM_CLASS (klass), 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_RUN_LAST, 0, NULL, NULL, NULL, 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 @@ -181,7 +193,7 @@ gst_d3d11_window_init (GstD3D11Window * self) self->enable_navigation_events = DEFAULT_ENABLE_NAVIGATION_EVENTS; self->fullscreen_toggle_mode = GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_NONE; self->fullscreen = DEFAULT_FULLSCREEN; - self->render_stats = DEFAULT_RENDER_STATS; + self->emit_present = DEFAULT_EMIT_PRESENT; } static void @@ -219,6 +231,9 @@ gst_d3d11_window_set_property (GObject * object, guint prop_id, case PROP_WINDOW_HANDLE: self->external_handle = (guintptr) g_value_get_pointer (value); break; + case PROP_EMIT_PRESENT: + self->emit_present = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -244,6 +259,9 @@ gst_d3d11_window_get_property (GObject * object, guint prop_id, case PROP_FULLSCREEN: g_value_set_boolean (value, self->fullscreen); break; + case PROP_EMIT_PRESENT: + g_value_set_boolean (value, self->emit_present); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -844,6 +862,17 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer, 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); if (crop_meta) { input_rect.left = crop_meta->x; @@ -895,8 +924,13 @@ gst_d3d111_window_present (GstD3D11Window * self, GstBuffer * buffer, if (self->allow_tearing && self->fullscreen) 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); + } self->first_present = FALSE; diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h index eb787aaaa9..f7d0213c99 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.h @@ -86,7 +86,7 @@ struct _GstD3D11Window GstD3D11WindowFullscreenToggleMode fullscreen_toggle_mode; gboolean requested_fullscreen; gboolean fullscreen; - gboolean render_stats; + gboolean emit_present; GstVideoInfo info; GstVideoInfo render_info; diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_corewindow.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_corewindow.cpp index 2da1433a68..2ff60abfe7 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_corewindow.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_corewindow.cpp @@ -452,7 +452,7 @@ gst_d3d11_window_core_window_present (GstD3D11Window * window, IDXGISwapChain1 *swap_chain = (IDXGISwapChain1 *) window->swap_chain; /* 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.pDirtyRects = &window->render_rect; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_swapchainpanel.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_swapchainpanel.cpp index 26ad2eb7a9..4574aab8d7 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_swapchainpanel.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_swapchainpanel.cpp @@ -442,7 +442,7 @@ gst_d3d11_window_swap_chain_panel_present (GstD3D11Window * window, IDXGISwapChain1 *swap_chain = (IDXGISwapChain1 *) window->swap_chain; /* 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.pDirtyRects = &window->render_rect; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp index 58437780a8..6ef2623406 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window_win32.cpp @@ -80,7 +80,6 @@ struct _GstD3D11WindowWin32 GstD3D11WindowWin32OverlayState overlay_state; HDC device_handle; - gboolean first_present; gboolean have_swapchain1; /* atomic */ @@ -1067,7 +1066,7 @@ gst_d3d11_window_win32_present (GstD3D11Window * window, guint present_flags) DXGI_PRESENT_PARAMETERS present_params = { 0, }; /* 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.pDirtyRects = &window->render_rect; }