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