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