• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
debug_init_once(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
gst_d3d11_device_enable_d3d11_debug(void)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
d3d11_message_severity_to_gst(D3D11_MESSAGE_SEVERITY level)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
gst_d3d11_device_d3d11_debug(GstD3D11Device * device,const gchar * file,const gchar * function,gint line)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
gst_d3d11_device_d3d11_debug(GstD3D11Device * device,const gchar * file,const gchar * function,gint line)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
gst_d3d11_device_enable_dxgi_debug(void)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
gst_d3d11_device_dxgi_get_device_interface(REFIID riid,void ** debug)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
dxgi_info_queue_message_severity_to_gst(DXGI_INFO_QUEUE_MESSAGE_SEVERITY level)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
gst_d3d11_device_dxgi_debug(GstD3D11Device * device,const gchar * file,const gchar * function,gint line)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
gst_d3d11_device_dxgi_debug(GstD3D11Device * device,const gchar * file,const gchar * function,gint line)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
gst_d3d11_device_class_init(GstD3D11DeviceClass * klass)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
gst_d3d11_device_init(GstD3D11Device * self)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
is_windows_8_or_greater(void)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
operator |(D3D11_FORMAT_SUPPORT lhs,D3D11_FORMAT_SUPPORT rhs)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
operator |=(D3D11_FORMAT_SUPPORT lhs,D3D11_FORMAT_SUPPORT rhs)453 operator |= (D3D11_FORMAT_SUPPORT lhs, D3D11_FORMAT_SUPPORT rhs)
454 {
455   return lhs | rhs;
456 }
457 
458 static gboolean
can_support_format(GstD3D11Device * self,DXGI_FORMAT format,D3D11_FORMAT_SUPPORT extra_flags)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
gst_d3d11_device_setup_format_table(GstD3D11Device * self)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
gst_d3d11_device_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)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
gst_d3d11_device_dispose(GObject * object)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
gst_d3d11_device_finalize(GObject * object)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
_gst_d3d11_device_get_adapter(const GstD3D11DeviceConstructData * data,IDXGIFactory1 * factory,guint * index,DXGI_ADAPTER_DESC * adapter_desc,IDXGIAdapter1 ** dxgi_adapter)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
gst_d3d11_device_setup_debug_layer(GstD3D11Device * self)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 *
gst_d3d11_device_new_internal(const GstD3D11DeviceConstructData * data)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 *
gst_d3d11_device_new(guint adapter_index,guint flags)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 *
gst_d3d11_device_new_for_adapter_luid(gint64 adapter_luid,guint flags)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 *
gst_d3d11_device_new_wrapped(ID3D11Device * device)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 *
gst_d3d11_device_get_device_handle(GstD3D11Device * device)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 *
gst_d3d11_device_get_device_context_handle(GstD3D11Device * device)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 *
gst_d3d11_device_get_dxgi_factory_handle(GstD3D11Device * device)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 *
gst_d3d11_device_get_video_device_handle(GstD3D11Device * device)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 *
gst_d3d11_device_get_video_context_handle(GstD3D11Device * device)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
gst_d3d11_device_lock(GstD3D11Device * device)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
gst_d3d11_device_unlock(GstD3D11Device * device)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 *
gst_d3d11_device_format_from_gst(GstD3D11Device * device,GstVideoFormat format)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 }
1449