diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device-private.h b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device-private.h index 832702390a..19f3b173bb 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device-private.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device-private.h @@ -64,8 +64,8 @@ GST_D3D11_API HRESULT gst_d3d11_device_get_rasterizer_msaa (GstD3D11Device * device, ID3D11RasterizerState ** rasterizer); -/* Used internally by gstd3d11utils.cpp */ -void gst_d3d11_device_mark_removed (GstD3D11Device * device, HRESULT reason); +GST_D3D11_API +void gst_d3d11_device_check_device_removed (GstD3D11Device * device); G_END_DECLS diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.cpp index ab8faff0bd..cbed7b3ad0 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.cpp @@ -96,24 +96,31 @@ enum PROP_DESCRIPTION, PROP_CREATE_FLAGS, PROP_ADAPTER_LUID, + PROP_DEVICE_REMOVED_REASON, }; +static GParamSpec *pspec_removed_reason = nullptr; + #define DEFAULT_ADAPTER 0 #define DEFAULT_CREATE_FLAGS 0 -enum -{ - /* signals */ - SIGNAL_DEVICE_REMOVED, - LAST_SIGNAL -}; - -static guint gst_d3d11_device_signals[LAST_SIGNAL] = { 0, }; - - /* *INDENT-OFF* */ struct _GstD3D11DevicePrivate { + _GstD3D11DevicePrivate () + { + device_removed_event = + CreateEventEx (nullptr, nullptr, 0, EVENT_ALL_ACCESS); + cancallable = + CreateEventEx (nullptr, nullptr, 0, EVENT_ALL_ACCESS); + } + + ~_GstD3D11DevicePrivate () + { + CloseHandle (device_removed_event); + CloseHandle (cancallable); + } + guint adapter = 0; guint device_id = 0; guint vendor_id = 0; @@ -123,6 +130,7 @@ struct _GstD3D11DevicePrivate gint64 adapter_luid = 0; ID3D11Device *device = nullptr; + ID3D11Device4 *device4 = nullptr; ID3D11Device5 *device5 = nullptr; ID3D11DeviceContext *device_context = nullptr; ID3D11DeviceContext4 *device_context4 = nullptr; @@ -157,7 +165,11 @@ struct _GstD3D11DevicePrivate IDXGIInfoQueue *dxgi_info_queue = nullptr; #endif - gboolean device_removed = FALSE; + DWORD device_removed_cookie = 0; + GThread *device_removed_monitor_thread = nullptr; + HANDLE device_removed_event; + HANDLE cancallable; + std::atomic removed_reason = { S_OK }; }; /* *INDENT-ON* */ @@ -430,18 +442,18 @@ gst_d3d11_device_class_init (GstD3D11DeviceClass * klass) G_MININT64, G_MAXINT64, 0, readable_flags)); /** - * GstD3D11Device::device-removed: - * @device: the #d3d11device + * GstD3D11Device:device-removed-reason: * - * Emitted when the D3D11Device gets suspended by the DirectX (error - * DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET have been returned - * after one of the DirectX operations). + * Device removed reason HRESULT code * * Since: 1.26 */ - gst_d3d11_device_signals[SIGNAL_DEVICE_REMOVED] = - g_signal_new ("device-removed", G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); + pspec_removed_reason = + g_param_spec_int ("device-removed-reason", "Device Removed Reason", + "HRESULT code returned from ID3D11Device::GetDeviceRemovedReason", + G_MININT32, G_MAXINT32, 0, readable_flags); + g_object_class_install_property (gobject_class, PROP_DEVICE_REMOVED_REASON, + pspec_removed_reason); gst_d3d11_memory_init_once (); } @@ -700,6 +712,9 @@ gst_d3d11_device_get_property (GObject * object, guint prop_id, case PROP_ADAPTER_LUID: g_value_set_int64 (value, priv->adapter_luid); break; + case PROP_DEVICE_REMOVED_REASON: + g_value_set_int (value, priv->removed_reason); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -741,7 +756,14 @@ gst_d3d11_device_dispose (GObject * object) GST_LOG_OBJECT (self, "dispose"); + if (priv->device4 && priv->device_removed_monitor_thread) { + priv->device4->UnregisterDeviceRemoved (priv->device_removed_cookie); + SetEvent (priv->cancallable); + g_clear_pointer (&priv->device_removed_monitor_thread, g_thread_join); + } + AcquireSRWLockExclusive (&_device_creation_rwlock); + priv->ps_cache.clear (); priv->vs_cache.clear (); priv->sampler_cache.clear (); @@ -749,6 +771,7 @@ gst_d3d11_device_dispose (GObject * object) GST_D3D11_CLEAR_COM (priv->rs); GST_D3D11_CLEAR_COM (priv->rs_msaa); GST_D3D11_CLEAR_COM (priv->device5); + GST_D3D11_CLEAR_COM (priv->device4); GST_D3D11_CLEAR_COM (priv->device_context4); GST_D3D11_CLEAR_COM (priv->video_device); GST_D3D11_CLEAR_COM (priv->video_context); @@ -977,12 +1000,47 @@ gst_d3d11_device_setup_debug_layer (GstD3D11Device * self) #endif } +void +gst_d3d11_device_check_device_removed (GstD3D11Device * self) +{ + auto priv = self->priv; + auto removed_reason = priv->device->GetDeviceRemovedReason (); + + if (removed_reason == S_OK) + return; + + HRESULT expected = S_OK; + if (std::atomic_compare_exchange_strong (&priv->removed_reason, + &expected, removed_reason)) { + auto error_text = g_win32_error_message ((guint) priv->removed_reason); + GST_ERROR_OBJECT (self, "DeviceRemovedReason: 0x%x, %s", + (guint) priv->removed_reason, GST_STR_NULL (error_text)); + g_free (error_text); + + g_object_notify_by_pspec (G_OBJECT (self), pspec_removed_reason); + } +} + +static gpointer +gst_d3d11_device_removed_monitor_thread (GstD3D11Device * self) +{ + auto priv = self->priv; + HANDLE waitables[] = { priv->device_removed_event, priv->cancallable }; + + auto ret = WaitForMultipleObjects (2, waitables, FALSE, INFINITE); + if (ret == WAIT_OBJECT_0) + gst_d3d11_device_check_device_removed (self); + + return nullptr; +} + static GstD3D11Device * gst_d3d11_device_new_internal (const GstD3D11DeviceConstructData * data) { ComPtr < IDXGIAdapter1 > adapter; ComPtr < IDXGIFactory1 > factory; ComPtr < ID3D11Device > device; + ComPtr < ID3D11Device4 > device4; ComPtr < ID3D11Device5 > device5; ComPtr < ID3D11DeviceContext > device_context; ComPtr < ID3D11DeviceContext4 > device_context4; @@ -1115,6 +1173,18 @@ gst_d3d11_device_new_internal (const GstD3D11DeviceConstructData * data) priv = self->priv; + hr = device.As (&device4); + if (SUCCEEDED (hr)) { + hr = device4->RegisterDeviceRemovedEvent (priv->device_removed_event, + &priv->device_removed_cookie); + if (SUCCEEDED (hr)) { + priv->device4 = device4.Detach (); + priv->device_removed_monitor_thread = + g_thread_new ("d3d11-removed-monitor", + (GThreadFunc) gst_d3d11_device_removed_monitor_thread, self); + } + } + hr = device.As (&device5); if (SUCCEEDED (hr)) hr = device_context.As (&device_context4); @@ -1430,18 +1500,6 @@ gst_d3d11_device_get_format (GstD3D11Device * device, GstVideoFormat format, return TRUE; } -void -gst_d3d11_device_mark_removed (GstD3D11Device * device, HRESULT reason) -{ - g_return_if_fail (GST_IS_D3D11_DEVICE (device)); - - if (!device->priv->device_removed) { - g_signal_emit (device, gst_d3d11_device_signals[SIGNAL_DEVICE_REMOVED], 0, - reason); - device->priv->device_removed = TRUE; - } -} - GST_DEFINE_MINI_OBJECT_TYPE (GstD3D11Fence, gst_d3d11_fence); struct _GstD3D11FencePrivate diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.cpp b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.cpp index 03cf89693d..e9239c1fdd 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.cpp @@ -551,26 +551,6 @@ gst_d3d11_luid_to_int64 (const LUID * luid) return val.QuadPart; } -#ifndef GST_DISABLE_GST_DEBUG -static void -gst_d3d11_log_gpu_remove_reason (HRESULT hr, GstD3D11Device * device, - GstDebugCategory * cat, const gchar * file, const gchar * function, - gint line) -{ - gchar *error_text = g_win32_error_message ((guint) hr); - - gst_debug_log (cat, GST_LEVEL_ERROR, file, function, line, - NULL, "DeviceRemovedReason: 0x%x, %s", (guint) hr, - GST_STR_NULL (error_text)); - if (hr != DXGI_ERROR_DEVICE_REMOVED) - g_critical ("D3D11Device have been removed. Reason (0x%x): %s", - (guint) hr, GST_STR_NULL (error_text)); - g_free (error_text); - - gst_d3d11_device_log_live_objects (device, file, function, line); -} -#endif - /** * _gst_d3d11_result: * @result: HRESULT D3D11 API return code @@ -591,11 +571,14 @@ _gst_d3d11_result (HRESULT hr, GstD3D11Device * device, GstDebugCategory * cat, const gchar * file, const gchar * function, gint line) { #ifndef GST_DISABLE_GST_DEBUG - gboolean ret = TRUE; - +#if (HAVE_D3D11SDKLAYERS_H || HAVE_DXGIDEBUG_H) + if (device) { + gst_d3d11_device_d3d11_debug (device, file, function, line); + gst_d3d11_device_dxgi_debug (device, file, function, line); + } +#endif if (FAILED (hr)) { gchar *error_text = NULL; - error_text = g_win32_error_message ((guint) hr); /* g_win32_error_message() doesn't cover all HERESULT return code, * so it could be empty string, or null if there was an error @@ -604,29 +587,16 @@ _gst_d3d11_result (HRESULT hr, GstD3D11Device * device, GstDebugCategory * cat, NULL, "D3D11 call failed: 0x%x, %s", (guint) hr, GST_STR_NULL (error_text)); g_free (error_text); - - if (device) { - ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device); - hr = device_handle->GetDeviceRemovedReason (); - if (hr != S_OK) { - gst_d3d11_log_gpu_remove_reason (hr, device, cat, file, function, line); - gst_d3d11_device_mark_removed (device, hr); - } - } - - ret = FALSE; - } -#if (HAVE_D3D11SDKLAYERS_H || HAVE_DXGIDEBUG_H) - if (device) { - gst_d3d11_device_d3d11_debug (device, file, function, line); - gst_d3d11_device_dxgi_debug (device, file, function, line); } #endif - return ret; -#else - return SUCCEEDED (hr); -#endif + if (SUCCEEDED (hr)) + return TRUE; + + if (device) + gst_d3d11_device_check_device_removed (device); + + return FALSE; } /**