d3d11device: Add device-removed-reason property

In addition to device removed status monitoring in gst_d3d11_result()
method, if ID3D11Device4 interface is available,
an event handle will be used for device removed status update.
And "device-removed" signal is removed since applications can monitor
the device removed status via gobject notify

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6699>
This commit is contained in:
Seungha Yang 2024-04-20 21:37:39 +09:00 committed by GStreamer Marge Bot
parent b12b04eeef
commit 40f7d7f1f7
3 changed files with 104 additions and 76 deletions

View file

@ -64,8 +64,8 @@ GST_D3D11_API
HRESULT gst_d3d11_device_get_rasterizer_msaa (GstD3D11Device * device, HRESULT gst_d3d11_device_get_rasterizer_msaa (GstD3D11Device * device,
ID3D11RasterizerState ** rasterizer); ID3D11RasterizerState ** rasterizer);
/* Used internally by gstd3d11utils.cpp */ GST_D3D11_API
void gst_d3d11_device_mark_removed (GstD3D11Device * device, HRESULT reason); void gst_d3d11_device_check_device_removed (GstD3D11Device * device);
G_END_DECLS G_END_DECLS

View file

@ -96,24 +96,31 @@ enum
PROP_DESCRIPTION, PROP_DESCRIPTION,
PROP_CREATE_FLAGS, PROP_CREATE_FLAGS,
PROP_ADAPTER_LUID, PROP_ADAPTER_LUID,
PROP_DEVICE_REMOVED_REASON,
}; };
static GParamSpec *pspec_removed_reason = nullptr;
#define DEFAULT_ADAPTER 0 #define DEFAULT_ADAPTER 0
#define DEFAULT_CREATE_FLAGS 0 #define DEFAULT_CREATE_FLAGS 0
enum
{
/* signals */
SIGNAL_DEVICE_REMOVED,
LAST_SIGNAL
};
static guint gst_d3d11_device_signals[LAST_SIGNAL] = { 0, };
/* *INDENT-OFF* */ /* *INDENT-OFF* */
struct _GstD3D11DevicePrivate 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 adapter = 0;
guint device_id = 0; guint device_id = 0;
guint vendor_id = 0; guint vendor_id = 0;
@ -123,6 +130,7 @@ struct _GstD3D11DevicePrivate
gint64 adapter_luid = 0; gint64 adapter_luid = 0;
ID3D11Device *device = nullptr; ID3D11Device *device = nullptr;
ID3D11Device4 *device4 = nullptr;
ID3D11Device5 *device5 = nullptr; ID3D11Device5 *device5 = nullptr;
ID3D11DeviceContext *device_context = nullptr; ID3D11DeviceContext *device_context = nullptr;
ID3D11DeviceContext4 *device_context4 = nullptr; ID3D11DeviceContext4 *device_context4 = nullptr;
@ -157,7 +165,11 @@ struct _GstD3D11DevicePrivate
IDXGIInfoQueue *dxgi_info_queue = nullptr; IDXGIInfoQueue *dxgi_info_queue = nullptr;
#endif #endif
gboolean device_removed = FALSE; DWORD device_removed_cookie = 0;
GThread *device_removed_monitor_thread = nullptr;
HANDLE device_removed_event;
HANDLE cancallable;
std::atomic<HRESULT> removed_reason = { S_OK };
}; };
/* *INDENT-ON* */ /* *INDENT-ON* */
@ -430,18 +442,18 @@ gst_d3d11_device_class_init (GstD3D11DeviceClass * klass)
G_MININT64, G_MAXINT64, 0, readable_flags)); G_MININT64, G_MAXINT64, 0, readable_flags));
/** /**
* GstD3D11Device::device-removed: * GstD3D11Device:device-removed-reason:
* @device: the #d3d11device
* *
* Emitted when the D3D11Device gets suspended by the DirectX (error * Device removed reason HRESULT code
* DXGI_ERROR_DEVICE_REMOVED or DXGI_ERROR_DEVICE_RESET have been returned
* after one of the DirectX operations).
* *
* Since: 1.26 * Since: 1.26
*/ */
gst_d3d11_device_signals[SIGNAL_DEVICE_REMOVED] = pspec_removed_reason =
g_signal_new ("device-removed", G_TYPE_FROM_CLASS (klass), g_param_spec_int ("device-removed-reason", "Device Removed Reason",
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); "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 (); gst_d3d11_memory_init_once ();
} }
@ -700,6 +712,9 @@ gst_d3d11_device_get_property (GObject * object, guint prop_id,
case PROP_ADAPTER_LUID: case PROP_ADAPTER_LUID:
g_value_set_int64 (value, priv->adapter_luid); g_value_set_int64 (value, priv->adapter_luid);
break; break;
case PROP_DEVICE_REMOVED_REASON:
g_value_set_int (value, priv->removed_reason);
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;
@ -741,7 +756,14 @@ gst_d3d11_device_dispose (GObject * object)
GST_LOG_OBJECT (self, "dispose"); 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); AcquireSRWLockExclusive (&_device_creation_rwlock);
priv->ps_cache.clear (); priv->ps_cache.clear ();
priv->vs_cache.clear (); priv->vs_cache.clear ();
priv->sampler_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);
GST_D3D11_CLEAR_COM (priv->rs_msaa); GST_D3D11_CLEAR_COM (priv->rs_msaa);
GST_D3D11_CLEAR_COM (priv->device5); GST_D3D11_CLEAR_COM (priv->device5);
GST_D3D11_CLEAR_COM (priv->device4);
GST_D3D11_CLEAR_COM (priv->device_context4); GST_D3D11_CLEAR_COM (priv->device_context4);
GST_D3D11_CLEAR_COM (priv->video_device); GST_D3D11_CLEAR_COM (priv->video_device);
GST_D3D11_CLEAR_COM (priv->video_context); GST_D3D11_CLEAR_COM (priv->video_context);
@ -977,12 +1000,47 @@ gst_d3d11_device_setup_debug_layer (GstD3D11Device * self)
#endif #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 * static GstD3D11Device *
gst_d3d11_device_new_internal (const GstD3D11DeviceConstructData * data) gst_d3d11_device_new_internal (const GstD3D11DeviceConstructData * data)
{ {
ComPtr < IDXGIAdapter1 > adapter; ComPtr < IDXGIAdapter1 > adapter;
ComPtr < IDXGIFactory1 > factory; ComPtr < IDXGIFactory1 > factory;
ComPtr < ID3D11Device > device; ComPtr < ID3D11Device > device;
ComPtr < ID3D11Device4 > device4;
ComPtr < ID3D11Device5 > device5; ComPtr < ID3D11Device5 > device5;
ComPtr < ID3D11DeviceContext > device_context; ComPtr < ID3D11DeviceContext > device_context;
ComPtr < ID3D11DeviceContext4 > device_context4; ComPtr < ID3D11DeviceContext4 > device_context4;
@ -1115,6 +1173,18 @@ gst_d3d11_device_new_internal (const GstD3D11DeviceConstructData * data)
priv = self->priv; 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); hr = device.As (&device5);
if (SUCCEEDED (hr)) if (SUCCEEDED (hr))
hr = device_context.As (&device_context4); hr = device_context.As (&device_context4);
@ -1430,18 +1500,6 @@ gst_d3d11_device_get_format (GstD3D11Device * device, GstVideoFormat format,
return TRUE; 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); GST_DEFINE_MINI_OBJECT_TYPE (GstD3D11Fence, gst_d3d11_fence);
struct _GstD3D11FencePrivate struct _GstD3D11FencePrivate

View file

@ -551,26 +551,6 @@ gst_d3d11_luid_to_int64 (const LUID * luid)
return val.QuadPart; 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: * _gst_d3d11_result:
* @result: HRESULT D3D11 API return code * @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) const gchar * file, const gchar * function, gint line)
{ {
#ifndef GST_DISABLE_GST_DEBUG #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)) { if (FAILED (hr)) {
gchar *error_text = NULL; gchar *error_text = NULL;
error_text = g_win32_error_message ((guint) hr); error_text = g_win32_error_message ((guint) hr);
/* g_win32_error_message() doesn't cover all HERESULT return code, /* g_win32_error_message() doesn't cover all HERESULT return code,
* so it could be empty string, or null if there was an error * 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, NULL, "D3D11 call failed: 0x%x, %s", (guint) hr,
GST_STR_NULL (error_text)); GST_STR_NULL (error_text));
g_free (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 #endif
return ret; if (SUCCEEDED (hr))
#else return TRUE;
return SUCCEEDED (hr);
#endif if (device)
gst_d3d11_device_check_device_removed (device);
return FALSE;
} }
/** /**