d3b65bd29bccdee016b56d191bb4f9b81104738b
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / gst-libs / gst / d3d11 / gstd3d11device.cpp
1 /* GStreamer
2  * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
3  * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gstd3d11device.h"
26 #include "gstd3d11utils.h"
27 #include "gstd3d11format.h"
28 #include "gstd3d11_private.h"
29 #include "gstd3d11memory.h"
30 #include <gmodule.h>
31 #include <wrl.h>
32
33 #include <windows.h>
34 #include <versionhelpers.h>
35
36 /**
37  * SECTION:gstd3d11device
38  * @short_description: Direct3D11 device abstraction
39  * @title: GstD3D11Device
40  *
41  * #GstD3D11Device wraps ID3D11Device and ID3D11DeviceContext for GPU resources
42  * to be able to be shared among various elements. Caller can get native
43  * Direct3D11 handles via getter method.
44  * Basically Direct3D11 API doesn't require dedicated thread like that of
45  * OpenGL context, and ID3D11Device APIs are supposed to be thread-safe.
46  * But concurrent call for ID3D11DeviceContext and DXGI API are not allowed.
47  * To protect such object, callers need to make use of gst_d3d11_device_lock()
48  * and gst_d3d11_device_unlock()
49  */
50
51 /* *INDENT-OFF* */
52 using namespace Microsoft::WRL;
53 /* *INDENT-ON* */
54
55 #if HAVE_D3D11SDKLAYERS_H
56 #include <d3d11sdklayers.h>
57 static GModule *d3d11_debug_module = NULL;
58
59 /* mingw header does not define D3D11_RLDO_IGNORE_INTERNAL
60  * D3D11_RLDO_SUMMARY = 0x1,
61    D3D11_RLDO_DETAIL = 0x2,
62  * D3D11_RLDO_IGNORE_INTERNAL = 0x4
63  */
64 #define GST_D3D11_RLDO_FLAGS (0x2 | 0x4)
65 #endif
66
67 #if HAVE_DXGIDEBUG_H
68 #include <dxgidebug.h>
69 typedef HRESULT (WINAPI * DXGIGetDebugInterface_t) (REFIID riid,
70     void **ppDebug);
71 static GModule *dxgi_debug_module = NULL;
72 static DXGIGetDebugInterface_t GstDXGIGetDebugInterface = NULL;
73
74 #endif
75
76 #if (HAVE_D3D11SDKLAYERS_H || HAVE_DXGIDEBUG_H)
77 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_debug_layer_debug);
78 #endif
79 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_device_debug);
80 #define GST_CAT_DEFAULT gst_d3d11_device_debug
81
82 enum
83 {
84   PROP_0,
85   PROP_ADAPTER,
86   PROP_DEVICE_ID,
87   PROP_VENDOR_ID,
88   PROP_HARDWARE,
89   PROP_DESCRIPTION,
90   PROP_CREATE_FLAGS,
91   PROP_ADAPTER_LUID,
92 };
93
94 #define DEFAULT_ADAPTER 0
95 #define DEFAULT_CREATE_FLAGS 0
96
97 #define GST_D3D11_N_FORMATS 25
98
99 struct _GstD3D11DevicePrivate
100 {
101   guint adapter;
102   guint device_id;
103   guint vendor_id;
104   gboolean hardware;
105   gchar *description;
106   guint create_flags;
107   gint64 adapter_luid;
108
109   ID3D11Device *device;
110   ID3D11DeviceContext *device_context;
111
112   ID3D11VideoDevice *video_device;
113   ID3D11VideoContext *video_context;
114
115   IDXGIFactory1 *factory;
116   GstD3D11Format format_table[GST_D3D11_N_FORMATS];
117
118   GRecMutex extern_lock;
119   GMutex resource_lock;
120
121 #if HAVE_D3D11SDKLAYERS_H
122   ID3D11Debug *d3d11_debug;
123   ID3D11InfoQueue *d3d11_info_queue;
124 #endif
125
126 #if HAVE_DXGIDEBUG_H
127   IDXGIDebug *dxgi_debug;
128   IDXGIInfoQueue *dxgi_info_queue;
129 #endif
130 };
131
132 static void
133 debug_init_once (void)
134 {
135   static gsize init_once = 0;
136
137   if (g_once_init_enter (&init_once)) {
138     GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug,
139         "d3d11device", 0, "d3d11 device object");
140 #if defined(HAVE_D3D11SDKLAYERS_H) || defined(HAVE_DXGIDEBUG_H)
141     GST_DEBUG_CATEGORY_INIT (gst_d3d11_debug_layer_debug,
142         "d3d11debuglayer", 0, "native d3d11 and dxgi debug");
143 #endif
144     g_once_init_leave (&init_once, 1);
145   }
146 }
147
148 #define gst_d3d11_device_parent_class parent_class
149 G_DEFINE_TYPE_WITH_CODE (GstD3D11Device, gst_d3d11_device, GST_TYPE_OBJECT,
150     G_ADD_PRIVATE (GstD3D11Device); debug_init_once ());
151
152 static void gst_d3d11_device_get_property (GObject * object, guint prop_id,
153     GValue * value, GParamSpec * pspec);
154 static void gst_d3d11_device_dispose (GObject * object);
155 static void gst_d3d11_device_finalize (GObject * object);
156
157 #if HAVE_D3D11SDKLAYERS_H
158 static gboolean
159 gst_d3d11_device_enable_d3d11_debug (void)
160 {
161   static gsize _init = 0;
162
163   /* If all below libraries are unavailable, d3d11 device would fail with
164    * D3D11_CREATE_DEVICE_DEBUG flag */
165   if (g_once_init_enter (&_init)) {
166     d3d11_debug_module =
167         g_module_open ("d3d11sdklayers.dll", G_MODULE_BIND_LAZY);
168
169     if (!d3d11_debug_module)
170       d3d11_debug_module =
171           g_module_open ("d3d11_1sdklayers.dll", G_MODULE_BIND_LAZY);
172     if (!d3d11_debug_module)
173       d3d11_debug_module =
174           g_module_open ("d3d11_2sdklayers.dll", G_MODULE_BIND_LAZY);
175     if (!d3d11_debug_module)
176       d3d11_debug_module =
177           g_module_open ("d3d11_3sdklayers.dll", G_MODULE_BIND_LAZY);
178
179     g_once_init_leave (&_init, 1);
180   }
181
182   if (d3d11_debug_module)
183     return TRUE;
184
185   return FALSE;
186 }
187
188 static inline GstDebugLevel
189 d3d11_message_severity_to_gst (D3D11_MESSAGE_SEVERITY level)
190 {
191   switch (level) {
192     case D3D11_MESSAGE_SEVERITY_CORRUPTION:
193     case D3D11_MESSAGE_SEVERITY_ERROR:
194       return GST_LEVEL_ERROR;
195     case D3D11_MESSAGE_SEVERITY_WARNING:
196       return GST_LEVEL_WARNING;
197     case D3D11_MESSAGE_SEVERITY_INFO:
198       return GST_LEVEL_INFO;
199     case D3D11_MESSAGE_SEVERITY_MESSAGE:
200       return GST_LEVEL_DEBUG;
201     default:
202       break;
203   }
204
205   return GST_LEVEL_LOG;
206 }
207
208 void
209 gst_d3d11_device_d3d11_debug (GstD3D11Device * device,
210     const gchar * file, const gchar * function, gint line)
211 {
212   GstD3D11DevicePrivate *priv = device->priv;
213   D3D11_MESSAGE *msg;
214   SIZE_T msg_len = 0;
215   HRESULT hr;
216   UINT64 num_msg, i;
217   ID3D11InfoQueue *info_queue = priv->d3d11_info_queue;
218
219   if (!info_queue)
220     return;
221
222   num_msg = info_queue->GetNumStoredMessages ();
223
224   for (i = 0; i < num_msg; i++) {
225     GstDebugLevel level;
226
227     hr = info_queue->GetMessage (i, NULL, &msg_len);
228
229     if (FAILED (hr) || msg_len == 0) {
230       return;
231     }
232
233     msg = (D3D11_MESSAGE *) g_alloca (msg_len);
234     hr = info_queue->GetMessage (i, msg, &msg_len);
235
236     level = d3d11_message_severity_to_gst (msg->Severity);
237     if (msg->Category == D3D11_MESSAGE_CATEGORY_STATE_CREATION &&
238         level > GST_LEVEL_ERROR) {
239       /* Do not warn for live object, since there would be live object
240        * when ReportLiveDeviceObjects was called */
241       level = GST_LEVEL_INFO;
242     }
243
244     gst_debug_log (gst_d3d11_debug_layer_debug, level, file, function, line,
245         G_OBJECT (device), "D3D11InfoQueue: %s", msg->pDescription);
246   }
247
248   info_queue->ClearStoredMessages ();
249
250   return;
251 }
252 #else
253 void
254 gst_d3d11_device_d3d11_debug (GstD3D11Device * device,
255     const gchar * file, const gchar * function, gint line)
256 {
257   /* do nothing */
258   return;
259 }
260 #endif
261
262 #if HAVE_DXGIDEBUG_H
263 static gboolean
264 gst_d3d11_device_enable_dxgi_debug (void)
265 {
266   static gsize _init = 0;
267   gboolean ret = FALSE;
268
269   /* If all below libraries are unavailable, d3d11 device would fail with
270    * D3D11_CREATE_DEVICE_DEBUG flag */
271   if (g_once_init_enter (&_init)) {
272 #if (!GST_D3D11_WINAPI_ONLY_APP)
273     dxgi_debug_module = g_module_open ("dxgidebug.dll", G_MODULE_BIND_LAZY);
274
275     if (dxgi_debug_module)
276       g_module_symbol (dxgi_debug_module,
277           "DXGIGetDebugInterface", (gpointer *) & GstDXGIGetDebugInterface);
278     if (GstDXGIGetDebugInterface)
279       ret = TRUE;
280 #elif (GST_D3D11_DXGI_HEADER_VERSION >= 3)
281     ret = TRUE;
282 #endif
283     g_once_init_leave (&_init, 1);
284   }
285
286   return ret;
287 }
288
289 static HRESULT
290 gst_d3d11_device_dxgi_get_device_interface (REFIID riid, void **debug)
291 {
292 #if (!GST_D3D11_WINAPI_ONLY_APP)
293   if (GstDXGIGetDebugInterface) {
294     return GstDXGIGetDebugInterface (riid, debug);
295   }
296 #elif (GST_D3D11_DXGI_HEADER_VERSION >= 3)
297   return DXGIGetDebugInterface1 (0, riid, debug);
298 #endif
299
300   return E_NOINTERFACE;
301 }
302
303 static inline GstDebugLevel
304 dxgi_info_queue_message_severity_to_gst (DXGI_INFO_QUEUE_MESSAGE_SEVERITY level)
305 {
306   switch (level) {
307     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION:
308     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR:
309       return GST_LEVEL_ERROR;
310     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING:
311       return GST_LEVEL_WARNING;
312     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_INFO:
313       return GST_LEVEL_INFO;
314     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_MESSAGE:
315       return GST_LEVEL_DEBUG;
316     default:
317       break;
318   }
319
320   return GST_LEVEL_LOG;
321 }
322
323 void
324 gst_d3d11_device_dxgi_debug (GstD3D11Device * device,
325     const gchar * file, const gchar * function, gint line)
326 {
327   GstD3D11DevicePrivate *priv = device->priv;
328   DXGI_INFO_QUEUE_MESSAGE *msg;
329   SIZE_T msg_len = 0;
330   HRESULT hr;
331   UINT64 num_msg, i;
332   IDXGIInfoQueue *info_queue = priv->dxgi_info_queue;
333
334   if (!info_queue)
335     return;
336
337   num_msg = info_queue->GetNumStoredMessages (DXGI_DEBUG_ALL);
338
339   for (i = 0; i < num_msg; i++) {
340     GstDebugLevel level;
341
342     hr = info_queue->GetMessage (DXGI_DEBUG_ALL, i, NULL, &msg_len);
343
344     if (FAILED (hr) || msg_len == 0) {
345       return;
346     }
347
348     msg = (DXGI_INFO_QUEUE_MESSAGE *) g_alloca (msg_len);
349     hr = info_queue->GetMessage (DXGI_DEBUG_ALL, i, msg, &msg_len);
350
351     level = dxgi_info_queue_message_severity_to_gst (msg->Severity);
352     gst_debug_log (gst_d3d11_debug_layer_debug, level, file, function, line,
353         G_OBJECT (device), "DXGIInfoQueue: %s", msg->pDescription);
354   }
355
356   info_queue->ClearStoredMessages (DXGI_DEBUG_ALL);
357
358   return;
359 }
360 #else
361 void
362 gst_d3d11_device_dxgi_debug (GstD3D11Device * device,
363     const gchar * file, const gchar * function, gint line)
364 {
365   /* do nothing */
366   return;
367 }
368 #endif
369
370 static void
371 gst_d3d11_device_class_init (GstD3D11DeviceClass * klass)
372 {
373   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
374   GParamFlags readable_flags =
375       (GParamFlags) (G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
376
377   gobject_class->get_property = gst_d3d11_device_get_property;
378   gobject_class->dispose = gst_d3d11_device_dispose;
379   gobject_class->finalize = gst_d3d11_device_finalize;
380
381   g_object_class_install_property (gobject_class, PROP_ADAPTER,
382       g_param_spec_uint ("adapter", "Adapter",
383           "DXGI Adapter index for creating device",
384           0, G_MAXUINT32, DEFAULT_ADAPTER, readable_flags));
385
386   g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
387       g_param_spec_uint ("device-id", "Device Id",
388           "DXGI Device ID", 0, G_MAXUINT32, 0, readable_flags));
389
390   g_object_class_install_property (gobject_class, PROP_VENDOR_ID,
391       g_param_spec_uint ("vendor-id", "Vendor Id",
392           "DXGI Vendor ID", 0, G_MAXUINT32, 0, readable_flags));
393
394   g_object_class_install_property (gobject_class, PROP_HARDWARE,
395       g_param_spec_boolean ("hardware", "Hardware",
396           "Whether hardware device or not", TRUE, readable_flags));
397
398   g_object_class_install_property (gobject_class, PROP_DESCRIPTION,
399       g_param_spec_string ("description", "Description",
400           "Human readable device description", NULL, readable_flags));
401
402   g_object_class_install_property (gobject_class, PROP_ADAPTER_LUID,
403       g_param_spec_int64 ("adapter-luid", "Adapter LUID",
404           "DXGI Adapter LUID (Locally Unique Identifier) of created device",
405           G_MININT64, G_MAXINT64, 0, readable_flags));
406
407   gst_d3d11_memory_init_once ();
408 }
409
410 static void
411 gst_d3d11_device_init (GstD3D11Device * self)
412 {
413   GstD3D11DevicePrivate *priv;
414
415   priv = (GstD3D11DevicePrivate *)
416       gst_d3d11_device_get_instance_private (self);
417   priv->adapter = DEFAULT_ADAPTER;
418
419   g_rec_mutex_init (&priv->extern_lock);
420   g_mutex_init (&priv->resource_lock);
421
422   self->priv = priv;
423 }
424
425 static gboolean
426 is_windows_8_or_greater (void)
427 {
428   static gsize version_once = 0;
429   static gboolean ret = FALSE;
430
431   if (g_once_init_enter (&version_once)) {
432 #if (!GST_D3D11_WINAPI_ONLY_APP)
433     if (IsWindows8OrGreater ())
434       ret = TRUE;
435 #else
436     ret = TRUE;
437 #endif
438
439     g_once_init_leave (&version_once, 1);
440   }
441
442   return ret;
443 }
444
445 inline D3D11_FORMAT_SUPPORT
446 operator | (D3D11_FORMAT_SUPPORT lhs, D3D11_FORMAT_SUPPORT rhs)
447 {
448   return static_cast < D3D11_FORMAT_SUPPORT > (static_cast < UINT >
449       (lhs) | static_cast < UINT > (rhs));
450 }
451
452 inline D3D11_FORMAT_SUPPORT
453 operator |= (D3D11_FORMAT_SUPPORT lhs, D3D11_FORMAT_SUPPORT rhs)
454 {
455   return lhs | rhs;
456 }
457
458 static gboolean
459 can_support_format (GstD3D11Device * self, DXGI_FORMAT format,
460     D3D11_FORMAT_SUPPORT extra_flags)
461 {
462   GstD3D11DevicePrivate *priv = self->priv;
463   ID3D11Device *handle = priv->device;
464   HRESULT hr;
465   UINT supported;
466   D3D11_FORMAT_SUPPORT flags = D3D11_FORMAT_SUPPORT_TEXTURE2D;
467
468   flags |= extra_flags;
469
470   if (!is_windows_8_or_greater ()) {
471     GST_INFO_OBJECT (self, "DXGI format %d needs Windows 8 or greater",
472         (guint) format);
473     return FALSE;
474   }
475
476   hr = handle->CheckFormatSupport (format, &supported);
477   if (FAILED (hr)) {
478     GST_DEBUG_OBJECT (self, "DXGI format %d is not supported by device",
479         (guint) format);
480     return FALSE;
481   }
482
483   if ((supported & flags) != flags) {
484     GST_DEBUG_OBJECT (self,
485         "DXGI format %d doesn't support flag 0x%x (supported flag 0x%x)",
486         (guint) format, (guint) supported, (guint) flags);
487     return FALSE;
488   }
489
490   GST_INFO_OBJECT (self, "Device supports DXGI format %d", (guint) format);
491
492   return TRUE;
493 }
494
495 static void
496 gst_d3d11_device_setup_format_table (GstD3D11Device * self)
497 {
498   GstD3D11DevicePrivate *priv = self->priv;
499   guint n_formats = 0;
500
501   /* RGB formats */
502   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_BGRA;
503   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
504   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM;
505   n_formats++;
506
507   /* Identical to BGRA, but alpha will be ignored */
508   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_BGRx;
509   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
510   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM;
511   n_formats++;
512
513   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_RGBA;
514   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
515   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R8G8B8A8_UNORM;
516   n_formats++;
517
518   /* Identical to RGBA, but alpha will be ignored */
519   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_RGBx;
520   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
521   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R8G8B8A8_UNORM;
522   n_formats++;
523
524   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_RGB10A2_LE;
525   priv->format_table[n_formats].resource_format[0] =
526       DXGI_FORMAT_R10G10B10A2_UNORM;
527   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R10G10B10A2_UNORM;
528   n_formats++;
529
530   /* YUV packed */
531   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_VUYA;
532   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
533   if (can_support_format (self, DXGI_FORMAT_AYUV,
534           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
535           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
536     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_AYUV;
537   else
538     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
539   n_formats++;
540
541   /* FIXME: d3d11 sampler doesn't support packed-and-subsampled formats
542    * very well (and it's really poorly documented).
543    * As per observation, d3d11 samplers seems to be dropping the second
544    * Y componet from "Y0-U0-Y1-V0" pair which results in bad visual quality
545    * than 4:2:0 subsampled formats. We should revisit this later */
546
547   /* TODO: The best would be using d3d11 compute shader to handle this kinds of
548    * samples but comute shader is not implemented yet by us.
549    *
550    * Another simple approach is using d3d11 video processor,
551    * but capability will be very device dependent because it depends on
552    * GPU vendor's driver implementation, moreover, software fallback does
553    * not support d3d11 video processor. So it's not reliable in this case */
554 #if 0
555   /* NOTE: packted yuv 4:2:2 YUY2, UYVY, and VYUY formats are not natively
556    * supported render target view formats
557    * (i.e., cannot be output format of shader pipeline) */
558   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_YUY2;
559   if (can_support_format (self, DXGI_FORMAT_YUY2,
560           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) {
561     priv->format_table[n_formats].resource_format[0] =
562         DXGI_FORMAT_R8G8B8A8_UNORM;
563     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_YUY2;
564   } else {
565     /* If DXGI_FORMAT_YUY2 format is not supported, use this format,
566      * it's analogous to YUY2 */
567     priv->format_table[n_formats].resource_format[0] =
568         DXGI_FORMAT_G8R8_G8B8_UNORM;
569   }
570   n_formats++;
571
572   /* No native DXGI format available for UYVY */
573   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_UYVY;
574   priv->format_table[n_formats].resource_format[0] =
575       DXGI_FORMAT_R8G8_B8G8_UNORM;
576   n_formats++;
577
578   /* No native DXGI format available for VYUY */
579   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_VYUY;
580   priv->format_table[n_formats].resource_format[0] =
581       DXGI_FORMAT_R8G8_B8G8_UNORM;
582   n_formats++;
583
584   /* Y210 and Y410 formats cannot support rtv */
585   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y210;
586   priv->format_table[n_formats].resource_format[0] =
587       DXGI_FORMAT_R16G16B16A16_UNORM;
588   if (can_support_format (self, DXGI_FORMAT_Y210,
589           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
590     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_Y210;
591   else
592     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
593   n_formats++;
594 #endif
595
596   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y410;
597   priv->format_table[n_formats].resource_format[0] =
598       DXGI_FORMAT_R10G10B10A2_UNORM;
599   if (can_support_format (self, DXGI_FORMAT_Y410,
600           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
601     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_Y410;
602   else
603     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
604   n_formats++;
605
606   /* YUV semi-planar */
607   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_NV12;
608   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
609   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8G8_UNORM;
610   if (can_support_format (self, DXGI_FORMAT_NV12,
611           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
612           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
613     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_NV12;
614   else
615     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
616   n_formats++;
617
618   /* no native format for NV21 */
619   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_NV21;
620   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
621   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8G8_UNORM;
622   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
623   n_formats++;
624
625   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_P010_10LE;
626   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
627   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
628   if (can_support_format (self, DXGI_FORMAT_P010,
629           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
630           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
631     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_P010;
632   else
633     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
634   n_formats++;
635
636   /* P012 is identical to P016 from runtime point of view */
637   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_P012_LE;
638   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
639   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
640   if (can_support_format (self, DXGI_FORMAT_P016,
641           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
642           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
643     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_P016;
644   else
645     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
646   n_formats++;
647
648   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_P016_LE;
649   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
650   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
651   if (can_support_format (self, DXGI_FORMAT_P016,
652           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
653           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
654     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_P016;
655   else
656     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
657   n_formats++;
658
659   /* YUV planar */
660   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I420;
661   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
662   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8_UNORM;
663   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R8_UNORM;
664   n_formats++;
665
666   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_YV12;
667   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
668   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8_UNORM;
669   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R8_UNORM;
670   n_formats++;
671
672   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I420_10LE;
673   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
674   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
675   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
676   n_formats++;
677
678   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I420_12LE;
679   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
680   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
681   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
682   n_formats++;
683
684   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y42B;
685   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
686   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8_UNORM;
687   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R8_UNORM;
688   n_formats++;
689
690   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I422_10LE;
691   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
692   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
693   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
694   n_formats++;
695
696   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I422_12LE;
697   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
698   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
699   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
700   n_formats++;
701
702   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y444;
703   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
704   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8_UNORM;
705   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R8_UNORM;
706   n_formats++;
707
708   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y444_10LE;
709   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
710   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
711   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
712   n_formats++;
713
714   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y444_12LE;
715   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
716   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
717   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
718   n_formats++;
719
720   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y444_16LE;
721   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
722   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
723   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
724   n_formats++;
725
726   /* GRAY */
727   /* NOTE: To support conversion by using video processor,
728    * mark DXGI_FORMAT_{R8,R16}_UNORM formats as known dxgi_format.
729    * Otherwise, d3d11 elements will not try to use video processor for
730    * those formats */
731   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_GRAY8;
732   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
733   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R8_UNORM;
734   n_formats++;
735
736   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_GRAY16_LE;
737   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
738   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R16_UNORM;
739   n_formats++;
740
741   g_assert (n_formats == GST_D3D11_N_FORMATS);
742 }
743
744 static void
745 gst_d3d11_device_get_property (GObject * object, guint prop_id,
746     GValue * value, GParamSpec * pspec)
747 {
748   GstD3D11Device *self = GST_D3D11_DEVICE (object);
749   GstD3D11DevicePrivate *priv = self->priv;
750
751   switch (prop_id) {
752     case PROP_ADAPTER:
753       g_value_set_uint (value, priv->adapter);
754       break;
755     case PROP_DEVICE_ID:
756       g_value_set_uint (value, priv->device_id);
757       break;
758     case PROP_VENDOR_ID:
759       g_value_set_uint (value, priv->vendor_id);
760       break;
761     case PROP_HARDWARE:
762       g_value_set_boolean (value, priv->hardware);
763       break;
764     case PROP_DESCRIPTION:
765       g_value_set_string (value, priv->description);
766       break;
767     case PROP_ADAPTER_LUID:
768       g_value_set_int64 (value, priv->adapter_luid);
769       break;
770     default:
771       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
772       break;
773   }
774 }
775
776 static void
777 gst_d3d11_device_dispose (GObject * object)
778 {
779   GstD3D11Device *self = GST_D3D11_DEVICE (object);
780   GstD3D11DevicePrivate *priv = self->priv;
781
782   GST_LOG_OBJECT (self, "dispose");
783
784   GST_D3D11_CLEAR_COM (priv->video_device);
785   GST_D3D11_CLEAR_COM (priv->video_context);
786   GST_D3D11_CLEAR_COM (priv->device);
787   GST_D3D11_CLEAR_COM (priv->device_context);
788   GST_D3D11_CLEAR_COM (priv->factory);
789 #if HAVE_D3D11SDKLAYERS_H
790   if (priv->d3d11_debug) {
791     priv->d3d11_debug->ReportLiveDeviceObjects ((D3D11_RLDO_FLAGS)
792         GST_D3D11_RLDO_FLAGS);
793   }
794   GST_D3D11_CLEAR_COM (priv->d3d11_debug);
795
796   if (priv->d3d11_info_queue)
797     gst_d3d11_device_d3d11_debug (self, __FILE__, GST_FUNCTION, __LINE__);
798
799   GST_D3D11_CLEAR_COM (priv->d3d11_info_queue);
800 #endif
801
802 #if HAVE_DXGIDEBUG_H
803   if (priv->dxgi_debug) {
804     priv->dxgi_debug->ReportLiveObjects (DXGI_DEBUG_ALL,
805         (DXGI_DEBUG_RLO_FLAGS) GST_D3D11_RLDO_FLAGS);
806   }
807   GST_D3D11_CLEAR_COM (priv->dxgi_debug);
808
809   if (priv->dxgi_info_queue)
810     gst_d3d11_device_dxgi_debug (self, __FILE__, GST_FUNCTION, __LINE__);
811
812   GST_D3D11_CLEAR_COM (priv->dxgi_info_queue);
813 #endif
814
815   G_OBJECT_CLASS (parent_class)->dispose (object);
816 }
817
818 static void
819 gst_d3d11_device_finalize (GObject * object)
820 {
821   GstD3D11Device *self = GST_D3D11_DEVICE (object);
822   GstD3D11DevicePrivate *priv = self->priv;
823
824   GST_LOG_OBJECT (self, "finalize");
825
826   g_rec_mutex_clear (&priv->extern_lock);
827   g_mutex_clear (&priv->resource_lock);
828   g_free (priv->description);
829
830   G_OBJECT_CLASS (parent_class)->finalize (object);
831 }
832
833 typedef enum
834 {
835   DEVICE_CONSTRUCT_FOR_ADAPTER_INDEX,
836   DEVICE_CONSTRUCT_FOR_ADAPTER_LUID,
837   DEVICE_CONSTRUCT_WRAPPED,
838 } GstD3D11DeviceConstructType;
839
840 typedef struct _GstD3D11DeviceConstructData
841 {
842   union
843   {
844     guint adapter_index;
845     gint64 adapter_luid;
846     ID3D11Device *device;
847   } data;
848   GstD3D11DeviceConstructType type;
849   UINT create_flags;
850 } GstD3D11DeviceConstructData;
851
852 static HRESULT
853 _gst_d3d11_device_get_adapter (const GstD3D11DeviceConstructData * data,
854     IDXGIFactory1 * factory, guint * index, DXGI_ADAPTER_DESC * adapter_desc,
855     IDXGIAdapter1 ** dxgi_adapter)
856 {
857   HRESULT hr = S_OK;
858   ComPtr < IDXGIAdapter1 > adapter1;
859   DXGI_ADAPTER_DESC desc;
860
861   switch (data->type) {
862     case DEVICE_CONSTRUCT_FOR_ADAPTER_INDEX:
863     {
864       hr = factory->EnumAdapters1 (data->data.adapter_index, &adapter1);
865       if (FAILED (hr))
866         return hr;
867
868       hr = adapter1->GetDesc (&desc);
869       if (FAILED (hr))
870         return hr;
871
872       *index = data->data.adapter_index;
873       *adapter_desc = desc;
874       *dxgi_adapter = adapter1.Detach ();
875
876       return S_OK;
877     }
878     case DEVICE_CONSTRUCT_FOR_ADAPTER_LUID:
879     {
880       for (guint i = 0;; i++) {
881         gint64 luid;
882
883         adapter1 = nullptr;
884
885         hr = factory->EnumAdapters1 (i, &adapter1);
886         if (FAILED (hr))
887           return hr;
888
889         hr = adapter1->GetDesc (&desc);
890         if (FAILED (hr))
891           continue;
892
893         luid = gst_d3d11_luid_to_int64 (&desc.AdapterLuid);
894         if (luid != data->data.adapter_luid)
895           continue;
896
897         *index = i;
898         *adapter_desc = desc;
899         *dxgi_adapter = adapter1.Detach ();
900
901         return S_OK;
902       }
903
904       return E_FAIL;
905     }
906     case DEVICE_CONSTRUCT_WRAPPED:
907     {
908       ComPtr < IDXGIDevice > dxgi_device;
909       ComPtr < IDXGIAdapter > adapter;
910       ID3D11Device *device = data->data.device;
911       guint luid;
912
913       hr = device->QueryInterface (IID_PPV_ARGS (&dxgi_device));
914       if (FAILED (hr))
915         return hr;
916
917       hr = dxgi_device->GetAdapter (&adapter);
918       if (FAILED (hr))
919         return hr;
920
921       hr = adapter.As (&adapter1);
922       if (FAILED (hr))
923         return hr;
924
925       hr = adapter1->GetDesc (&desc);
926       if (FAILED (hr))
927         return hr;
928
929       luid = gst_d3d11_luid_to_int64 (&desc.AdapterLuid);
930
931       for (guint i = 0;; i++) {
932         DXGI_ADAPTER_DESC tmp_desc;
933         ComPtr < IDXGIAdapter1 > tmp;
934
935         hr = factory->EnumAdapters1 (i, &tmp);
936         if (FAILED (hr))
937           return hr;
938
939         hr = tmp->GetDesc (&tmp_desc);
940         if (FAILED (hr))
941           continue;
942
943         if (luid != gst_d3d11_luid_to_int64 (&tmp_desc.AdapterLuid))
944           continue;
945
946         *index = i;
947         *adapter_desc = desc;
948         *dxgi_adapter = adapter1.Detach ();
949
950         return S_OK;
951       }
952
953       return E_FAIL;
954     }
955     default:
956       g_assert_not_reached ();
957       break;
958   }
959
960   return E_FAIL;
961 }
962
963 static void
964 gst_d3d11_device_setup_debug_layer (GstD3D11Device * self)
965 {
966 #if HAVE_DXGIDEBUG_H
967   if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) >
968       GST_LEVEL_ERROR) {
969     GstD3D11DevicePrivate *priv = self->priv;
970
971     if (gst_d3d11_device_enable_dxgi_debug ()) {
972       IDXGIDebug *debug = nullptr;
973       IDXGIInfoQueue *info_queue = nullptr;
974       HRESULT hr;
975
976       GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
977           "dxgi debug library was loaded");
978       hr = gst_d3d11_device_dxgi_get_device_interface (IID_PPV_ARGS (&debug));
979
980       if (SUCCEEDED (hr)) {
981         GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
982             "IDXGIDebug interface available");
983         priv->dxgi_debug = debug;
984
985         hr = gst_d3d11_device_dxgi_get_device_interface (IID_PPV_ARGS
986             (&info_queue));
987         if (SUCCEEDED (hr)) {
988           GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
989               "IDXGIInfoQueue interface available");
990           priv->dxgi_info_queue = info_queue;
991         }
992       }
993     } else {
994       GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
995           "couldn't load dxgi debug library");
996     }
997   }
998 #endif
999
1000 #if HAVE_D3D11SDKLAYERS_H
1001   if ((self->priv->create_flags & D3D11_CREATE_DEVICE_DEBUG) != 0) {
1002     GstD3D11DevicePrivate *priv = self->priv;
1003     ID3D11Debug *debug;
1004     ID3D11InfoQueue *info_queue;
1005     HRESULT hr;
1006
1007     hr = priv->device->QueryInterface (IID_PPV_ARGS (&debug));
1008
1009     if (SUCCEEDED (hr)) {
1010       GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
1011           "D3D11Debug interface available");
1012       priv->d3d11_debug = debug;
1013
1014       hr = priv->device->QueryInterface (IID_PPV_ARGS (&info_queue));
1015       if (SUCCEEDED (hr)) {
1016         GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
1017             "ID3D11InfoQueue interface available");
1018         priv->d3d11_info_queue = info_queue;
1019       }
1020     }
1021   }
1022 #endif
1023 }
1024
1025 static GstD3D11Device *
1026 gst_d3d11_device_new_internal (const GstD3D11DeviceConstructData * data)
1027 {
1028   ComPtr < IDXGIAdapter1 > adapter;
1029   ComPtr < IDXGIFactory1 > factory;
1030   ComPtr < ID3D11Device > device;
1031   ComPtr < ID3D11DeviceContext > device_context;
1032   HRESULT hr;
1033   UINT create_flags;
1034   guint adapter_index = 0;
1035   DXGI_ADAPTER_DESC adapter_desc;
1036   static const D3D_FEATURE_LEVEL feature_levels[] = {
1037     D3D_FEATURE_LEVEL_11_1,
1038     D3D_FEATURE_LEVEL_11_0,
1039     D3D_FEATURE_LEVEL_10_1,
1040     D3D_FEATURE_LEVEL_10_0,
1041     D3D_FEATURE_LEVEL_9_3,
1042     D3D_FEATURE_LEVEL_9_2,
1043     D3D_FEATURE_LEVEL_9_1
1044   };
1045   D3D_FEATURE_LEVEL selected_level;
1046
1047   debug_init_once ();
1048
1049   hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory));
1050   if (!gst_d3d11_result (hr, NULL)) {
1051     GST_ERROR ("cannot create dxgi factory, hr: 0x%x", (guint) hr);
1052     return nullptr;
1053   }
1054
1055   create_flags = 0;
1056   if (data->type != DEVICE_CONSTRUCT_WRAPPED) {
1057     create_flags = data->create_flags;
1058 #if HAVE_D3D11SDKLAYERS_H
1059     if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) >
1060         GST_LEVEL_ERROR) {
1061       /* DirectX SDK should be installed on system for this */
1062       if (gst_d3d11_device_enable_d3d11_debug ()) {
1063         GST_CAT_INFO (gst_d3d11_debug_layer_debug,
1064             "d3d11 debug library was loaded");
1065         create_flags |= D3D11_CREATE_DEVICE_DEBUG;
1066       } else {
1067         GST_CAT_INFO (gst_d3d11_debug_layer_debug,
1068             "couldn't load d3d11 debug library");
1069       }
1070     }
1071 #endif
1072   }
1073
1074   /* Ensure valid device handle */
1075   if (data->type == DEVICE_CONSTRUCT_WRAPPED) {
1076     ID3D11Device *external_device = data->data.device;
1077
1078     hr = external_device->QueryInterface (IID_PPV_ARGS (&device));
1079     if (FAILED (hr)) {
1080       GST_ERROR ("Not a valid external ID3D11Device handle");
1081       return nullptr;
1082     }
1083
1084     device->GetImmediateContext (&device_context);
1085   }
1086
1087   hr = _gst_d3d11_device_get_adapter (data, factory.Get (), &adapter_index,
1088       &adapter_desc, &adapter);
1089   if (FAILED (hr)) {
1090     GST_INFO ("Failed to get DXGI adapter");
1091     return nullptr;
1092   }
1093
1094   if (data->type != DEVICE_CONSTRUCT_WRAPPED) {
1095     hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN,
1096         NULL, create_flags, feature_levels, G_N_ELEMENTS (feature_levels),
1097         D3D11_SDK_VERSION, &device, &selected_level, &device_context);
1098
1099     if (FAILED (hr)) {
1100       /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
1101       hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN,
1102           NULL, create_flags, &feature_levels[1],
1103           G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &device,
1104           &selected_level, &device_context);
1105     }
1106
1107     /* if D3D11_CREATE_DEVICE_DEBUG was enabled but couldn't create device,
1108      * try it without the flag again */
1109     if (FAILED (hr) && (create_flags & D3D11_CREATE_DEVICE_DEBUG) != 0) {
1110       create_flags &= ~D3D11_CREATE_DEVICE_DEBUG;
1111
1112       hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN,
1113           NULL, create_flags, feature_levels, G_N_ELEMENTS (feature_levels),
1114           D3D11_SDK_VERSION, &device, &selected_level, &device_context);
1115
1116       if (FAILED (hr)) {
1117         /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
1118         hr = D3D11CreateDevice (adapter.Get (), D3D_DRIVER_TYPE_UNKNOWN,
1119             NULL, create_flags, &feature_levels[1],
1120             G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &device,
1121             &selected_level, &device_context);
1122       }
1123     }
1124   }
1125
1126   if (FAILED (hr)) {
1127     switch (data->type) {
1128       case DEVICE_CONSTRUCT_FOR_ADAPTER_INDEX:
1129       {
1130         GST_INFO ("Failed to create d3d11 device for adapter index %d"
1131             " with flags 0x%x, hr: 0x%x", data->data.adapter_index,
1132             create_flags, (guint) hr);
1133         return nullptr;
1134       }
1135       case DEVICE_CONSTRUCT_FOR_ADAPTER_LUID:
1136       {
1137         GST_ERROR ("Failed to create d3d11 device for adapter luid %"
1138             G_GINT64_FORMAT " with flags 0x%x, hr: 0x%x",
1139             data->data.adapter_luid, create_flags, (guint) hr);
1140         return nullptr;
1141       }
1142       default:
1143         break;
1144     }
1145
1146     return nullptr;
1147   }
1148
1149   GstD3D11Device *self = nullptr;
1150   GstD3D11DevicePrivate *priv;
1151
1152   self = (GstD3D11Device *) g_object_new (GST_TYPE_D3D11_DEVICE, nullptr);
1153   gst_object_ref_sink (self);
1154
1155   priv = self->priv;
1156
1157   priv->adapter = adapter_index;
1158   priv->device = device.Detach ();
1159   priv->device_context = device_context.Detach ();
1160   priv->factory = factory.Detach ();
1161
1162   priv->vendor_id = adapter_desc.VendorId;
1163   priv->device_id = adapter_desc.DeviceId;
1164   priv->description = g_utf16_to_utf8 ((gunichar2 *) adapter_desc.Description,
1165       -1, nullptr, nullptr, nullptr);
1166   priv->adapter_luid = gst_d3d11_luid_to_int64 (&adapter_desc.AdapterLuid);
1167
1168   DXGI_ADAPTER_DESC1 desc1;
1169   hr = adapter->GetDesc1 (&desc1);
1170
1171   /* DXGI_ADAPTER_FLAG_SOFTWARE is missing in dxgi.h of mingw */
1172   if (SUCCEEDED (hr) && (desc1.Flags & 0x2) != 0x2)
1173     priv->hardware = TRUE;
1174
1175   priv->create_flags = create_flags;
1176   gst_d3d11_device_setup_format_table (self);
1177   gst_d3d11_device_setup_debug_layer (self);
1178
1179   return self;
1180 }
1181
1182 /**
1183  * gst_d3d11_device_new:
1184  * @adapter_index: the index of adapter for creating d3d11 device
1185  * @flags: a D3D11_CREATE_DEVICE_FLAG value used for creating d3d11 device
1186  *
1187  * Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter_index
1188  * or %NULL when failed to create D3D11 device with given adapter index.
1189  *
1190  * Since: 1.20
1191  */
1192 GstD3D11Device *
1193 gst_d3d11_device_new (guint adapter_index, guint flags)
1194 {
1195   GstD3D11DeviceConstructData data;
1196
1197   data.data.adapter_index = adapter_index;
1198   data.type = DEVICE_CONSTRUCT_FOR_ADAPTER_INDEX;
1199   data.create_flags = flags;
1200
1201   return gst_d3d11_device_new_internal (&data);
1202 }
1203
1204 /**
1205  * gst_d3d11_device_new_for_adapter_luid:
1206  * @adapter_luid: an int64 representation of the DXGI adapter LUID
1207  * @flags: a D3D11_CREATE_DEVICE_FLAG value used for creating d3d11 device
1208  *
1209  * Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter_luid
1210  * or %NULL when failed to create D3D11 device with given adapter luid.
1211  *
1212  * Since: 1.20
1213  */
1214 GstD3D11Device *
1215 gst_d3d11_device_new_for_adapter_luid (gint64 adapter_luid, guint flags)
1216 {
1217   GstD3D11DeviceConstructData data;
1218
1219   data.data.adapter_luid = adapter_luid;
1220   data.type = DEVICE_CONSTRUCT_FOR_ADAPTER_LUID;
1221   data.create_flags = flags;
1222
1223   return gst_d3d11_device_new_internal (&data);
1224 }
1225
1226 /**
1227  * gst_d3d11_device_new_wrapped:
1228  * @device: (transfer none): an existing ID3D11Device handle
1229  *
1230  * Returns: (transfer full) (nullable): a new #GstD3D11Device for @device
1231  * or %NULL if an error occurred
1232  *
1233  * Since: 1.20
1234  */
1235 GstD3D11Device *
1236 gst_d3d11_device_new_wrapped (ID3D11Device * device)
1237 {
1238   GstD3D11DeviceConstructData data;
1239
1240   g_return_val_if_fail (device != nullptr, nullptr);
1241
1242   data.data.device = device;
1243   data.type = DEVICE_CONSTRUCT_WRAPPED;
1244   data.create_flags = 0;
1245
1246   return gst_d3d11_device_new_internal (&data);
1247 }
1248
1249 /**
1250  * gst_d3d11_device_get_device_handle:
1251  * @device: a #GstD3D11Device
1252  *
1253  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1254  * object.
1255  *
1256  * Returns: (transfer none): the ID3D11Device handle
1257  *
1258  * Since: 1.20
1259  */
1260 ID3D11Device *
1261 gst_d3d11_device_get_device_handle (GstD3D11Device * device)
1262 {
1263   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1264
1265   return device->priv->device;
1266 }
1267
1268 /**
1269  * gst_d3d11_device_get_device_context_handle:
1270  * @device: a #GstD3D11Device
1271  *
1272  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1273  * object. Any ID3D11DeviceContext call needs to be protected by
1274  * gst_d3d11_device_lock() and gst_d3d11_device_unlock() method.
1275  *
1276  * Returns: (transfer none): the immeidate ID3D11DeviceContext handle
1277  *
1278  * Since: 1.20
1279  */
1280 ID3D11DeviceContext *
1281 gst_d3d11_device_get_device_context_handle (GstD3D11Device * device)
1282 {
1283   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1284
1285   return device->priv->device_context;
1286 }
1287
1288 /**
1289  * gst_d3d11_device_get_dxgi_factory_handle:
1290  * @device: a #GstD3D11Device
1291  *
1292  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1293  * object.
1294  *
1295  * Returns: (transfer none): the IDXGIFactory1 handle
1296  *
1297  * Since: 1.20
1298  */
1299 IDXGIFactory1 *
1300 gst_d3d11_device_get_dxgi_factory_handle (GstD3D11Device * device)
1301 {
1302   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1303
1304   return device->priv->factory;
1305 }
1306
1307 /**
1308  * gst_d3d11_device_get_video_device_handle:
1309  * @device: a #GstD3D11Device
1310  *
1311  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1312  * object.
1313  *
1314  * Returns: (nullable) (transfer none) : the ID3D11VideoDevice handle or %NULL
1315  * if ID3D11VideoDevice is unavailable.
1316  *
1317  * Since: 1.20
1318  */
1319 ID3D11VideoDevice *
1320 gst_d3d11_device_get_video_device_handle (GstD3D11Device * device)
1321 {
1322   GstD3D11DevicePrivate *priv;
1323
1324   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1325
1326   priv = device->priv;
1327   g_mutex_lock (&priv->resource_lock);
1328   if (!priv->video_device) {
1329     HRESULT hr;
1330     ID3D11VideoDevice *video_device = NULL;
1331
1332     hr = priv->device->QueryInterface (IID_PPV_ARGS (&video_device));
1333     if (gst_d3d11_result (hr, device))
1334       priv->video_device = video_device;
1335   }
1336   g_mutex_unlock (&priv->resource_lock);
1337
1338   return priv->video_device;
1339 }
1340
1341 /**
1342  * gst_d3d11_device_get_video_context_handle:
1343  * @device: a #GstD3D11Device
1344  *
1345  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1346  * object.
1347  *
1348  * Returns: (nullable) (transfer none): the ID3D11VideoContext handle or %NULL
1349  * if ID3D11VideoContext is unavailable.
1350  *
1351  * Since: 1.20
1352  */
1353 ID3D11VideoContext *
1354 gst_d3d11_device_get_video_context_handle (GstD3D11Device * device)
1355 {
1356   GstD3D11DevicePrivate *priv;
1357
1358   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1359
1360   priv = device->priv;
1361   g_mutex_lock (&priv->resource_lock);
1362   if (!priv->video_context) {
1363     HRESULT hr;
1364     ID3D11VideoContext *video_context = NULL;
1365
1366     hr = priv->device_context->QueryInterface (IID_PPV_ARGS (&video_context));
1367     if (gst_d3d11_result (hr, device))
1368       priv->video_context = video_context;
1369   }
1370   g_mutex_unlock (&priv->resource_lock);
1371
1372   return priv->video_context;
1373 }
1374
1375 /**
1376  * gst_d3d11_device_lock:
1377  * @device: a #GstD3D11Device
1378  *
1379  * Take lock for @device. Any thread-unsafe API call needs to be
1380  * protected by this method. This call must be paired with
1381  * gst_d3d11_device_unlock()
1382  *
1383  * Since: 1.20
1384  */
1385 void
1386 gst_d3d11_device_lock (GstD3D11Device * device)
1387 {
1388   GstD3D11DevicePrivate *priv;
1389
1390   g_return_if_fail (GST_IS_D3D11_DEVICE (device));
1391
1392   priv = device->priv;
1393
1394   GST_TRACE_OBJECT (device, "device locking");
1395   g_rec_mutex_lock (&priv->extern_lock);
1396   GST_TRACE_OBJECT (device, "device locked");
1397 }
1398
1399 /**
1400  * gst_d3d11_device_unlock:
1401  * @device: a #GstD3D11Device
1402  *
1403  * Release lock for @device. This call must be paired with
1404  * gst_d3d11_device_lock()
1405  *
1406  * Since: 1.20
1407  */
1408 void
1409 gst_d3d11_device_unlock (GstD3D11Device * device)
1410 {
1411   GstD3D11DevicePrivate *priv;
1412
1413   g_return_if_fail (GST_IS_D3D11_DEVICE (device));
1414
1415   priv = device->priv;
1416
1417   g_rec_mutex_unlock (&priv->extern_lock);
1418   GST_TRACE_OBJECT (device, "device unlocked");
1419 }
1420
1421 /**
1422  * gst_d3d11_device_format_from_gst:
1423  * @device: a #GstD3D11Device
1424  * @format: a #GstVideoFormat
1425  *
1426  * Returns: (transfer none) (nullable): a pointer to #GstD3D11Format
1427  * or %NULL if @format is not supported by @device
1428  *
1429  * Since: 1.20
1430  */
1431 const GstD3D11Format *
1432 gst_d3d11_device_format_from_gst (GstD3D11Device * device,
1433     GstVideoFormat format)
1434 {
1435   GstD3D11DevicePrivate *priv;
1436   guint i;
1437
1438   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1439
1440   priv = device->priv;
1441
1442   for (i = 0; i < G_N_ELEMENTS (priv->format_table); i++) {
1443     if (priv->format_table[i].format == format)
1444       return &priv->format_table[i];
1445   }
1446
1447   return NULL;
1448 }