From 5ac7a21ef05f69ea173c7450626c1ff64bfa24ed Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Fri, 8 Oct 2021 19:41:22 +0900 Subject: [PATCH] d3d11: d3d11device: Add gst_d3d11_device_new_{for_adapter_luid,wrapped} * gst_d3d11_device_new_for_adapter_luid() Used for creating D3D11 device for a DXGI adapter (i.e., GPU) corresponding to a LUID (Locally Unique Identifier). This method can be useful for interop with other APIs such as Direct3D12, MediaFoundation, CUDA, etc. * gst_d3d11_device_new_wrapped() Allows creating a new GstD3D11Device object by using already configured ID3D11Device. This is conceptually equivalent to gst_gl_context_new_wrapped() Part-of: --- .../gst-libs/gst/d3d11/gstd3d11device.cpp | 663 +++++++++++------- .../gst-libs/gst/d3d11/gstd3d11device.h | 9 +- .../gst-libs/gst/d3d11/gstd3d11utils.cpp | 23 + .../gst-libs/gst/d3d11/gstd3d11utils.h | 3 + .../tests/check/libs/d3d11device.cpp | 208 ++++++ .../gst-plugins-bad/tests/check/meson.build | 15 +- 6 files changed, 668 insertions(+), 253 deletions(-) create mode 100644 subprojects/gst-plugins-bad/tests/check/libs/d3d11device.cpp 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 79cdaa82f0..712e829556 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.cpp @@ -130,25 +130,27 @@ struct _GstD3D11DevicePrivate }; static void -do_debug_init (void) +debug_init_once (void) { - GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug, - "d3d11device", 0, "d3d11 device object"); + static gsize init_once = 0; + + if (g_once_init_enter (&init_once)) { + GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug, + "d3d11device", 0, "d3d11 device object"); #if defined(HAVE_D3D11SDKLAYERS_H) || defined(HAVE_DXGIDEBUG_H) - GST_DEBUG_CATEGORY_INIT (gst_d3d11_debug_layer_debug, - "d3d11debuglayer", 0, "native d3d11 and dxgi debug"); + GST_DEBUG_CATEGORY_INIT (gst_d3d11_debug_layer_debug, + "d3d11debuglayer", 0, "native d3d11 and dxgi debug"); #endif + g_once_init_leave (&init_once, 1); + } } #define gst_d3d11_device_parent_class parent_class G_DEFINE_TYPE_WITH_CODE (GstD3D11Device, gst_d3d11_device, GST_TYPE_OBJECT, - G_ADD_PRIVATE (GstD3D11Device); do_debug_init ()); + G_ADD_PRIVATE (GstD3D11Device); debug_init_once ()); -static void gst_d3d11_device_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec); static void gst_d3d11_device_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_d3d11_device_constructed (GObject * object); static void gst_d3d11_device_dispose (GObject * object); static void gst_d3d11_device_finalize (GObject * object); @@ -363,22 +365,17 @@ static void gst_d3d11_device_class_init (GstD3D11DeviceClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - GParamFlags rw_construct_only_flags = - (GParamFlags) (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); GParamFlags readable_flags = (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - gobject_class->set_property = gst_d3d11_device_set_property; gobject_class->get_property = gst_d3d11_device_get_property; - gobject_class->constructed = gst_d3d11_device_constructed; gobject_class->dispose = gst_d3d11_device_dispose; gobject_class->finalize = gst_d3d11_device_finalize; g_object_class_install_property (gobject_class, PROP_ADAPTER, g_param_spec_uint ("adapter", "Adapter", "DXGI Adapter index for creating device", - 0, G_MAXUINT32, DEFAULT_ADAPTER, rw_construct_only_flags)); + 0, G_MAXUINT32, DEFAULT_ADAPTER, readable_flags)); g_object_class_install_property (gobject_class, PROP_DEVICE_ID, g_param_spec_uint ("device-id", "Device Id", @@ -396,15 +393,10 @@ gst_d3d11_device_class_init (GstD3D11DeviceClass * klass) g_param_spec_string ("description", "Description", "Human readable device description", NULL, readable_flags)); - g_object_class_install_property (gobject_class, PROP_CREATE_FLAGS, - g_param_spec_uint ("create-flags", "Create flags", - "D3D11_CREATE_DEVICE_FLAG flags used for D3D11CreateDevice", - 0, G_MAXUINT32, DEFAULT_CREATE_FLAGS, rw_construct_only_flags)); - g_object_class_install_property (gobject_class, PROP_ADAPTER_LUID, g_param_spec_int64 ("adapter-luid", "Adapter LUID", "DXGI Adapter LUID (Locally Unique Identifier) of created device", - 0, G_MAXINT64, 0, readable_flags)); + G_MININT64, G_MAXINT64, 0, readable_flags)); gst_d3d11_memory_init_once (); } @@ -743,216 +735,6 @@ gst_d3d11_device_setup_format_table (GstD3D11Device * self) g_assert (n_formats == GST_D3D11_N_FORMATS); } -static void -gst_d3d11_device_constructed (GObject * object) -{ - GstD3D11Device *self = GST_D3D11_DEVICE (object); - GstD3D11DevicePrivate *priv = self->priv; - ComPtr < IDXGIAdapter1 > adapter; - ComPtr < IDXGIFactory1 > factory; - HRESULT hr; - UINT d3d11_flags = priv->create_flags; - - static const D3D_FEATURE_LEVEL feature_levels[] = { - D3D_FEATURE_LEVEL_11_1, - D3D_FEATURE_LEVEL_11_0, - D3D_FEATURE_LEVEL_10_1, - D3D_FEATURE_LEVEL_10_0, - D3D_FEATURE_LEVEL_9_3, - D3D_FEATURE_LEVEL_9_2, - D3D_FEATURE_LEVEL_9_1 - }; - D3D_FEATURE_LEVEL selected_level; - - GST_DEBUG_OBJECT (self, - "Built with DXGI header version %d", GST_D3D11_DXGI_HEADER_VERSION); - -#if HAVE_DXGIDEBUG_H - if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) > - GST_LEVEL_NONE) { - if (gst_d3d11_device_enable_dxgi_debug ()) { - IDXGIDebug *debug = NULL; - IDXGIInfoQueue *info_queue = NULL; - - GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, - "dxgi debug library was loaded"); - hr = gst_d3d11_device_dxgi_get_device_interface (IID_PPV_ARGS (&debug)); - - if (SUCCEEDED (hr)) { - GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, - "IDXGIDebug interface available"); - priv->dxgi_debug = debug; - - hr = gst_d3d11_device_dxgi_get_device_interface (IID_PPV_ARGS - (&info_queue)); - if (SUCCEEDED (hr)) { - GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, - "IDXGIInfoQueue interface available"); - priv->dxgi_info_queue = info_queue; - } - } - } else { - GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, - "couldn't load dxgi debug library"); - } - } -#endif - - hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory)); - if (!gst_d3d11_result (hr, NULL)) { - GST_ERROR_OBJECT (self, "cannot create dxgi factory, hr: 0x%x", (guint) hr); - goto out; - } - - if (factory->EnumAdapters1 (priv->adapter, &adapter) == DXGI_ERROR_NOT_FOUND) { - GST_DEBUG_OBJECT (self, "No adapter for index %d", priv->adapter); - goto out; - } else { - DXGI_ADAPTER_DESC1 desc; - - hr = adapter->GetDesc1 (&desc); - if (SUCCEEDED (hr)) { - gchar *description = NULL; - gboolean is_hardware = FALSE; - gint64 adapter_luid; - - /* DXGI_ADAPTER_FLAG_SOFTWARE is missing in dxgi.h of mingw */ - if ((desc.Flags & 0x2) != 0x2) { - is_hardware = TRUE; - } - - adapter_luid = (((gint64) desc.AdapterLuid.HighPart) << 32) | - ((gint64) desc.AdapterLuid.LowPart); - description = g_utf16_to_utf8 ((gunichar2 *) desc.Description, - -1, NULL, NULL, NULL); - GST_DEBUG_OBJECT (self, - "adapter index %d: D3D11 device vendor-id: 0x%04x, device-id: 0x%04x, " - "Flags: 0x%x, adapter-luid: %" G_GINT64_FORMAT ", %s", - priv->adapter, desc.VendorId, desc.DeviceId, desc.Flags, adapter_luid, - description); - - priv->vendor_id = desc.VendorId; - priv->device_id = desc.DeviceId; - priv->hardware = is_hardware; - priv->description = description; - priv->adapter_luid = adapter_luid; - } - } - -#if HAVE_D3D11SDKLAYERS_H - if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) > - GST_LEVEL_NONE) { - /* DirectX SDK should be installed on system for this */ - if (gst_d3d11_device_enable_d3d11_debug ()) { - GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, - "d3d11 debug library was loaded"); - d3d11_flags |= D3D11_CREATE_DEVICE_DEBUG; - } else { - GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, - "couldn't load d3d11 debug library"); - } - } -#endif - - hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, - NULL, d3d11_flags, feature_levels, G_N_ELEMENTS (feature_levels), - D3D11_SDK_VERSION, &priv->device, &selected_level, &priv->device_context); - - if (FAILED (hr)) { - /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */ - hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, - NULL, d3d11_flags, &feature_levels[1], - G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &priv->device, - &selected_level, &priv->device_context); - } - - /* if D3D11_CREATE_DEVICE_DEBUG was enabled but couldn't create device, - * try it without the flag again */ - if (FAILED (hr) && (d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) == - D3D11_CREATE_DEVICE_DEBUG) { - GST_WARNING_OBJECT (self, "Couldn't create d3d11 device with debug flag"); - - d3d11_flags &= ~D3D11_CREATE_DEVICE_DEBUG; - - hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, - NULL, d3d11_flags, feature_levels, G_N_ELEMENTS (feature_levels), - D3D11_SDK_VERSION, &priv->device, &selected_level, - &priv->device_context); - - if (FAILED (hr)) { - /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */ - hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, - NULL, d3d11_flags, &feature_levels[1], - G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &priv->device, - &selected_level, &priv->device_context); - } - } - - if (SUCCEEDED (hr)) { - GST_DEBUG_OBJECT (self, "Selected feature level 0x%x", selected_level); - } else { - GST_INFO_OBJECT (self, - "cannot create d3d11 device for adapter index %d with flags 0x%x, " - "hr: 0x%x", priv->adapter, d3d11_flags, (guint) hr); - goto out; - } - - priv->factory = factory.Detach (); - -#if HAVE_D3D11SDKLAYERS_H - if ((d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) == D3D11_CREATE_DEVICE_DEBUG) { - ID3D11Debug *debug; - ID3D11InfoQueue *info_queue; - - hr = priv->device->QueryInterface (IID_PPV_ARGS (&debug)); - - if (SUCCEEDED (hr)) { - GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, - "D3D11Debug interface available"); - priv->d3d11_debug = debug; - - hr = priv->device->QueryInterface (IID_PPV_ARGS (&info_queue)); - if (SUCCEEDED (hr)) { - GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, - "ID3D11InfoQueue interface available"); - priv->d3d11_info_queue = info_queue; - } - } - } -#endif - - /* Update final create flags here, since D3D11_CREATE_DEVICE_DEBUG - * might be added by us */ - priv->create_flags = d3d11_flags; - - gst_d3d11_device_setup_format_table (self); - -out: - G_OBJECT_CLASS (parent_class)->constructed (object); - - return; -} - -static void -gst_d3d11_device_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstD3D11Device *self = GST_D3D11_DEVICE (object); - GstD3D11DevicePrivate *priv = self->priv; - - switch (prop_id) { - case PROP_ADAPTER: - priv->adapter = g_value_get_uint (value); - break; - case PROP_CREATE_FLAGS: - priv->create_flags = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - static void gst_d3d11_device_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) @@ -976,9 +758,6 @@ gst_d3d11_device_get_property (GObject * object, guint prop_id, case PROP_DESCRIPTION: g_value_set_string (value, priv->description); break; - case PROP_CREATE_FLAGS: - g_value_set_uint (value, priv->create_flags); - break; case PROP_ADAPTER_LUID: g_value_set_int64 (value, priv->adapter_luid); break; @@ -1045,36 +824,420 @@ gst_d3d11_device_finalize (GObject * object) G_OBJECT_CLASS (parent_class)->finalize (object); } +typedef enum +{ + DEVICE_CONSTRUCT_FOR_ADAPTER_INDEX, + DEVICE_CONSTRUCT_FOR_ADAPTER_LUID, + DEVICE_CONSTRUCT_WRAPPED, +} GstD3D11DeviceConstructType; + +typedef struct _GstD3D11DeviceConstructData +{ + union + { + guint adapter_index; + gint64 adapter_luid; + ID3D11Device *device; + } data; + GstD3D11DeviceConstructType type; + UINT create_flags; +} GstD3D11DeviceConstructData; + +static HRESULT +_gst_d3d11_device_get_adapter (const GstD3D11DeviceConstructData * data, + IDXGIFactory1 * factory, guint * index, DXGI_ADAPTER_DESC * adapter_desc, + IDXGIAdapter1 ** dxgi_adapter) +{ + HRESULT hr = S_OK; + ComPtr < IDXGIAdapter1 > adapter1; + DXGI_ADAPTER_DESC desc; + + switch (data->type) { + case DEVICE_CONSTRUCT_FOR_ADAPTER_INDEX: + { + hr = factory->EnumAdapters1 (data->data.adapter_index, &adapter1); + if (FAILED (hr)) + return hr; + + hr = adapter1->GetDesc (&desc); + if (FAILED (hr)) + return hr; + + *index = data->data.adapter_index; + *adapter_desc = desc; + *dxgi_adapter = adapter1.Detach (); + + return S_OK; + } + case DEVICE_CONSTRUCT_FOR_ADAPTER_LUID: + { + for (guint i = 0;; i++) { + gint64 luid; + + adapter1 = nullptr; + + hr = factory->EnumAdapters1 (i, &adapter1); + if (FAILED (hr)) + return hr; + + hr = adapter1->GetDesc (&desc); + if (FAILED (hr)) + continue; + + luid = gst_d3d11_luid_to_int64 (&desc.AdapterLuid); + if (luid != data->data.adapter_luid) + continue; + + *index = i; + *adapter_desc = desc; + *dxgi_adapter = adapter1.Detach (); + + return S_OK; + } + + return E_FAIL; + } + case DEVICE_CONSTRUCT_WRAPPED: + { + ComPtr < IDXGIDevice > dxgi_device; + ComPtr < IDXGIAdapter > adapter; + ID3D11Device *device = data->data.device; + guint luid; + + hr = device->QueryInterface (IID_PPV_ARGS (&dxgi_device)); + if (FAILED (hr)) + return hr; + + hr = dxgi_device->GetAdapter (&adapter); + if (FAILED (hr)) + return hr; + + hr = adapter.As (&adapter1); + if (FAILED (hr)) + return hr; + + hr = adapter1->GetDesc (&desc); + if (FAILED (hr)) + return hr; + + luid = gst_d3d11_luid_to_int64 (&desc.AdapterLuid); + + for (guint i = 0;; i++) { + DXGI_ADAPTER_DESC tmp_desc; + ComPtr < IDXGIAdapter1 > tmp; + + hr = factory->EnumAdapters1 (i, &tmp); + if (FAILED (hr)) + return hr; + + hr = tmp->GetDesc (&tmp_desc); + if (FAILED (hr)) + continue; + + if (luid != gst_d3d11_luid_to_int64 (&tmp_desc.AdapterLuid)) + continue; + + *index = i; + *adapter_desc = desc; + *dxgi_adapter = adapter1.Detach (); + + return S_OK; + } + + return E_FAIL; + } + default: + g_assert_not_reached (); + break; + } + + return E_FAIL; +} + +static void +gst_d3d11_device_setup_debug_layer (GstD3D11Device * self) +{ +#if HAVE_DXGIDEBUG_H + if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) > + GST_LEVEL_ERROR) { + GstD3D11DevicePrivate *priv = self->priv; + + if (gst_d3d11_device_enable_dxgi_debug ()) { + IDXGIDebug *debug = nullptr; + IDXGIInfoQueue *info_queue = nullptr; + HRESULT hr; + + GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, + "dxgi debug library was loaded"); + hr = gst_d3d11_device_dxgi_get_device_interface (IID_PPV_ARGS (&debug)); + + if (SUCCEEDED (hr)) { + GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, + "IDXGIDebug interface available"); + priv->dxgi_debug = debug; + + hr = gst_d3d11_device_dxgi_get_device_interface (IID_PPV_ARGS + (&info_queue)); + if (SUCCEEDED (hr)) { + GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, + "IDXGIInfoQueue interface available"); + priv->dxgi_info_queue = info_queue; + } + } + } else { + GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, + "couldn't load dxgi debug library"); + } + } +#endif + +#if HAVE_D3D11SDKLAYERS_H + if ((self->priv->create_flags & D3D11_CREATE_DEVICE_DEBUG) != 0) { + GstD3D11DevicePrivate *priv = self->priv; + ID3D11Debug *debug; + ID3D11InfoQueue *info_queue; + HRESULT hr; + + hr = priv->device->QueryInterface (IID_PPV_ARGS (&debug)); + + if (SUCCEEDED (hr)) { + GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, + "D3D11Debug interface available"); + priv->d3d11_debug = debug; + + hr = priv->device->QueryInterface (IID_PPV_ARGS (&info_queue)); + if (SUCCEEDED (hr)) { + GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self, + "ID3D11InfoQueue interface available"); + priv->d3d11_info_queue = info_queue; + } + } + } +#endif +} + +static GstD3D11Device * +gst_d3d11_device_new_internal (const GstD3D11DeviceConstructData * data) +{ + ComPtr < IDXGIAdapter1 > adapter; + ComPtr < IDXGIFactory1 > factory; + ComPtr < ID3D11Device > device; + ComPtr < ID3D11DeviceContext > device_context; + HRESULT hr; + UINT create_flags; + guint adapter_index = 0; + DXGI_ADAPTER_DESC adapter_desc; + static const D3D_FEATURE_LEVEL feature_levels[] = { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + D3D_FEATURE_LEVEL_9_3, + D3D_FEATURE_LEVEL_9_2, + D3D_FEATURE_LEVEL_9_1 + }; + D3D_FEATURE_LEVEL selected_level; + + debug_init_once (); + + hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory)); + if (!gst_d3d11_result (hr, NULL)) { + GST_ERROR ("cannot create dxgi factory, hr: 0x%x", (guint) hr); + return nullptr; + } + + create_flags = 0; + if (data->type != DEVICE_CONSTRUCT_WRAPPED) { + create_flags = data->create_flags; +#if HAVE_D3D11SDKLAYERS_H + if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) > + GST_LEVEL_ERROR) { + /* DirectX SDK should be installed on system for this */ + if (gst_d3d11_device_enable_d3d11_debug ()) { + GST_CAT_INFO (gst_d3d11_debug_layer_debug, + "d3d11 debug library was loaded"); + create_flags |= D3D11_CREATE_DEVICE_DEBUG; + } else { + GST_CAT_INFO (gst_d3d11_debug_layer_debug, + "couldn't load d3d11 debug library"); + } + } +#endif + } + + /* Ensure valid device handle */ + if (data->type == DEVICE_CONSTRUCT_WRAPPED) { + ID3D11Device *external_device = data->data.device; + + hr = external_device->QueryInterface (IID_PPV_ARGS (&device)); + if (FAILED (hr)) { + GST_ERROR ("Not a valid external ID3D11Device handle"); + return nullptr; + } + + device->GetImmediateContext (&device_context); + } + + hr = _gst_d3d11_device_get_adapter (data, factory.Get (), &adapter_index, + &adapter_desc, &adapter); + if (FAILED (hr)) { + GST_INFO ("Failed to get DXGI adapter"); + return nullptr; + } + + if (data->type != DEVICE_CONSTRUCT_WRAPPED) { + hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, + NULL, create_flags, feature_levels, G_N_ELEMENTS (feature_levels), + D3D11_SDK_VERSION, &device, &selected_level, &device_context); + + if (FAILED (hr)) { + /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */ + hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, + NULL, create_flags, &feature_levels[1], + G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &device, + &selected_level, &device_context); + } + + /* if D3D11_CREATE_DEVICE_DEBUG was enabled but couldn't create device, + * try it without the flag again */ + if (FAILED (hr) && (create_flags & D3D11_CREATE_DEVICE_DEBUG) != 0) { + create_flags &= ~D3D11_CREATE_DEVICE_DEBUG; + + hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, + NULL, create_flags, feature_levels, G_N_ELEMENTS (feature_levels), + D3D11_SDK_VERSION, &device, &selected_level, &device_context); + + if (FAILED (hr)) { + /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */ + hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN, + NULL, create_flags, &feature_levels[1], + G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &device, + &selected_level, &device_context); + } + } + } + + if (FAILED (hr)) { + switch (data->type) { + case DEVICE_CONSTRUCT_FOR_ADAPTER_INDEX: + { + GST_INFO ("Failed to create d3d11 device for adapter index %d" + " with flags 0x%x, hr: 0x%x", data->data.adapter_index, + create_flags, (guint) hr); + return nullptr; + } + case DEVICE_CONSTRUCT_FOR_ADAPTER_LUID: + { + GST_ERROR ("Failed to create d3d11 device for adapter luid %" + G_GINT64_FORMAT " with flags 0x%x, hr: 0x%x", + data->data.adapter_luid, create_flags, (guint) hr); + return nullptr; + } + default: + break; + } + + return nullptr; + } + + GstD3D11Device *self = nullptr; + GstD3D11DevicePrivate *priv; + + self = (GstD3D11Device *) g_object_new (GST_TYPE_D3D11_DEVICE, nullptr); + gst_object_ref_sink (self); + + priv = self->priv; + + priv->adapter = adapter_index; + priv->device = device.Detach (); + priv->device_context = device_context.Detach (); + priv->factory = factory.Detach (); + + priv->vendor_id = adapter_desc.VendorId; + priv->device_id = adapter_desc.DeviceId; + priv->description = g_utf16_to_utf8 ((gunichar2 *) adapter_desc.Description, + -1, nullptr, nullptr, nullptr); + priv->adapter_luid = gst_d3d11_luid_to_int64 (&adapter_desc.AdapterLuid); + + DXGI_ADAPTER_DESC1 desc1; + hr = adapter->GetDesc1 (&desc1); + + /* DXGI_ADAPTER_FLAG_SOFTWARE is missing in dxgi.h of mingw */ + if (SUCCEEDED (hr) && (desc1.Flags & 0x2) != 0x2) + priv->hardware = TRUE; + + priv->create_flags = create_flags; + gst_d3d11_device_setup_format_table (self); + gst_d3d11_device_setup_debug_layer (self); + + return self; +} + /** * gst_d3d11_device_new: - * @adapter: the index of adapter for creating d3d11 device + * @adapter_index: the index of adapter for creating d3d11 device * @flags: a D3D11_CREATE_DEVICE_FLAG value used for creating d3d11 device * - * Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter + * Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter_index * or %NULL when failed to create D3D11 device with given adapter index. * * Since: 1.20 */ GstD3D11Device * -gst_d3d11_device_new (guint adapter, guint flags) +gst_d3d11_device_new (guint adapter_index, guint flags) { - GstD3D11Device *device = NULL; - GstD3D11DevicePrivate *priv; + GstD3D11DeviceConstructData data; - device = (GstD3D11Device *) - g_object_new (GST_TYPE_D3D11_DEVICE, "adapter", adapter, - "create-flags", flags, NULL); + data.data.adapter_index = adapter_index; + data.type = DEVICE_CONSTRUCT_FOR_ADAPTER_INDEX; + data.create_flags = flags; - priv = device->priv; + return gst_d3d11_device_new_internal (&data); +} - if (!priv->device || !priv->device_context) { - GST_DEBUG ("Cannot create d3d11 device with adapter %d", adapter); - gst_clear_object (&device); - } else { - gst_object_ref_sink (device); - } +/** + * gst_d3d11_device_new_for_adapter_luid: + * @adapter_luid: an int64 representation of the DXGI adapter LUID + * @flags: a D3D11_CREATE_DEVICE_FLAG value used for creating d3d11 device + * + * Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter_luid + * or %NULL when failed to create D3D11 device with given adapter luid. + * + * Since: 1.20 + */ +GstD3D11Device * +gst_d3d11_device_new_for_adapter_luid (gint64 adapter_luid, guint flags) +{ + GstD3D11DeviceConstructData data; - return device; + data.data.adapter_luid = adapter_luid; + data.type = DEVICE_CONSTRUCT_FOR_ADAPTER_LUID; + data.create_flags = flags; + + return gst_d3d11_device_new_internal (&data); +} + +/** + * gst_d3d11_device_new_wrapped: + * @device: (transfer none): an existing ID3D11Device handle + * + * Returns: (transfer full) (nullable): a new #GstD3D11Device for @device + * or %NULL if an error occurred + * + * Since: 1.20 + */ +GstD3D11Device * +gst_d3d11_device_new_wrapped (ID3D11Device * device) +{ + GstD3D11DeviceConstructData data; + + g_return_val_if_fail (device != nullptr, nullptr); + + data.data.device = device; + data.type = DEVICE_CONSTRUCT_WRAPPED; + data.create_flags = 0; + + return gst_d3d11_device_new_internal (&data); } /** diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.h b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.h index fd5d77d3ff..cad6b2d131 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.h @@ -59,9 +59,16 @@ GST_D3D11_API GType gst_d3d11_device_get_type (void); GST_D3D11_API -GstD3D11Device * gst_d3d11_device_new (guint adapter, +GstD3D11Device * gst_d3d11_device_new (guint adapter_index, guint flags); +GST_D3D11_API +GstD3D11Device * gst_d3d11_device_new_for_adapter_luid (gint64 adapter_luid, + guint flags); + +GST_D3D11_API +GstD3D11Device * gst_d3d11_device_new_wrapped (ID3D11Device * device); + GST_D3D11_API ID3D11Device * gst_d3d11_device_get_device_handle (GstD3D11Device * device); 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 e0d2aef64a..9e52c63210 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.cpp @@ -367,6 +367,29 @@ gst_d3d11_ensure_element_data (GstElement * element, gint adapter, return TRUE; } +/** + * gst_d3d11_luid_to_int64: + * @luid: A pointer to LUID struct + * + * Converts from a LUID to a 64-bit signed integer. + * See also Int64FromLuid method defined in + * windows.devices.display.core.interop.h Windows SDK header + * + * Since: 1.20 + */ +gint64 +gst_d3d11_luid_to_int64 (const LUID * luid) +{ + LARGE_INTEGER val; + + g_return_val_if_fail (luid != nullptr, 0); + + val.LowPart = luid->LowPart; + val.HighPart = luid->HighPart; + + return val.QuadPart; +} + gboolean _gst_d3d11_result (HRESULT hr, GstD3D11Device * device, GstDebugCategory * cat, const gchar * file, const gchar * function, gint line) diff --git a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.h b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.h index 6dd8cd9432..8d18b43f5e 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.h @@ -41,6 +41,9 @@ gboolean gst_d3d11_ensure_element_data (GstElement * element, gint adapter, GstD3D11Device ** device); +GST_D3D11_API +gint64 gst_d3d11_luid_to_int64 (const LUID * luid); + GST_D3D11_API gboolean _gst_d3d11_result (HRESULT hr, GstD3D11Device * device, diff --git a/subprojects/gst-plugins-bad/tests/check/libs/d3d11device.cpp b/subprojects/gst-plugins-bad/tests/check/libs/d3d11device.cpp new file mode 100644 index 0000000000..4d18803f22 --- /dev/null +++ b/subprojects/gst-plugins-bad/tests/check/libs/d3d11device.cpp @@ -0,0 +1,208 @@ +/* GStreamer + * Copyright (C) 2021 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +/* *INDENT-OFF* */ +using namespace Microsoft::WRL; +/* *INDENT-ON* */ + +static gboolean have_multiple_adapters = FALSE; + +GST_START_TEST (test_device_new) +{ + GstD3D11Device *device = nullptr; + guint adapter_index = G_MAXINT; + + device = gst_d3d11_device_new (0, 0); + fail_unless (GST_IS_D3D11_DEVICE (device)); + + g_object_get (device, "adapter", &adapter_index, nullptr); + fail_unless_equals_int (adapter_index, 0); + gst_clear_object (&device); + + if (have_multiple_adapters) { + device = gst_d3d11_device_new (1, 0); + fail_unless (GST_IS_D3D11_DEVICE (device)); + + g_object_get (device, "adapter", &adapter_index, nullptr); + fail_unless_equals_int (adapter_index, 1); + } + + gst_clear_object (&device); +} + +GST_END_TEST; + +GST_START_TEST (test_device_for_adapter_luid) +{ + GstD3D11Device *device = nullptr; + HRESULT hr; + ComPtr < IDXGIAdapter1 > adapter; + ComPtr < IDXGIFactory1 > factory; + DXGI_ADAPTER_DESC desc; + guint adapter_index = G_MAXINT; + gint64 adapter_luid = 0; + gint64 luid; + + hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory)); + if (SUCCEEDED (hr)) + hr = factory->EnumAdapters1 (0, &adapter); + + if (SUCCEEDED (hr)) + hr = adapter->GetDesc (&desc); + + if (SUCCEEDED (hr)) { + luid = gst_d3d11_luid_to_int64 (&desc.AdapterLuid); + device = gst_d3d11_device_new_for_adapter_luid (luid, 0); + fail_unless (GST_IS_D3D11_DEVICE (device)); + + g_object_get (device, "adapter", &adapter_index, "adapter-luid", + &adapter_luid, nullptr); + + /* adapter_luid is corresponding to the first enumerated adapter, + * so adapter index should be zero here */ + fail_unless_equals_int (adapter_index, 0); + fail_unless_equals_int64 (adapter_luid, luid); + } + + gst_clear_object (&device); + adapter = nullptr; + + if (have_multiple_adapters) { + if (SUCCEEDED (hr)) + hr = factory->EnumAdapters1 (1, &adapter); + + if (SUCCEEDED (hr)) + hr = adapter->GetDesc (&desc); + + if (SUCCEEDED (hr)) { + luid = gst_d3d11_luid_to_int64 (&desc.AdapterLuid); + device = gst_d3d11_device_new_for_adapter_luid (luid, 0); + fail_unless (GST_IS_D3D11_DEVICE (device)); + + g_object_get (device, "adapter", &adapter_index, "adapter-luid", + &adapter_luid, nullptr); + + fail_unless_equals_int (adapter_index, 1); + fail_unless_equals_int64 (adapter_luid, luid); + } + } + + gst_clear_object (&device); +} + +GST_END_TEST; + +GST_START_TEST (test_device_new_wrapped) +{ + GstD3D11Device *device = nullptr; + GstD3D11Device *device_clone = nullptr; + ID3D11Device *device_handle, *device_handle_clone; + ID3D11DeviceContext *context_handle, *context_handle_clone; + guint adapter_index = 0; + guint index; + gint64 luid, luid_clone; + + if (have_multiple_adapters) + adapter_index = 1; + + device = gst_d3d11_device_new (adapter_index, 0); + fail_unless (GST_IS_D3D11_DEVICE (device)); + + device_handle = gst_d3d11_device_get_device_handle (device); + fail_unless (device_handle != nullptr); + + context_handle = gst_d3d11_device_get_device_context_handle (device); + fail_unless (context_handle != nullptr); + + g_object_get (device, "adapter", &index, "adapter-luid", &luid, nullptr); + fail_unless_equals_int (index, adapter_index); + + device_clone = gst_d3d11_device_new_wrapped (device_handle); + fail_unless (GST_IS_D3D11_DEVICE (device_clone)); + + device_handle_clone = gst_d3d11_device_get_device_handle (device_clone); + fail_unless_equals_pointer (device_handle, device_handle_clone); + + context_handle_clone = + gst_d3d11_device_get_device_context_handle (device_clone); + fail_unless_equals_pointer (context_handle, context_handle_clone); + + g_object_get (device_clone, + "adapter", &index, "adapter-luid", &luid_clone, nullptr); + fail_unless_equals_int (index, adapter_index); + fail_unless_equals_int64 (luid, luid_clone); + + gst_clear_object (&device); + gst_clear_object (&device_clone); +} + +GST_END_TEST; + +static gboolean +check_d3d11_available (void) +{ + HRESULT hr; + ComPtr < IDXGIAdapter1 > adapter; + ComPtr < IDXGIFactory1 > factory; + + hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory)); + if (FAILED (hr)) + return FALSE; + + hr = factory->EnumAdapters1 (0, &adapter); + if (FAILED (hr)) + return FALSE; + + adapter = nullptr; + hr = factory->EnumAdapters1 (1, &adapter); + if (SUCCEEDED (hr)) + have_multiple_adapters = TRUE; + + return TRUE; +} + +static Suite * +d3d11device_suite (void) +{ + Suite *s = suite_create ("d3d11device"); + TCase *tc_basic = tcase_create ("general"); + + suite_add_tcase (s, tc_basic); + + if (!check_d3d11_available ()) + goto out; + + tcase_add_test (tc_basic, test_device_new); + tcase_add_test (tc_basic, test_device_for_adapter_luid); + tcase_add_test (tc_basic, test_device_new_wrapped); + +out: + return s; +} + +GST_CHECK_MAIN (d3d11device); diff --git a/subprojects/gst-plugins-bad/tests/check/meson.build b/subprojects/gst-plugins-bad/tests/check/meson.build index c87dd367a3..ab866c2a74 100644 --- a/subprojects/gst-plugins-bad/tests/check/meson.build +++ b/subprojects/gst-plugins-bad/tests/check/meson.build @@ -92,6 +92,7 @@ base_tests = [ [['libs/vkcommandpool.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], [['libs/vkimage.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], [['libs/vkinstance.c'], not gstvulkan_dep.found(), [gstvulkan_dep]], + [['libs/d3d11device.cpp'], not gstd3d11_dep.found(), [gstd3d11_dep]], ] # FIXME: unistd dependency, unstable or not tested yet on windows @@ -168,6 +169,16 @@ else endif gst_plugin_scanner_path = join_paths(gst_plugin_scanner_dir, 'gst-plugin-scanner') +extra_args = [] +# XXX: our MinGW 32bits toolchain complians when ComPtr is in use +if host_system == 'windows' and cc.get_id() != 'msvc' + mingw_args = cc.get_supported_arguments([ + '-Wno-redundant-decls', + ]) + + extra_args += mingw_args +endif + foreach t : base_tests fnames = t.get(0) test_name = fnames[0].split('.').get(0).underscorify() @@ -187,8 +198,8 @@ foreach t : base_tests if not skip_test exe = executable(test_name, fnames, extra_sources, include_directories : [configinc], - c_args : gst_plugins_bad_args + test_defines, - cpp_args : gst_plugins_bad_args + test_defines, + c_args : gst_plugins_bad_args + test_defines + extra_args, + cpp_args : gst_plugins_bad_args + test_defines + extra_args, dependencies : [libm] + test_deps + extra_deps, )