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 5eba00abad6622cd9df7134ad696e57ab5cdb43d..712e82955692b66024711375447b0b4cd01ce992 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11device.cpp @@ -87,7 +87,6 @@ enum PROP_VENDOR_ID, PROP_HARDWARE, PROP_DESCRIPTION, - PROP_ALLOW_TEARING, PROP_CREATE_FLAGS, PROP_ADAPTER_LUID, }; @@ -104,7 +103,6 @@ struct _GstD3D11DevicePrivate guint vendor_id; gboolean hardware; gchar *description; - gboolean allow_tearing; guint create_flags; gint64 adapter_luid; @@ -132,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); @@ -365,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", @@ -398,20 +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_ALLOW_TEARING, - g_param_spec_boolean ("allow-tearing", "Allow tearing", - "Whether dxgi device supports allow-tearing feature or not", FALSE, - 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 (); } @@ -750,230 +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 (GST_D3D11_DXGI_HEADER_VERSION >= 5) - { - ComPtr < IDXGIFactory5 > factory5; - BOOL allow_tearing; - - hr = factory.As (&factory5); - if (SUCCEEDED (hr)) { - hr = factory5->CheckFeatureSupport (DXGI_FEATURE_PRESENT_ALLOW_TEARING, - (void *) &allow_tearing, sizeof (allow_tearing)); - - priv->allow_tearing = SUCCEEDED (hr) && allow_tearing; - } - } -#endif - - 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) @@ -997,12 +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_ALLOW_TEARING: - g_value_set_boolean (value, priv->allow_tearing); - 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; @@ -1069,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; + + 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 device; + 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 fd5d77d3ffd0907b132f78d59d599371c5a15e38..cad6b2d131d05f74f4d3d8b270614e3b5fedc735 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 e0d2aef64adb19b0d5bccc35bf556cd7cde538df..ecc21aed15f1ac9236362baf8e88033b0f94d7bd 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.cpp +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.cpp @@ -66,12 +66,15 @@ _init_context_debug (void) * gst_d3d11_handle_set_context: * @element: a #GstElement * @context: a #GstContext + * @adapter_index: a DXGI adapter index * @device: (inout) (transfer full): location of a #GstD3D11Device * * Helper function for implementing #GstElementClass.set_context() in * D3D11 capable elements. * * Retrieve's the #GstD3D11Device in @context and places the result in @device. + * @device is accepted if @adapter_index is equal to -1 (accept any device) + * or equal to that of @device * * Returns: whether the @device could be set successfully * @@ -79,7 +82,7 @@ _init_context_debug (void) */ gboolean gst_d3d11_handle_set_context (GstElement * element, GstContext * context, - gint adapter, GstD3D11Device ** device) + gint adapter_index, GstD3D11Device ** device) { const gchar *context_type; @@ -95,7 +98,7 @@ gst_d3d11_handle_set_context (GstElement * element, GstContext * context, if (g_strcmp0 (context_type, GST_D3D11_DEVICE_HANDLE_CONTEXT_TYPE) == 0) { const GstStructure *str; GstD3D11Device *other_device = NULL; - guint other_adapter = 0; + guint other_adapter_index = 0; /* If we had device already, will not replace it */ if (*device) @@ -104,8 +107,70 @@ gst_d3d11_handle_set_context (GstElement * element, GstContext * context, str = gst_context_get_structure (context); if (gst_structure_get (str, "device", GST_TYPE_D3D11_DEVICE, - &other_device, "adapter", G_TYPE_UINT, &other_adapter, NULL)) { - if (adapter == -1 || (guint) adapter == other_adapter) { + &other_device, "adapter", G_TYPE_UINT, &other_adapter_index, + NULL)) { + if (adapter_index == -1 || (guint) adapter_index == other_adapter_index) { + GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, + element, "Found D3D11 device context"); + *device = other_device; + + return TRUE; + } + + gst_object_unref (other_device); + } + } + + return FALSE; +} + +/** + * gst_d3d11_handle_set_context_for_adapter_luid: + * @element: a #GstElement + * @context: a #GstContext + * @adapter_luid: an int64 representation of DXGI adapter LUID + * @device: (inout) (transfer full): location of a #GstD3D11Device + * + * Helper function for implementing #GstElementClass.set_context() in + * D3D11 capable elements. + * + * Retrieve's the #GstD3D11Device in @context and places the result in @device. + * @device is accepted only when @adapter_index is equal to that of @device + * + * Returns: whether the @device could be set successfully + * + * Since: 1.20 + */ +gboolean +gst_d3d11_handle_set_context_for_adapter_luid (GstElement * element, + GstContext * context, gint64 adapter_luid, GstD3D11Device ** device) +{ + const gchar *context_type; + + g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE); + g_return_val_if_fail (device != NULL, FALSE); + + _init_context_debug (); + + if (!context) + return FALSE; + + context_type = gst_context_get_context_type (context); + if (g_strcmp0 (context_type, GST_D3D11_DEVICE_HANDLE_CONTEXT_TYPE) == 0) { + const GstStructure *str; + GstD3D11Device *other_device = NULL; + gint64 other_adapter_luid = 0; + + /* If we had device already, will not replace it */ + if (*device) + return TRUE; + + str = gst_context_get_structure (context); + + if (gst_structure_get (str, "device", GST_TYPE_D3D11_DEVICE, + &other_device, "adapter-luid", G_TYPE_INT64, + &other_adapter_luid, NULL)) { + if (adapter_luid == other_adapter_luid) { GST_CAT_DEBUG_OBJECT (GST_CAT_CONTEXT, element, "Found D3D11 device context"); *device = other_device; @@ -301,7 +366,7 @@ run_d3d11_context_query (GstElement * element, GstD3D11Device ** device) /** * gst_d3d11_ensure_element_data: * @element: the #GstElement running the query - * @adapter: preferred adapter index, pass adapter >=0 when + * @adapter: preferred DXGI adapter index, pass adapter >=0 when * the adapter explicitly required. Otherwise, set -1. * @device: (inout): the resulting #GstD3D11Device * @@ -367,6 +432,93 @@ gst_d3d11_ensure_element_data (GstElement * element, gint adapter, return TRUE; } +/** + * gst_d3d11_ensure_element_data_for_adapter_luid: + * @element: the #GstElement running the query + * @adapter_luid: an int64 representation of DXGI adapter LUID + * @device: (inout): the resulting #GstD3D11Device + * + * Perform the steps necessary for retrieving a #GstD3D11Device + * from the surrounding elements or from the application using the #GstContext mechanism. + * + * If the contents of @device is not %NULL, then no #GstContext query is + * necessary for #GstD3D11Device retrieval is performed. + * + * Returns: whether a #GstD3D11Device exists in @device + * + * Since: 1.20 + */ +gboolean +gst_d3d11_ensure_element_data_for_adapter_luid (GstElement * element, + gint64 adapter_luid, GstD3D11Device ** device) +{ + g_return_val_if_fail (element != NULL, FALSE); + g_return_val_if_fail (device != NULL, FALSE); + + _init_context_debug (); + + if (*device) { + GST_LOG_OBJECT (element, "already have a device %" GST_PTR_FORMAT, *device); + return TRUE; + } + + run_d3d11_context_query (element, device); + if (*device) + return TRUE; + + /* Needs D3D11_CREATE_DEVICE_BGRA_SUPPORT flag for Direct2D interop */ + *device = gst_d3d11_device_new_for_adapter_luid (adapter_luid, + D3D11_CREATE_DEVICE_BGRA_SUPPORT); + + if (*device == NULL) { + GST_ERROR_OBJECT (element, + "Couldn't create new device with adapter luid %" G_GINT64_FORMAT, + adapter_luid); + return FALSE; + } else { + GstContext *context; + GstMessage *msg; + + /* Propagate new D3D11 device context */ + + context = gst_context_new (GST_D3D11_DEVICE_HANDLE_CONTEXT_TYPE, TRUE); + context_set_d3d11_device (context, *device); + + gst_element_set_context (element, context); + + GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, + "posting have context (%p) message with D3D11 device context (%p)", + context, *device); + msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context); + gst_element_post_message (GST_ELEMENT_CAST (element), msg); + } + + 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 6dd8cd94327f7670f5a48fb166e1efe517e0526a..a5b22ac1f907a01585c5f485a0eb2040b1be68f9 100644 --- a/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.h +++ b/subprojects/gst-plugins-bad/gst-libs/gst/d3d11/gstd3d11utils.h @@ -28,9 +28,15 @@ G_BEGIN_DECLS GST_D3D11_API gboolean gst_d3d11_handle_set_context (GstElement * element, GstContext * context, - gint adapter, + gint adapter_index, GstD3D11Device ** device); +GST_D3D11_API +gboolean gst_d3d11_handle_set_context_for_adapter_luid (GstElement * element, + GstContext * context, + gint64 adapter_luid, + GstD3D11Device ** device); + GST_D3D11_API gboolean gst_d3d11_handle_context_query (GstElement * element, GstQuery * query, @@ -38,9 +44,17 @@ gboolean gst_d3d11_handle_context_query (GstElement * element, GST_D3D11_API gboolean gst_d3d11_ensure_element_data (GstElement * element, - gint adapter, + gint adapter_index, GstD3D11Device ** device); +GST_D3D11_API +gboolean gst_d3d11_ensure_element_data_for_adapter_luid (GstElement * element, + gint64 adapter_luid, + 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/sys/d3d11/gstd3d11av1dec.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11av1dec.cpp index f428865196893dfa7041311016fe014dad90d5ca..290c0b56e397eecded06c65e7fb57545bc97cee3 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11av1dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11av1dec.cpp @@ -501,8 +501,8 @@ gst_d3d11_av1_dec_set_context (GstElement * element, GstContext * context) GstD3D11AV1DecClass *klass = GST_D3D11_AV1_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - gst_d3d11_handle_set_context (element, context, cdata->adapter, - &inner->device); + gst_d3d11_handle_set_context_for_adapter_luid (element, + context, cdata->adapter_luid, &inner->device); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -515,18 +515,9 @@ gst_d3d11_av1_dec_open (GstVideoDecoder * decoder) GstD3D11AV1DecClass *klass = GST_D3D11_AV1_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), cdata->adapter, - &inner->device)) { - GST_ERROR_OBJECT (self, "Cannot create d3d11device"); - return FALSE; - } - - inner->d3d11_decoder = gst_d3d11_decoder_new (inner->device, - GST_DXVA_CODEC_AV1); - - if (!inner->d3d11_decoder) { - GST_ERROR_OBJECT (self, "Cannot create d3d11 decoder"); - gst_clear_object (&inner->device); + if (!gst_d3d11_decoder_proxy_open (decoder, + cdata, &inner->device, &inner->d3d11_decoder)) { + GST_ERROR_OBJECT (self, "Failed to open decoder"); return FALSE; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11decoder.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11decoder.cpp index ce65b537f38bf4b87f9434f24eaa6537f4c5c15c..a511c6cb7f68f05ecbf8b85f5e26cd4901deda16 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11decoder.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11decoder.cpp @@ -2090,7 +2090,7 @@ gst_d3d11_decoder_supports_resolution (GstD3D11Device * device, enum { - PROP_DECODER_ADAPTER = 1, + PROP_DECODER_ADAPTER_LUID = 1, PROP_DECODER_DEVICE_ID, PROP_DECODER_VENDOR_ID, }; @@ -2101,7 +2101,6 @@ struct _GstD3D11DecoderClassData GstCaps *sink_caps; GstCaps *src_caps; gchar *description; - GstDXVACodec codec; }; /** @@ -2126,13 +2125,12 @@ gst_d3d11_decoder_class_data_new (GstD3D11Device * device, GstDXVACodec codec, ret = g_new0 (GstD3D11DecoderClassData, 1); - ret->codec = codec; - /* class data will be leaked if the element never gets instantiated */ GST_MINI_OBJECT_FLAG_SET (sink_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); GST_MINI_OBJECT_FLAG_SET (src_caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED); - g_object_get (device, "adapter", &ret->subclass_data.adapter, + ret->subclass_data.codec = codec; + g_object_get (device, "adapter-luid", &ret->subclass_data.adapter_luid, "device-id", &ret->subclass_data.device_id, "vendor-id", &ret->subclass_data.vendor_id, "description", &ret->description, nullptr); @@ -2174,10 +2172,10 @@ gst_d3d11_decoder_proxy_class_init (GstElementClass * klass, std::string description; const gchar *codec_name; - g_object_class_install_property (gobject_class, PROP_DECODER_ADAPTER, - g_param_spec_uint ("adapter", "Adapter", - "DXGI Adapter index for creating device", - 0, G_MAXUINT32, cdata->adapter, + g_object_class_install_property (gobject_class, PROP_DECODER_ADAPTER_LUID, + g_param_spec_int64 ("adapter-luid", "Adapter LUID", + "DXGI Adapter LUID (Locally Unique Identifier) of created device", + G_MININT64, G_MAXINT64, cdata->adapter_luid, (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); g_object_class_install_property (gobject_class, PROP_DECODER_DEVICE_ID, @@ -2190,7 +2188,7 @@ gst_d3d11_decoder_proxy_class_init (GstElementClass * klass, "DXGI Vendor ID", 0, G_MAXUINT32, 0, (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); - codec_name = gst_dxva_codec_to_string (data->codec); + codec_name = gst_dxva_codec_to_string (cdata->codec); long_name = "Direct3D11/DXVA " + std::string (codec_name) + " " + std::string (data->description) + " Decoder"; description = "Direct3D11/DXVA based " + std::string (codec_name) + @@ -2215,8 +2213,8 @@ gst_d3d11_decoder_proxy_get_property (GObject * object, guint prop_id, GstD3D11DecoderSubClassData * subclass_data) { switch (prop_id) { - case PROP_DECODER_ADAPTER: - g_value_set_uint (value, subclass_data->adapter); + case PROP_DECODER_ADAPTER_LUID: + g_value_set_int64 (value, subclass_data->adapter_luid); break; case PROP_DECODER_DEVICE_ID: g_value_set_uint (value, subclass_data->device_id); @@ -2229,3 +2227,27 @@ gst_d3d11_decoder_proxy_get_property (GObject * object, guint prop_id, break; } } + +gboolean +gst_d3d11_decoder_proxy_open (GstVideoDecoder * videodec, + GstD3D11DecoderSubClassData * subclass_data, GstD3D11Device ** device, + GstD3D11Decoder ** decoder) +{ + GstElement *elem = GST_ELEMENT (videodec); + + if (!gst_d3d11_ensure_element_data_for_adapter_luid (elem, + subclass_data->adapter_luid, device)) { + GST_ERROR_OBJECT (elem, "Cannot create d3d11device"); + return FALSE; + } + + *decoder = gst_d3d11_decoder_new (*device, subclass_data->codec); + + if (*decoder == nullptr) { + GST_ERROR_OBJECT (elem, "Cannot create d3d11 decoder"); + gst_clear_object (device); + return FALSE; + } + + return TRUE; +} diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11decoder.h b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11decoder.h index 08445fe651639aa541d5d84cf305a9f54aed0f2d..f07028b291976cce60fe71ab9289732c2f842980 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11decoder.h +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11decoder.h @@ -48,7 +48,8 @@ typedef enum typedef struct { - guint adapter; + GstDXVACodec codec; + gint64 adapter_luid; guint device_id; guint vendor_id; } GstD3D11DecoderSubClassData; @@ -157,6 +158,11 @@ void gst_d3d11_decoder_proxy_get_property (GObject * object, GParamSpec * pspec, GstD3D11DecoderSubClassData * subclass_data); +gboolean gst_d3d11_decoder_proxy_open (GstVideoDecoder * videodec, + GstD3D11DecoderSubClassData * subclass_data, + GstD3D11Device ** device, + GstD3D11Decoder ** decoder); + G_END_DECLS #endif /* __GST_D3D11_DECODER_H__ */ diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11h264dec.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11h264dec.cpp index ba7318cf977dc9434b328510877c7b629cc6816b..bea4462ef13c28ee8868004fc9b814a427f97ffe 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11h264dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11h264dec.cpp @@ -236,8 +236,8 @@ gst_d3d11_h264_dec_set_context (GstElement * element, GstContext * context) GstD3D11H264DecClass *klass = GST_D3D11_H264_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - gst_d3d11_handle_set_context (element, context, cdata->adapter, - &inner->device); + gst_d3d11_handle_set_context_for_adapter_luid (element, + context, cdata->adapter_luid, &inner->device); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -267,18 +267,9 @@ gst_d3d11_h264_dec_open (GstVideoDecoder * decoder) GstD3D11H264DecClass *klass = GST_D3D11_H264_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), cdata->adapter, - &inner->device)) { - GST_ERROR_OBJECT (self, "Cannot create d3d11device"); - return FALSE; - } - - inner->d3d11_decoder = gst_d3d11_decoder_new (inner->device, - GST_DXVA_CODEC_H264); - - if (!inner->d3d11_decoder) { - GST_ERROR_OBJECT (self, "Cannot create d3d11 decoder"); - gst_clear_object (&inner->device); + if (!gst_d3d11_decoder_proxy_open (decoder, + cdata, &inner->device, &inner->d3d11_decoder)) { + GST_ERROR_OBJECT (self, "Failed to open decoder"); return FALSE; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11h265dec.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11h265dec.cpp index 91bd56d929371b18d53ced1fd3a20e0122cae244..2ec9b7017c213899316e421d889269b29a2b6d13 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11h265dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11h265dec.cpp @@ -203,8 +203,8 @@ gst_d3d11_h265_dec_set_context (GstElement * element, GstContext * context) GstD3D11H265DecClass *klass = GST_D3D11_H265_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - gst_d3d11_handle_set_context (element, context, cdata->adapter, - &inner->device); + gst_d3d11_handle_set_context_for_adapter_luid (element, + context, cdata->adapter_luid, &inner->device); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -217,18 +217,9 @@ gst_d3d11_h265_dec_open (GstVideoDecoder * decoder) GstD3D11H265DecClass *klass = GST_D3D11_H265_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), cdata->adapter, - &inner->device)) { - GST_ERROR_OBJECT (self, "Cannot create d3d11device"); - return FALSE; - } - - inner->d3d11_decoder = gst_d3d11_decoder_new (inner->device, - GST_DXVA_CODEC_H265); - - if (!inner->d3d11_decoder) { - GST_ERROR_OBJECT (self, "Cannot create d3d11 decoder"); - gst_clear_object (&inner->device); + if (!gst_d3d11_decoder_proxy_open (decoder, + cdata, &inner->device, &inner->d3d11_decoder)) { + GST_ERROR_OBJECT (self, "Failed to open decoder"); return FALSE; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11mpeg2dec.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11mpeg2dec.cpp index 8b89519c4ad177167d909c32259ac4807c2af742..145d2f55d7218c4a0850de2ef3b61ac1a9e13125 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11mpeg2dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11mpeg2dec.cpp @@ -215,8 +215,8 @@ gst_d3d11_mpeg2_dec_set_context (GstElement * element, GstContext * context) GstD3D11Mpeg2DecClass *klass = GST_D3D11_MPEG2_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - gst_d3d11_handle_set_context (element, context, cdata->adapter, - &inner->device); + gst_d3d11_handle_set_context_for_adapter_luid (element, + context, cdata->adapter_luid, &inner->device); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -229,18 +229,9 @@ gst_d3d11_mpeg2_dec_open (GstVideoDecoder * decoder) GstD3D11Mpeg2DecClass *klass = GST_D3D11_MPEG2_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), cdata->adapter, - &inner->device)) { - GST_ERROR_OBJECT (self, "Cannot create d3d11device"); - return FALSE; - } - - inner->d3d11_decoder = gst_d3d11_decoder_new (inner->device, - GST_DXVA_CODEC_MPEG2); - - if (!inner->d3d11_decoder) { - GST_ERROR_OBJECT (self, "Cannot create d3d11 decoder"); - gst_clear_object (&inner->device); + if (!gst_d3d11_decoder_proxy_open (decoder, + cdata, &inner->device, &inner->d3d11_decoder)) { + GST_ERROR_OBJECT (self, "Failed to open decoder"); return FALSE; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11vp8dec.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11vp8dec.cpp index a870a64a0d4506660889b1ed4add34cb63bc14d8..e5a55aa0a0e8c93913efa365620ba59597d011ea 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11vp8dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11vp8dec.cpp @@ -199,8 +199,8 @@ gst_d3d11_vp8_dec_set_context (GstElement * element, GstContext * context) GstD3D11Vp8DecClass *klass = GST_D3D11_VP8_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - gst_d3d11_handle_set_context (element, context, cdata->adapter, - &inner->device); + gst_d3d11_handle_set_context_for_adapter_luid (element, + context, cdata->adapter_luid, &inner->device); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -213,18 +213,9 @@ gst_d3d11_vp8_dec_open (GstVideoDecoder * decoder) GstD3D11Vp8DecClass *klass = GST_D3D11_VP8_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), cdata->adapter, - &inner->device)) { - GST_ERROR_OBJECT (self, "Cannot create d3d11device"); - return FALSE; - } - - inner->d3d11_decoder = gst_d3d11_decoder_new (inner->device, - GST_DXVA_CODEC_VP8); - - if (!inner->d3d11_decoder) { - GST_ERROR_OBJECT (self, "Cannot create d3d11 decoder"); - gst_clear_object (&inner->device); + if (!gst_d3d11_decoder_proxy_open (decoder, + cdata, &inner->device, &inner->d3d11_decoder)) { + GST_ERROR_OBJECT (self, "Failed to open decoder"); return FALSE; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11vp9dec.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11vp9dec.cpp index b84d28a76e039f336e4dfec380f43393d6acbc78..abb666e7b089c6cfe96e64a84f99c8e0f69ded7d 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11vp9dec.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11vp9dec.cpp @@ -234,8 +234,8 @@ gst_d3d11_vp9_dec_set_context (GstElement * element, GstContext * context) GstD3D11Vp9DecClass *klass = GST_D3D11_VP9_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - gst_d3d11_handle_set_context (element, context, cdata->adapter, - &inner->device); + gst_d3d11_handle_set_context_for_adapter_luid (element, + context, cdata->adapter_luid, &inner->device); GST_ELEMENT_CLASS (parent_class)->set_context (element, context); } @@ -248,18 +248,9 @@ gst_d3d11_vp9_dec_open (GstVideoDecoder * decoder) GstD3D11Vp9DecClass *klass = GST_D3D11_VP9_DEC_GET_CLASS (self); GstD3D11DecoderSubClassData *cdata = &klass->class_data; - if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), cdata->adapter, - &inner->device)) { - GST_ERROR_OBJECT (self, "Cannot create d3d11device"); - return FALSE; - } - - inner->d3d11_decoder = gst_d3d11_decoder_new (inner->device, - GST_DXVA_CODEC_VP9); - - if (!inner->d3d11_decoder) { - GST_ERROR_OBJECT (self, "Cannot create d3d11 decoder"); - gst_clear_object (&inner->device); + if (!gst_d3d11_decoder_proxy_open (decoder, + cdata, &inner->device, &inner->d3d11_decoder)) { + GST_ERROR_OBJECT (self, "Failed to open decoder"); return FALSE; } diff --git a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp index 00f98be924baea0a3fe0207551ffbda4ea3ac180..d0c994d895f6522e26e0d48dae7b06a639d6bec0 100644 --- a/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp +++ b/subprojects/gst-plugins-bad/sys/d3d11/gstd3d11window.cpp @@ -533,7 +533,25 @@ gst_d3d11_window_prepare_default (GstD3D11Window * window, guint display_width, /* Step 3: Create swapchain * (or reuse old swapchain if the format is not changed) */ window->allow_tearing = FALSE; - g_object_get (window->device, "allow-tearing", &window->allow_tearing, NULL); + +#if (GST_D3D11_DXGI_HEADER_VERSION >= 5) + { + ComPtr < IDXGIFactory5 > factory5; + IDXGIFactory1 *factory_handle; + BOOL allow_tearing = FALSE; + + factory_handle = gst_d3d11_device_get_dxgi_factory_handle (window->device); + hr = factory_handle->QueryInterface (IID_PPV_ARGS (&factory5)); + if (SUCCEEDED (hr)) { + hr = factory5->CheckFeatureSupport (DXGI_FEATURE_PRESENT_ALLOW_TEARING, + (void *) &allow_tearing, sizeof (allow_tearing)); + } + + if (SUCCEEDED (hr) && allow_tearing) + window->allow_tearing = allow_tearing; + } +#endif + if (window->allow_tearing) { GST_DEBUG_OBJECT (window, "device support tearning"); swapchain_flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; diff --git a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfh264enc.cpp b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfh264enc.cpp index 69374b7d02c6f14a59bd174285f5595a15ba9e46..522e5907f568e877b21c5dc94b1f09ce43a4b203 100644 --- a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfh264enc.cpp +++ b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfh264enc.cpp @@ -163,7 +163,7 @@ enum PROP_QP_B, PROP_REF, PROP_D3D11_AWARE, - PROP_ADAPTER, + PROP_ADAPTER_LUID, }; #define DEFAULT_BITRATE (2 * 1024) @@ -476,10 +476,10 @@ gst_mf_h264_enc_class_init (GstMFH264EncClass * klass, gpointer data) (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); if (device_caps->d3d11_aware) { - g_object_class_install_property (gobject_class, PROP_ADAPTER, - g_param_spec_uint ("adapter", "Adapter", - "DXGI Adapter index for creating device", - 0, G_MAXUINT32, device_caps->adapter, + 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", + G_MININT64, G_MAXINT64, device_caps->adapter_luid, (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); } @@ -629,8 +629,8 @@ gst_mf_h264_enc_get_property (GObject * object, guint prop_id, case PROP_D3D11_AWARE: g_value_set_boolean (value, klass->device_caps.d3d11_aware); break; - case PROP_ADAPTER: - g_value_set_uint (value, klass->device_caps.adapter); + case PROP_ADAPTER_LUID: + g_value_set_int64 (value, klass->device_caps.adapter_luid); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfh265enc.cpp b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfh265enc.cpp index 375acf4dbd908dd20111db758f2ce6912cb087a4..e844ce8131299fa112171f32ca5dc871cce74bf3 100644 --- a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfh265enc.cpp +++ b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfh265enc.cpp @@ -118,7 +118,7 @@ enum PROP_QP_B, PROP_REF, PROP_D3D11_AWARE, - PROP_ADAPTER, + PROP_ADAPTER_LUID, }; #define DEFAULT_BITRATE (2 * 1024) @@ -364,10 +364,10 @@ gst_mf_h265_enc_class_init (GstMFH265EncClass * klass, gpointer data) (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); if (device_caps->d3d11_aware) { - g_object_class_install_property (gobject_class, PROP_ADAPTER, - g_param_spec_uint ("adapter", "Adapter", - "DXGI Adapter index for creating device", - 0, G_MAXUINT32, device_caps->adapter, + 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", + G_MININT64, G_MAXINT64, device_caps->adapter_luid, (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); } @@ -487,8 +487,8 @@ gst_mf_h265_enc_get_property (GObject * object, guint prop_id, case PROP_D3D11_AWARE: g_value_set_boolean (value, klass->device_caps.d3d11_aware); break; - case PROP_ADAPTER: - g_value_set_uint (value, klass->device_caps.adapter); + case PROP_ADAPTER_LUID: + g_value_set_int64 (value, klass->device_caps.adapter_luid); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); diff --git a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvideoenc.cpp b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvideoenc.cpp index 312bb8ec2f736554babab59eb33508b8df8d68c7..66c48e19cd47e161d8793480005d294e707246ed 100644 --- a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvideoenc.cpp +++ b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvideoenc.cpp @@ -120,8 +120,13 @@ gst_mf_video_enc_set_context (GstElement * element, GstContext * context) { #if GST_MF_HAVE_D3D11 GstMFVideoEnc *self = GST_MF_VIDEO_ENC (element); + GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (self); + GstMFVideoEncDeviceCaps *device_caps = &klass->device_caps; - gst_d3d11_handle_set_context (element, context, 0, &self->other_d3d11_device); + if (device_caps->d3d11_aware) { + gst_d3d11_handle_set_context_for_adapter_luid (element, context, + device_caps->adapter_luid, &self->other_d3d11_device); + } #endif GST_ELEMENT_CLASS (parent_class)->set_context (element, context); @@ -134,7 +139,6 @@ gst_mf_video_enc_open (GstVideoEncoder * enc) GstMFVideoEncClass *klass = GST_MF_VIDEO_ENC_GET_CLASS (enc); GstMFVideoEncDeviceCaps *device_caps = &klass->device_caps; GstMFTransformEnumParams enum_params = { 0, }; - gint64 adapter_luid = 0; MFT_REGISTER_TYPE_INFO output_type; gboolean ret; @@ -145,14 +149,15 @@ gst_mf_video_enc_open (GstVideoEncoder * enc) ComPtr < ID3D10Multithread > multi_thread; GstD3D11Device *device; - if (!gst_d3d11_ensure_element_data (GST_ELEMENT_CAST (self), - device_caps->adapter, &self->other_d3d11_device)) { + if (!gst_d3d11_ensure_element_data_for_adapter_luid (GST_ELEMENT (self), + device_caps->adapter_luid, &self->other_d3d11_device)) { GST_ERROR_OBJECT (self, "Other d3d11 device is unavailable"); return FALSE; } /* Create our own device with D3D11_CREATE_DEVICE_VIDEO_SUPPORT */ - self->d3d11_device = gst_d3d11_device_new (device_caps->adapter, + self->d3d11_device = + gst_d3d11_device_new_for_adapter_luid (device_caps->adapter_luid, D3D11_CREATE_DEVICE_VIDEO_SUPPORT); if (!self->d3d11_device) { GST_ERROR_OBJECT (self, "Couldn't create internal d3d11 device"); @@ -191,8 +196,6 @@ gst_mf_video_enc_open (GstVideoEncoder * enc) gst_clear_object (&self->d3d11_device); return FALSE; } - - g_object_get (self->d3d11_device, "adapter-luid", &adapter_luid, NULL); } #endif @@ -205,12 +208,12 @@ gst_mf_video_enc_open (GstVideoEncoder * enc) enum_params.device_index = klass->device_index; if (device_caps->d3d11_aware) - enum_params.adapter_luid = adapter_luid; + enum_params.adapter_luid = device_caps->adapter_luid; GST_DEBUG_OBJECT (self, "Create MFT with enum flags: 0x%x, device index: %d, d3d11 aware: %d, " "adapter-luid %" G_GINT64_FORMAT, klass->enum_flags, klass->device_index, - device_caps->d3d11_aware, adapter_luid); + device_caps->d3d11_aware, device_caps->adapter_luid); self->transform = gst_mf_transform_new (&enum_params); ret = !!self->transform; @@ -1692,10 +1695,10 @@ gst_mf_video_enc_enum_internal (GstMFTransform * transform, GUID & subtype, } if (d3d11_device && (have_NV12 || have_P010) && d3d11_aware) { - guint adapter = 0; + gint64 adapter_luid = 0; GValue d3d11_formats = G_VALUE_INIT; - g_object_get (d3d11_device, "adapter", &adapter, NULL); + g_object_get (d3d11_device, "adapter-luid", &adapter_luid, NULL); d3d11_caps = gst_caps_copy (sink_caps); @@ -1719,7 +1722,7 @@ gst_mf_video_enc_enum_internal (GstMFTransform * transform, GUID & subtype, gst_caps_set_features_simple (d3d11_caps, gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_D3D11_MEMORY)); device_caps->d3d11_aware = TRUE; - device_caps->adapter = adapter; + device_caps->adapter_luid = adapter_luid; } #endif diff --git a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvideoenc.h b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvideoenc.h index 1248fb5f2b09d578e41b77a682bbc13030937517..f798dbc2d6836174679c8497163411450249f5f6 100644 --- a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvideoenc.h +++ b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvideoenc.h @@ -75,8 +75,8 @@ struct _GstMFVideoEncDeviceCaps /* TRUE if MFT support d3d11 and also we can use d3d11 interop */ gboolean d3d11_aware; - /* DXGI adapter index to use, ignored if d3d11-unaware */ - guint adapter; + /* DXGI adapter LUID, valid only when d3d11_aware == TRUE */ + gint64 adapter_luid; }; struct _GstMFVideoEncClassData diff --git a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvp9enc.cpp b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvp9enc.cpp index 99e3fa7f9a3826fba8b81f9fea925cfe478ab731..ef38d08e0b34b78886a9b51d3ba0f65d6ed1ef21 100644 --- a/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvp9enc.cpp +++ b/subprojects/gst-plugins-bad/sys/mediafoundation/gstmfvp9enc.cpp @@ -108,7 +108,7 @@ enum PROP_CONTENT_TYPE, PROP_LOW_LATENCY, PROP_D3D11_AWARE, - PROP_ADAPTER, + PROP_ADAPTER_LUID, }; #define DEFAULT_BITRATE (2 * 1024) @@ -261,10 +261,10 @@ gst_mf_vp9_enc_class_init (GstMFVP9EncClass * klass, gpointer data) (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); if (device_caps->d3d11_aware) { - g_object_class_install_property (gobject_class, PROP_ADAPTER, - g_param_spec_uint ("adapter", "Adapter", - "DXGI Adapter index for creating device", - 0, G_MAXUINT32, device_caps->adapter, + 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", + G_MININT64, G_MAXINT64, device_caps->adapter_luid, (GParamFlags) (GST_PARAM_CONDITIONALLY_AVAILABLE | G_PARAM_READABLE | G_PARAM_STATIC_STRINGS))); } @@ -349,8 +349,8 @@ gst_mf_vp9_enc_get_property (GObject * object, guint prop_id, case PROP_D3D11_AWARE: g_value_set_boolean (value, klass->device_caps.d3d11_aware); break; - case PROP_ADAPTER: - g_value_set_uint (value, klass->device_caps.adapter); + case PROP_ADAPTER_LUID: + g_value_set_int64 (value, klass->device_caps.adapter_luid); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); 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 0000000000000000000000000000000000000000..4d18803f222deb013d772dc1c4ab3301ea5231df --- /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 c87dd367a31b8bd18cf0a9059b597b0c18f85894..ab866c2a74e613eea9cabd2a6707e1256335d4ec 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, )