fd40ead5efe179900fdb2651d483dfbb1ce43d42
[platform/upstream/gstreamer.git] / gst-libs / gst / d3d11 / gstd3d11device.c
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 <gmodule.h>
30
31 #include <windows.h>
32 #include <versionhelpers.h>
33
34 /**
35  * SECTION:gstd3d11device
36  * @short_description: Direct3D11 device abstraction
37  * @title: GstD3D11Device
38  *
39  * #GstD3D11Device wraps ID3D11Device and ID3D11DeviceContext for GPU resources
40  * to be able to be shared among various elements. Caller can get native
41  * Direct3D11 handles via getter method.
42  * Basically Direct3D11 API doesn't require dedicated thread like that of
43  * OpenGL context, and ID3D11Device APIs are supposed to be thread-safe.
44  * But concurrent call for ID3D11DeviceContext and DXGI API are not allowed.
45  * To protect such object, callers need to make use of gst_d3d11_device_lock()
46  * and gst_d3d11_device_unlock()
47  */
48
49 #if HAVE_D3D11SDKLAYERS_H
50 #include <d3d11sdklayers.h>
51 static GModule *d3d11_debug_module = NULL;
52
53 /* mingw header does not define D3D11_RLDO_IGNORE_INTERNAL
54  * D3D11_RLDO_SUMMARY = 0x1,
55    D3D11_RLDO_DETAIL = 0x2,
56  * D3D11_RLDO_IGNORE_INTERNAL = 0x4
57  */
58 #define GST_D3D11_RLDO_FLAGS (0x2 | 0x4)
59 #endif
60
61 #if HAVE_DXGIDEBUG_H
62 #include <dxgidebug.h>
63 typedef HRESULT (WINAPI * DXGIGetDebugInterface_t) (REFIID riid,
64     void **ppDebug);
65 static GModule *dxgi_debug_module = NULL;
66 static DXGIGetDebugInterface_t GstDXGIGetDebugInterface = NULL;
67
68 #endif
69
70 #if (HAVE_D3D11SDKLAYERS_H || HAVE_DXGIDEBUG_H)
71 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_debug_layer_debug);
72 #endif
73 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_device_debug);
74 #define GST_CAT_DEFAULT gst_d3d11_device_debug
75
76 enum
77 {
78   PROP_0,
79   PROP_ADAPTER,
80   PROP_DEVICE_ID,
81   PROP_VENDOR_ID,
82   PROP_HARDWARE,
83   PROP_DESCRIPTION,
84   PROP_ALLOW_TEARING,
85   PROP_CREATE_FLAGS,
86   PROP_ADAPTER_LUID,
87 };
88
89 #define DEFAULT_ADAPTER 0
90 #define DEFAULT_CREATE_FLAGS 0
91
92 struct _GstD3D11DevicePrivate
93 {
94   guint adapter;
95   guint device_id;
96   guint vendor_id;
97   gboolean hardware;
98   gchar *description;
99   gboolean allow_tearing;
100   guint create_flags;
101   gint64 adapter_luid;
102
103   ID3D11Device *device;
104   ID3D11DeviceContext *device_context;
105
106   ID3D11VideoDevice *video_device;
107   ID3D11VideoContext *video_context;
108
109   IDXGIFactory1 *factory;
110   GstD3D11Format format_table[GST_D3D11_N_FORMATS];
111
112   GRecMutex extern_lock;
113   GMutex resource_lock;
114
115 #if HAVE_D3D11SDKLAYERS_H
116   ID3D11Debug *d3d11_debug;
117   ID3D11InfoQueue *d3d11_info_queue;
118 #endif
119
120 #if HAVE_DXGIDEBUG_H
121   IDXGIDebug *dxgi_debug;
122   IDXGIInfoQueue *dxgi_info_queue;
123 #endif
124 };
125
126 static void
127 do_debug_init (void)
128 {
129   GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug,
130       "d3d11device", 0, "d3d11 device object");
131 #if defined(HAVE_D3D11SDKLAYERS_H) || defined(HAVE_DXGIDEBUG_H)
132   GST_DEBUG_CATEGORY_INIT (gst_d3d11_debug_layer_debug,
133       "d3d11debuglayer", 0, "native d3d11 and dxgi debug");
134 #endif
135 }
136
137 #define gst_d3d11_device_parent_class parent_class
138 G_DEFINE_TYPE_WITH_CODE (GstD3D11Device, gst_d3d11_device, GST_TYPE_OBJECT,
139     G_ADD_PRIVATE (GstD3D11Device); do_debug_init ());
140
141 static void gst_d3d11_device_set_property (GObject * object, guint prop_id,
142     const GValue * value, GParamSpec * pspec);
143 static void gst_d3d11_device_get_property (GObject * object, guint prop_id,
144     GValue * value, GParamSpec * pspec);
145 static void gst_d3d11_device_constructed (GObject * object);
146 static void gst_d3d11_device_dispose (GObject * object);
147 static void gst_d3d11_device_finalize (GObject * object);
148
149 #if HAVE_D3D11SDKLAYERS_H
150 static gboolean
151 gst_d3d11_device_enable_d3d11_debug (void)
152 {
153   static volatile gsize _init = 0;
154
155   /* If all below libraries are unavailable, d3d11 device would fail with
156    * D3D11_CREATE_DEVICE_DEBUG flag */
157   if (g_once_init_enter (&_init)) {
158     d3d11_debug_module =
159         g_module_open ("d3d11sdklayers.dll", G_MODULE_BIND_LAZY);
160
161     if (!d3d11_debug_module)
162       d3d11_debug_module =
163           g_module_open ("d3d11_1sdklayers.dll", G_MODULE_BIND_LAZY);
164
165     g_once_init_leave (&_init, 1);
166   }
167
168   return ! !d3d11_debug_module;
169 }
170
171 static inline GstDebugLevel
172 d3d11_message_severity_to_gst (D3D11_MESSAGE_SEVERITY level)
173 {
174   switch (level) {
175     case D3D11_MESSAGE_SEVERITY_CORRUPTION:
176     case D3D11_MESSAGE_SEVERITY_ERROR:
177       return GST_LEVEL_ERROR;
178     case D3D11_MESSAGE_SEVERITY_WARNING:
179       return GST_LEVEL_WARNING;
180     case D3D11_MESSAGE_SEVERITY_INFO:
181       return GST_LEVEL_INFO;
182     case D3D11_MESSAGE_SEVERITY_MESSAGE:
183       return GST_LEVEL_DEBUG;
184     default:
185       break;
186   }
187
188   return GST_LEVEL_LOG;
189 }
190
191 void
192 gst_d3d11_device_d3d11_debug (GstD3D11Device * device,
193     const gchar * file, const gchar * function, gint line)
194 {
195   GstD3D11DevicePrivate *priv = device->priv;
196   D3D11_MESSAGE *msg;
197   SIZE_T msg_len = 0;
198   HRESULT hr;
199   UINT64 num_msg, i;
200
201   if (!priv->d3d11_info_queue)
202     return;
203
204   num_msg = ID3D11InfoQueue_GetNumStoredMessages (priv->d3d11_info_queue);
205
206   for (i = 0; i < num_msg; i++) {
207     GstDebugLevel level;
208
209     hr = ID3D11InfoQueue_GetMessage (priv->d3d11_info_queue, i, NULL, &msg_len);
210
211     if (FAILED (hr) || msg_len == 0) {
212       return;
213     }
214
215     msg = (D3D11_MESSAGE *) g_alloca (msg_len);
216     hr = ID3D11InfoQueue_GetMessage (priv->d3d11_info_queue, i, msg, &msg_len);
217
218     level = d3d11_message_severity_to_gst (msg->Severity);
219     if (msg->Category == D3D11_MESSAGE_CATEGORY_STATE_CREATION &&
220         level > GST_LEVEL_ERROR) {
221       /* Do not warn for live object, since there would be live object
222        * when ReportLiveDeviceObjects was called */
223       level = GST_LEVEL_INFO;
224     }
225
226     gst_debug_log (gst_d3d11_debug_layer_debug, level, file, function, line,
227         G_OBJECT (device), "D3D11InfoQueue: %s", msg->pDescription);
228   }
229
230   ID3D11InfoQueue_ClearStoredMessages (priv->d3d11_info_queue);
231
232   return;
233 }
234 #else
235 void
236 gst_d3d11_device_d3d11_debug (GstD3D11Device * device,
237     const gchar * file, const gchar * function, gint line)
238 {
239   /* do nothing */
240   return;
241 }
242 #endif
243
244 #if HAVE_DXGIDEBUG_H
245 static gboolean
246 gst_d3d11_device_enable_dxgi_debug (void)
247 {
248   static volatile gsize _init = 0;
249   gboolean ret = FALSE;
250
251   /* If all below libraries are unavailable, d3d11 device would fail with
252    * D3D11_CREATE_DEVICE_DEBUG flag */
253   if (g_once_init_enter (&_init)) {
254 #if (!GST_D3D11_WINAPI_ONLY_APP)
255     dxgi_debug_module = g_module_open ("dxgidebug.dll", G_MODULE_BIND_LAZY);
256
257     if (dxgi_debug_module)
258       g_module_symbol (dxgi_debug_module,
259           "DXGIGetDebugInterface", (gpointer *) & GstDXGIGetDebugInterface);
260     ret = ! !GstDXGIGetDebugInterface;
261 #elif (GST_D3D11_DXGI_HEADER_VERSION >= 3)
262     ret = TRUE;
263 #endif
264     g_once_init_leave (&_init, 1);
265   }
266
267   return ret;
268 }
269
270 static HRESULT
271 gst_d3d11_device_dxgi_get_device_interface (REFIID riid, void **debug)
272 {
273 #if (!GST_D3D11_WINAPI_ONLY_APP)
274   if (GstDXGIGetDebugInterface) {
275     return GstDXGIGetDebugInterface (riid, debug);
276   }
277 #elif (GST_D3D11_DXGI_HEADER_VERSION >= 3)
278   return DXGIGetDebugInterface1 (0, riid, debug);
279 #endif
280
281   return E_NOINTERFACE;
282 }
283
284 static inline GstDebugLevel
285 dxgi_info_queue_message_severity_to_gst (DXGI_INFO_QUEUE_MESSAGE_SEVERITY level)
286 {
287   switch (level) {
288     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION:
289     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR:
290       return GST_LEVEL_ERROR;
291     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING:
292       return GST_LEVEL_WARNING;
293     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_INFO:
294       return GST_LEVEL_INFO;
295     case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_MESSAGE:
296       return GST_LEVEL_DEBUG;
297     default:
298       break;
299   }
300
301   return GST_LEVEL_LOG;
302 }
303
304 void
305 gst_d3d11_device_dxgi_debug (GstD3D11Device * device,
306     const gchar * file, const gchar * function, gint line)
307 {
308   GstD3D11DevicePrivate *priv = device->priv;
309   DXGI_INFO_QUEUE_MESSAGE *msg;
310   SIZE_T msg_len = 0;
311   HRESULT hr;
312   UINT64 num_msg, i;
313
314   if (!priv->dxgi_info_queue)
315     return;
316
317   num_msg = IDXGIInfoQueue_GetNumStoredMessages (priv->dxgi_info_queue,
318       DXGI_DEBUG_ALL);
319
320   for (i = 0; i < num_msg; i++) {
321     GstDebugLevel level;
322
323     hr = IDXGIInfoQueue_GetMessage (priv->dxgi_info_queue,
324         DXGI_DEBUG_ALL, i, NULL, &msg_len);
325
326     if (FAILED (hr) || msg_len == 0) {
327       return;
328     }
329
330     msg = (DXGI_INFO_QUEUE_MESSAGE *) g_alloca (msg_len);
331     hr = IDXGIInfoQueue_GetMessage (priv->dxgi_info_queue,
332         DXGI_DEBUG_ALL, i, msg, &msg_len);
333
334     level = dxgi_info_queue_message_severity_to_gst (msg->Severity);
335     gst_debug_log (gst_d3d11_debug_layer_debug, level, file, function, line,
336         G_OBJECT (device), "DXGIInfoQueue: %s", msg->pDescription);
337   }
338
339   IDXGIInfoQueue_ClearStoredMessages (priv->dxgi_info_queue, DXGI_DEBUG_ALL);
340
341   return;
342 }
343 #else
344 void
345 gst_d3d11_device_dxgi_debug (GstD3D11Device * device,
346     const gchar * file, const gchar * function, gint line)
347 {
348   /* do nothing */
349   return;
350 }
351 #endif
352
353 static void
354 gst_d3d11_device_class_init (GstD3D11DeviceClass * klass)
355 {
356   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
357
358   gobject_class->set_property = gst_d3d11_device_set_property;
359   gobject_class->get_property = gst_d3d11_device_get_property;
360   gobject_class->constructed = gst_d3d11_device_constructed;
361   gobject_class->dispose = gst_d3d11_device_dispose;
362   gobject_class->finalize = gst_d3d11_device_finalize;
363
364   g_object_class_install_property (gobject_class, PROP_ADAPTER,
365       g_param_spec_uint ("adapter", "Adapter",
366           "DXGI Adapter index for creating device",
367           0, G_MAXUINT32, DEFAULT_ADAPTER,
368           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
369
370   g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
371       g_param_spec_uint ("device-id", "Device Id",
372           "DXGI Device ID", 0, G_MAXUINT32, 0,
373           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
374
375   g_object_class_install_property (gobject_class, PROP_VENDOR_ID,
376       g_param_spec_uint ("vendor-id", "Vendor Id",
377           "DXGI Vendor ID", 0, G_MAXUINT32, 0,
378           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
379
380   g_object_class_install_property (gobject_class, PROP_HARDWARE,
381       g_param_spec_boolean ("hardware", "Hardware",
382           "Whether hardware device or not", TRUE,
383           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
384
385   g_object_class_install_property (gobject_class, PROP_DESCRIPTION,
386       g_param_spec_string ("description", "Description",
387           "Human readable device description", NULL,
388           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
389
390   g_object_class_install_property (gobject_class, PROP_ALLOW_TEARING,
391       g_param_spec_boolean ("allow-tearing", "Allow tearing",
392           "Whether dxgi device supports allow-tearing feature or not", FALSE,
393           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
394
395   g_object_class_install_property (gobject_class, PROP_CREATE_FLAGS,
396       g_param_spec_uint ("create-flags", "Create flags",
397           "D3D11_CREATE_DEVICE_FLAG flags used for D3D11CreateDevice",
398           0, G_MAXUINT32, DEFAULT_CREATE_FLAGS,
399           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
400
401   g_object_class_install_property (gobject_class, PROP_ADAPTER_LUID,
402       g_param_spec_int64 ("adapter-luid", "Adapter LUID",
403           "DXGI Adapter LUID (Locally Unique Identifier) of created device",
404           0, G_MAXINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
405 }
406
407 static void
408 gst_d3d11_device_init (GstD3D11Device * self)
409 {
410   GstD3D11DevicePrivate *priv;
411
412   priv = gst_d3d11_device_get_instance_private (self);
413   priv->adapter = DEFAULT_ADAPTER;
414
415   g_rec_mutex_init (&priv->extern_lock);
416   g_mutex_init (&priv->resource_lock);
417
418   self->priv = priv;
419 }
420
421 static gboolean
422 is_windows_8_or_greater (void)
423 {
424   static gsize version_once = 0;
425   static gboolean ret = FALSE;
426
427   if (g_once_init_enter (&version_once)) {
428 #if (!GST_D3D11_WINAPI_ONLY_APP)
429     if (IsWindows8OrGreater ())
430       ret = TRUE;
431 #else
432     ret = TRUE;
433 #endif
434
435     g_once_init_leave (&version_once, 1);
436   }
437
438   return ret;
439 }
440
441 static gboolean
442 can_support_format (GstD3D11Device * self, DXGI_FORMAT format,
443     D3D11_FORMAT_SUPPORT extra_flags)
444 {
445   GstD3D11DevicePrivate *priv = self->priv;
446   ID3D11Device *handle = priv->device;
447   HRESULT hr;
448   UINT supported;
449   D3D11_FORMAT_SUPPORT flags = D3D11_FORMAT_SUPPORT_TEXTURE2D;
450
451   flags |= extra_flags;
452
453   if (!is_windows_8_or_greater ()) {
454     GST_INFO_OBJECT (self, "DXGI format %d needs Windows 8 or greater",
455         (guint) format);
456     return FALSE;
457   }
458
459   hr = ID3D11Device_CheckFormatSupport (handle, format, &supported);
460   if (FAILED (hr)) {
461     GST_DEBUG_OBJECT (self, "DXGI format %d is not supported by device",
462         (guint) format);
463     return FALSE;
464   }
465
466   if ((supported & flags) != flags) {
467     GST_DEBUG_OBJECT (self,
468         "DXGI format %d doesn't support flag 0x%x (supported flag 0x%x)",
469         (guint) format, (guint) supported, (guint) flags);
470     return FALSE;
471   }
472
473   GST_INFO_OBJECT (self, "Device supports DXGI format %d", (guint) format);
474
475   return TRUE;
476 }
477
478 static void
479 gst_d3d11_device_setup_format_table (GstD3D11Device * self)
480 {
481   GstD3D11DevicePrivate *priv = self->priv;
482   guint n_formats = 0;
483
484   /* RGB formats */
485   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_BGRA;
486   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
487   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM;
488   n_formats++;
489
490   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_RGBA;
491   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
492   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R8G8B8A8_UNORM;
493   n_formats++;
494
495   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_RGB10A2_LE;
496   priv->format_table[n_formats].resource_format[0] =
497       DXGI_FORMAT_R10G10B10A2_UNORM;
498   priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R10G10B10A2_UNORM;
499   n_formats++;
500
501   /* YUV packed */
502   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_VUYA;
503   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
504   if (can_support_format (self, DXGI_FORMAT_AYUV,
505           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
506           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
507     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_AYUV;
508   else
509     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
510   n_formats++;
511
512   /* NOTE: packted yuv 4:2:2 YUY2, UYVY, and VYUY formats are not natively
513    * supported render target view formats
514    * (i.e., cannot be output format of shader pipeline) */
515   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_YUY2;
516   if (can_support_format (self, DXGI_FORMAT_YUY2,
517           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) {
518     priv->format_table[n_formats].resource_format[0] =
519         DXGI_FORMAT_R8G8B8A8_UNORM;
520     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_YUY2;
521   } else {
522     /* If DXGI_FORMAT_YUY2 format is not supported, use this format,
523      * it's analogous to YUY2 */
524     priv->format_table[n_formats].resource_format[0] =
525         DXGI_FORMAT_G8R8_G8B8_UNORM;
526   }
527   n_formats++;
528
529   /* No native DXGI format available for UYVY */
530   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_UYVY;
531   priv->format_table[n_formats].resource_format[0] =
532       DXGI_FORMAT_R8G8_B8G8_UNORM;
533   n_formats++;
534
535   /* No native DXGI format available for VYUY */
536   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_VYUY;
537   priv->format_table[n_formats].resource_format[0] =
538       DXGI_FORMAT_R8G8_B8G8_UNORM;
539   n_formats++;
540
541   /* Y210 and Y410 formats cannot support rtv */
542   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y210;
543   priv->format_table[n_formats].resource_format[0] =
544       DXGI_FORMAT_R16G16B16A16_UNORM;
545   if (can_support_format (self, DXGI_FORMAT_Y210,
546           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
547     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_Y210;
548   else
549     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
550   n_formats++;
551
552   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y410;
553   priv->format_table[n_formats].resource_format[0] =
554       DXGI_FORMAT_R10G10B10A2_UNORM;
555   if (can_support_format (self, DXGI_FORMAT_Y410,
556           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
557     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_Y410;
558   else
559     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
560   n_formats++;
561
562   /* YUV semi-planar */
563   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_NV12;
564   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
565   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8G8_UNORM;
566   if (can_support_format (self, DXGI_FORMAT_NV12,
567           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
568           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
569     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_NV12;
570   else
571     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
572   n_formats++;
573
574   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_P010_10LE;
575   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
576   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
577   if (can_support_format (self, DXGI_FORMAT_P010,
578           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
579           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
580     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_P010;
581   else
582     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
583   n_formats++;
584
585   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_P016_LE;
586   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
587   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
588   if (can_support_format (self, DXGI_FORMAT_P016,
589           D3D11_FORMAT_SUPPORT_RENDER_TARGET |
590           D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
591     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_P016;
592   else
593     priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
594   n_formats++;
595
596   /* YUV planar */
597   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I420;
598   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
599   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8_UNORM;
600   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R8_UNORM;
601   n_formats++;
602
603   priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I420_10LE;
604   priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
605   priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
606   priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
607   n_formats++;
608
609   g_assert (n_formats == GST_D3D11_N_FORMATS);
610 }
611
612 static void
613 gst_d3d11_device_constructed (GObject * object)
614 {
615   GstD3D11Device *self = GST_D3D11_DEVICE (object);
616   GstD3D11DevicePrivate *priv = self->priv;
617   IDXGIAdapter1 *adapter = NULL;
618   IDXGIFactory1 *factory = NULL;
619   HRESULT hr;
620   UINT d3d11_flags = priv->create_flags;
621
622   static const D3D_FEATURE_LEVEL feature_levels[] = {
623     D3D_FEATURE_LEVEL_11_1,
624     D3D_FEATURE_LEVEL_11_0,
625     D3D_FEATURE_LEVEL_10_1,
626     D3D_FEATURE_LEVEL_10_0,
627     D3D_FEATURE_LEVEL_9_3,
628     D3D_FEATURE_LEVEL_9_2,
629     D3D_FEATURE_LEVEL_9_1
630   };
631   D3D_FEATURE_LEVEL selected_level;
632
633   GST_DEBUG_OBJECT (self,
634       "Built with DXGI header version %d", GST_D3D11_DXGI_HEADER_VERSION);
635
636 #if HAVE_DXGIDEBUG_H
637   if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) >
638       GST_LEVEL_NONE) {
639     if (gst_d3d11_device_enable_dxgi_debug ()) {
640       IDXGIDebug *debug = NULL;
641       IDXGIInfoQueue *info_queue = NULL;
642
643       GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
644           "dxgi debug library was loaded");
645       hr = gst_d3d11_device_dxgi_get_device_interface (&IID_IDXGIDebug,
646           (void **) &debug);
647
648       if (SUCCEEDED (hr)) {
649         GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
650             "IDXGIDebug interface available");
651         priv->dxgi_debug = debug;
652
653         hr = gst_d3d11_device_dxgi_get_device_interface (&IID_IDXGIInfoQueue,
654             (void **) &info_queue);
655         if (SUCCEEDED (hr)) {
656           GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
657               "IDXGIInfoQueue interface available");
658           priv->dxgi_info_queue = info_queue;
659         }
660       }
661     } else {
662       GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
663           "couldn't load dxgi debug library");
664     }
665   }
666 #endif
667
668 #if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
669   hr = CreateDXGIFactory1 (&IID_IDXGIFactory5, (void **) &factory);
670   if (!gst_d3d11_result (hr, NULL)) {
671     GST_INFO_OBJECT (self, "IDXGIFactory5 was unavailable");
672     factory = NULL;
673   } else {
674     BOOL allow_tearing;
675
676     hr = IDXGIFactory5_CheckFeatureSupport ((IDXGIFactory5 *) factory,
677         DXGI_FEATURE_PRESENT_ALLOW_TEARING, (void *) &allow_tearing,
678         sizeof (allow_tearing));
679
680     priv->allow_tearing = SUCCEEDED (hr) && allow_tearing;
681
682     hr = S_OK;
683   }
684 #endif
685
686   if (!factory) {
687     hr = CreateDXGIFactory1 (&IID_IDXGIFactory1, (void **) &factory);
688   }
689
690   if (!gst_d3d11_result (hr, NULL)) {
691     GST_ERROR_OBJECT (self, "cannot create dxgi factory, hr: 0x%x", (guint) hr);
692     goto error;
693   }
694
695   if (IDXGIFactory1_EnumAdapters1 (factory, priv->adapter,
696           &adapter) == DXGI_ERROR_NOT_FOUND) {
697     GST_DEBUG_OBJECT (self, "No adapter for index %d", priv->adapter);
698     goto error;
699   } else {
700     DXGI_ADAPTER_DESC1 desc;
701
702     hr = IDXGIAdapter1_GetDesc1 (adapter, &desc);
703     if (SUCCEEDED (hr)) {
704       gchar *description = NULL;
705       gboolean is_hardware = FALSE;
706       gint64 adapter_luid;
707
708       /* DXGI_ADAPTER_FLAG_SOFTWARE is missing in dxgi.h of mingw */
709       if ((desc.Flags & 0x2) != 0x2) {
710         is_hardware = TRUE;
711       }
712
713       adapter_luid = (((gint64) desc.AdapterLuid.HighPart) << 32) |
714           ((gint64) desc.AdapterLuid.LowPart);
715       description = g_utf16_to_utf8 (desc.Description, -1, NULL, NULL, NULL);
716       GST_DEBUG_OBJECT (self,
717           "adapter index %d: D3D11 device vendor-id: 0x%04x, device-id: 0x%04x, "
718           "Flags: 0x%x, adapter-luid: %" G_GINT64_FORMAT ", %s",
719           priv->adapter, desc.VendorId, desc.DeviceId, desc.Flags, adapter_luid,
720           description);
721
722       priv->vendor_id = desc.VendorId;
723       priv->device_id = desc.DeviceId;
724       priv->hardware = is_hardware;
725       priv->description = description;
726       priv->adapter_luid = adapter_luid;
727     }
728   }
729
730 #if HAVE_D3D11SDKLAYERS_H
731   if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) >
732       GST_LEVEL_NONE) {
733     /* DirectX SDK should be installed on system for this */
734     if (gst_d3d11_device_enable_d3d11_debug ()) {
735       GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
736           "d3d11 debug library was loaded");
737       d3d11_flags |= D3D11_CREATE_DEVICE_DEBUG;
738     } else {
739       GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
740           "couldn't load d3d11 debug library");
741     }
742   }
743 #endif
744
745   hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
746       NULL, d3d11_flags, feature_levels, G_N_ELEMENTS (feature_levels),
747       D3D11_SDK_VERSION, &priv->device, &selected_level, &priv->device_context);
748
749   if (!gst_d3d11_result (hr, NULL)) {
750     /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
751     hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
752         NULL, d3d11_flags, &feature_levels[1],
753         G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &priv->device,
754         &selected_level, &priv->device_context);
755   }
756
757   /* if D3D11_CREATE_DEVICE_DEBUG was enabled but couldn't create device,
758    * try it without the flag again */
759   if (FAILED (hr) && (d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) ==
760       D3D11_CREATE_DEVICE_DEBUG) {
761     GST_WARNING_OBJECT (self, "Couldn't create d3d11 device with debug flag");
762
763     d3d11_flags &= ~D3D11_CREATE_DEVICE_DEBUG;
764
765     hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
766         NULL, d3d11_flags, feature_levels, G_N_ELEMENTS (feature_levels),
767         D3D11_SDK_VERSION, &priv->device, &selected_level,
768         &priv->device_context);
769
770     if (!gst_d3d11_result (hr, NULL)) {
771       /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
772       hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
773           NULL, d3d11_flags, &feature_levels[1],
774           G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &priv->device,
775           &selected_level, &priv->device_context);
776     }
777   }
778
779   if (gst_d3d11_result (hr, NULL)) {
780     GST_DEBUG_OBJECT (self, "Selected feature level 0x%x", selected_level);
781   } else {
782     GST_WARNING_OBJECT (self,
783         "cannot create d3d11 device, hr: 0x%x", (guint) hr);
784     goto error;
785   }
786
787   priv->factory = factory;
788
789 #if HAVE_D3D11SDKLAYERS_H
790   if ((d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) == D3D11_CREATE_DEVICE_DEBUG) {
791     ID3D11Debug *debug;
792     ID3D11InfoQueue *info_queue;
793
794     hr = ID3D11Device_QueryInterface (priv->device,
795         &IID_ID3D11Debug, (void **) &debug);
796
797     if (SUCCEEDED (hr)) {
798       GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
799           "D3D11Debug interface available");
800       priv->d3d11_debug = debug;
801
802       hr = ID3D11Device_QueryInterface (priv->device,
803           &IID_ID3D11InfoQueue, (void **) &info_queue);
804       if (SUCCEEDED (hr)) {
805         GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
806             "ID3D11InfoQueue interface available");
807         priv->d3d11_info_queue = info_queue;
808       }
809     }
810   }
811 #endif
812
813   /* Update final create flags here, since D3D11_CREATE_DEVICE_DEBUG
814    * might be added by us */
815   priv->create_flags = d3d11_flags;
816
817   IDXGIAdapter1_Release (adapter);
818   gst_d3d11_device_setup_format_table (self);
819
820   G_OBJECT_CLASS (parent_class)->constructed (object);
821
822   return;
823
824 error:
825   if (factory)
826     IDXGIFactory1_Release (factory);
827
828   if (adapter)
829     IDXGIAdapter1_Release (adapter);
830
831   G_OBJECT_CLASS (parent_class)->constructed (object);
832
833   return;
834 }
835
836 static void
837 gst_d3d11_device_set_property (GObject * object, guint prop_id,
838     const GValue * value, GParamSpec * pspec)
839 {
840   GstD3D11Device *self = GST_D3D11_DEVICE (object);
841   GstD3D11DevicePrivate *priv = self->priv;
842
843   switch (prop_id) {
844     case PROP_ADAPTER:
845       priv->adapter = g_value_get_uint (value);
846       break;
847     case PROP_CREATE_FLAGS:
848       priv->create_flags = g_value_get_uint (value);
849       break;
850     default:
851       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
852       break;
853   }
854 }
855
856 static void
857 gst_d3d11_device_get_property (GObject * object, guint prop_id,
858     GValue * value, GParamSpec * pspec)
859 {
860   GstD3D11Device *self = GST_D3D11_DEVICE (object);
861   GstD3D11DevicePrivate *priv = self->priv;
862
863   switch (prop_id) {
864     case PROP_ADAPTER:
865       g_value_set_uint (value, priv->adapter);
866       break;
867     case PROP_DEVICE_ID:
868       g_value_set_uint (value, priv->device_id);
869       break;
870     case PROP_VENDOR_ID:
871       g_value_set_uint (value, priv->vendor_id);
872       break;
873     case PROP_HARDWARE:
874       g_value_set_boolean (value, priv->hardware);
875       break;
876     case PROP_DESCRIPTION:
877       g_value_set_string (value, priv->description);
878       break;
879     case PROP_ALLOW_TEARING:
880       g_value_set_boolean (value, priv->allow_tearing);
881       break;
882     case PROP_CREATE_FLAGS:
883       g_value_set_uint (value, priv->create_flags);
884       break;
885     case PROP_ADAPTER_LUID:
886       g_value_set_int64 (value, priv->adapter_luid);
887       break;
888     default:
889       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
890       break;
891   }
892 }
893
894 static void
895 gst_d3d11_device_dispose (GObject * object)
896 {
897   GstD3D11Device *self = GST_D3D11_DEVICE (object);
898   GstD3D11DevicePrivate *priv = self->priv;
899
900   GST_LOG_OBJECT (self, "dispose");
901
902   if (priv->video_device) {
903     ID3D11VideoDevice_Release (priv->video_device);
904     priv->video_device = NULL;
905   }
906
907   if (priv->video_context) {
908     ID3D11VideoContext_Release (priv->video_context);
909     priv->video_context = NULL;
910   }
911
912   if (priv->device) {
913     ID3D11Device_Release (priv->device);
914     priv->device = NULL;
915   }
916
917   if (priv->device_context) {
918     ID3D11DeviceContext_Release (priv->device_context);
919     priv->device_context = NULL;
920   }
921
922   if (priv->factory) {
923     IDXGIFactory1_Release (priv->factory);
924     priv->factory = NULL;
925   }
926 #if HAVE_D3D11SDKLAYERS_H
927   if (priv->d3d11_debug) {
928     ID3D11Debug_ReportLiveDeviceObjects (priv->d3d11_debug,
929         (D3D11_RLDO_FLAGS) GST_D3D11_RLDO_FLAGS);
930     ID3D11Debug_Release (priv->d3d11_debug);
931     priv->d3d11_debug = NULL;
932   }
933
934   if (priv->d3d11_info_queue) {
935     gst_d3d11_device_d3d11_debug (self, __FILE__, GST_FUNCTION, __LINE__);
936
937     ID3D11InfoQueue_Release (priv->d3d11_info_queue);
938     priv->d3d11_info_queue = NULL;
939   }
940 #endif
941
942 #if HAVE_DXGIDEBUG_H
943   if (priv->dxgi_debug) {
944     IDXGIDebug_ReportLiveObjects (priv->dxgi_debug, DXGI_DEBUG_ALL,
945         (DXGI_DEBUG_RLO_FLAGS) GST_D3D11_RLDO_FLAGS);
946     IDXGIDebug_Release (priv->dxgi_debug);
947     priv->dxgi_debug = NULL;
948   }
949
950   if (priv->dxgi_info_queue) {
951     gst_d3d11_device_dxgi_debug (self, __FILE__, GST_FUNCTION, __LINE__);
952
953     IDXGIInfoQueue_Release (priv->dxgi_info_queue);
954     priv->dxgi_info_queue = NULL;
955   }
956 #endif
957
958   G_OBJECT_CLASS (parent_class)->dispose (object);
959 }
960
961 static void
962 gst_d3d11_device_finalize (GObject * object)
963 {
964   GstD3D11Device *self = GST_D3D11_DEVICE (object);
965   GstD3D11DevicePrivate *priv = self->priv;
966
967   GST_LOG_OBJECT (self, "finalize");
968
969   g_rec_mutex_clear (&priv->extern_lock);
970   g_mutex_clear (&priv->resource_lock);
971   g_free (priv->description);
972
973   G_OBJECT_CLASS (parent_class)->finalize (object);
974 }
975
976 /**
977  * gst_d3d11_device_new:
978  * @adapter: the index of adapter for creating d3d11 device
979  * @flags: a D3D11_CREATE_DEVICE_FLAG value used for creating d3d11 device
980  *
981  * Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter
982  * or %NULL when failed to create D3D11 device with given adapter index.
983  *
984  * Since: 1.20
985  */
986 GstD3D11Device *
987 gst_d3d11_device_new (guint adapter, guint flags)
988 {
989   GstD3D11Device *device = NULL;
990   GstD3D11DevicePrivate *priv;
991
992   device = g_object_new (GST_TYPE_D3D11_DEVICE, "adapter", adapter,
993       "create-flags", flags, NULL);
994
995   priv = device->priv;
996
997   if (!priv->device || !priv->device_context) {
998     GST_DEBUG ("Cannot create d3d11 device with adapter %d", adapter);
999     gst_clear_object (&device);
1000   } else {
1001     gst_object_ref_sink (device);
1002   }
1003
1004   return device;
1005 }
1006
1007 /**
1008  * gst_d3d11_device_get_device_handle:
1009  * @device: a #GstD3D11Device
1010  *
1011  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1012  * object.
1013  *
1014  * Returns: (transfer none): the ID3D11Device handle
1015  *
1016  * Since: 1.20
1017  */
1018 ID3D11Device *
1019 gst_d3d11_device_get_device_handle (GstD3D11Device * device)
1020 {
1021   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1022
1023   return device->priv->device;
1024 }
1025
1026 /**
1027  * gst_d3d11_device_get_device_context_handle:
1028  * @device: a #GstD3D11Device
1029  *
1030  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1031  * object. Any ID3D11DeviceContext call needs to be protected by
1032  * gst_d3d11_device_lock() and gst_d3d11_device_unlock() method.
1033  *
1034  * Returns: (transfer none): the immeidate ID3D11DeviceContext handle
1035  *
1036  * Since: 1.20
1037  */
1038 ID3D11DeviceContext *
1039 gst_d3d11_device_get_device_context_handle (GstD3D11Device * device)
1040 {
1041   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1042
1043   return device->priv->device_context;
1044 }
1045
1046 /**
1047  * gst_d3d11_device_get_dxgi_factory_handle:
1048  * @device: a #GstD3D11Device
1049  *
1050  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1051  * object.
1052  *
1053  * Returns: (transfer none): the IDXGIFactory1 handle
1054  *
1055  * Since: 1.20
1056  */
1057 IDXGIFactory1 *
1058 gst_d3d11_device_get_dxgi_factory_handle (GstD3D11Device * device)
1059 {
1060   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1061
1062   return device->priv->factory;
1063 }
1064
1065 /**
1066  * gst_d3d11_device_get_video_device_handle:
1067  * @device: a #GstD3D11Device
1068  *
1069  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1070  * object.
1071  *
1072  * Returns: (nullable) (transfer none) : the ID3D11VideoDevice handle or %NULL
1073  * if ID3D11VideoDevice is unavailable.
1074  *
1075  * Since: 1.20
1076  */
1077 ID3D11VideoDevice *
1078 gst_d3d11_device_get_video_device_handle (GstD3D11Device * device)
1079 {
1080   GstD3D11DevicePrivate *priv;
1081
1082   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1083
1084   priv = device->priv;
1085   g_mutex_lock (&priv->resource_lock);
1086   if (!priv->video_device) {
1087     HRESULT hr;
1088
1089     hr = ID3D11Device_QueryInterface (priv->device, &IID_ID3D11VideoDevice,
1090         (void **) &priv->video_device);
1091     gst_d3d11_result (hr, device);
1092   }
1093   g_mutex_unlock (&priv->resource_lock);
1094
1095   return priv->video_device;
1096 }
1097
1098 /**
1099  * gst_d3d11_device_get_video_context_handle:
1100  * @device: a #GstD3D11Device
1101  *
1102  * Used for various D3D11 APIs directly. Caller must not destroy returned device
1103  * object.
1104  *
1105  * Returns: (nullable) (transfer none): the ID3D11VideoContext handle or %NULL
1106  * if ID3D11VideoContext is unavailable.
1107  *
1108  * Since: 1.20
1109  */
1110 ID3D11VideoContext *
1111 gst_d3d11_device_get_video_context_handle (GstD3D11Device * device)
1112 {
1113   GstD3D11DevicePrivate *priv;
1114
1115   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1116
1117   priv = device->priv;
1118   g_mutex_lock (&priv->resource_lock);
1119   if (!priv->video_context) {
1120     HRESULT hr;
1121
1122     hr = ID3D11DeviceContext_QueryInterface (priv->device_context,
1123         &IID_ID3D11VideoContext, (void **) &priv->video_context);
1124     gst_d3d11_result (hr, device);
1125   }
1126   g_mutex_unlock (&priv->resource_lock);
1127
1128   return priv->video_context;
1129 }
1130
1131 /**
1132  * gst_d3d11_device_lock:
1133  * @device: a #GstD3D11Device
1134  *
1135  * Take lock for @device. Any thread-unsafe API call needs to be
1136  * protected by this method. This call must be paired with
1137  * gst_d3d11_device_unlock()
1138  *
1139  * Since: 1.20
1140  */
1141 void
1142 gst_d3d11_device_lock (GstD3D11Device * device)
1143 {
1144   GstD3D11DevicePrivate *priv;
1145
1146   g_return_if_fail (GST_IS_D3D11_DEVICE (device));
1147
1148   priv = device->priv;
1149
1150   GST_TRACE_OBJECT (device, "device locking");
1151   g_rec_mutex_lock (&priv->extern_lock);
1152   GST_TRACE_OBJECT (device, "device locked");
1153 }
1154
1155 /**
1156  * gst_d3d11_device_unlock:
1157  * @device: a #GstD3D11Device
1158  *
1159  * Release lock for @device. This call must be paired with
1160  * gst_d3d11_device_lock()
1161  *
1162  * Since: 1.20
1163  */
1164 void
1165 gst_d3d11_device_unlock (GstD3D11Device * device)
1166 {
1167   GstD3D11DevicePrivate *priv;
1168
1169   g_return_if_fail (GST_IS_D3D11_DEVICE (device));
1170
1171   priv = device->priv;
1172
1173   g_rec_mutex_unlock (&priv->extern_lock);
1174   GST_TRACE_OBJECT (device, "device unlocked");
1175 }
1176
1177 /**
1178  * gst_d3d11_device_format_from_gst:
1179  * @device: a #GstD3D11Device
1180  * @format: a #GstVideoFormat
1181  *
1182  * Returns: (transfer none) (nullable): a pointer to #GstD3D11Format
1183  * or %NULL if @format is not supported by @device
1184  *
1185  * Since: 1.20
1186  */
1187 const GstD3D11Format *
1188 gst_d3d11_device_format_from_gst (GstD3D11Device * device,
1189     GstVideoFormat format)
1190 {
1191   GstD3D11DevicePrivate *priv;
1192   gint i;
1193
1194   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1195
1196   priv = device->priv;
1197
1198   for (i = 0; i < G_N_ELEMENTS (priv->format_table); i++) {
1199     if (priv->format_table[i].format == format)
1200       return &priv->format_table[i];
1201   }
1202
1203   return NULL;
1204 }