2 * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
3 * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
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.
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.
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.
25 #include "gstd3d11device.h"
26 #include "gstd3d11utils.h"
27 #include "gstd3d11format.h"
28 #include "gstd3d11_private.h"
32 #include <versionhelpers.h>
35 * SECTION:gstd3d11device
36 * @short_description: Direct3D11 device abstraction
37 * @title: GstD3D11Device
39 * #GstD3D11Device wraps ID3D11Device and ID3D11DeviceContext for GPU resources
40 * to be able to be shared among various elements. Caller can get native
41 * Direct3D11 handles via getter method.
42 * Basically Direct3D11 API doesn't require dedicated thread like that of
43 * OpenGL context, and ID3D11Device APIs are supposed to be thread-safe.
44 * But concurrent call for ID3D11DeviceContext and DXGI API are not allowed.
45 * To protect such object, callers need to make use of gst_d3d11_device_lock()
46 * and gst_d3d11_device_unlock()
49 #if HAVE_D3D11SDKLAYERS_H
50 #include <d3d11sdklayers.h>
51 static GModule *d3d11_debug_module = NULL;
53 /* mingw header does not define D3D11_RLDO_IGNORE_INTERNAL
54 * D3D11_RLDO_SUMMARY = 0x1,
55 D3D11_RLDO_DETAIL = 0x2,
56 * D3D11_RLDO_IGNORE_INTERNAL = 0x4
58 #define GST_D3D11_RLDO_FLAGS (0x2 | 0x4)
62 #include <dxgidebug.h>
63 typedef HRESULT (WINAPI * DXGIGetDebugInterface_t) (REFIID riid,
65 static GModule *dxgi_debug_module = NULL;
66 static DXGIGetDebugInterface_t GstDXGIGetDebugInterface = NULL;
70 #if (HAVE_D3D11SDKLAYERS_H || HAVE_DXGIDEBUG_H)
71 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_debug_layer_debug);
73 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_device_debug);
74 #define GST_CAT_DEFAULT gst_d3d11_device_debug
89 #define DEFAULT_ADAPTER 0
90 #define DEFAULT_CREATE_FLAGS 0
92 struct _GstD3D11DevicePrivate
99 gboolean allow_tearing;
103 ID3D11Device *device;
104 ID3D11DeviceContext *device_context;
106 ID3D11VideoDevice *video_device;
107 ID3D11VideoContext *video_context;
109 IDXGIFactory1 *factory;
110 GstD3D11Format format_table[GST_D3D11_N_FORMATS];
112 GRecMutex extern_lock;
113 GMutex resource_lock;
115 #if HAVE_D3D11SDKLAYERS_H
116 ID3D11Debug *d3d11_debug;
117 ID3D11InfoQueue *d3d11_info_queue;
121 IDXGIDebug *dxgi_debug;
122 IDXGIInfoQueue *dxgi_info_queue;
129 GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug,
130 "d3d11device", 0, "d3d11 device object");
131 #if defined(HAVE_D3D11SDKLAYERS_H) || defined(HAVE_DXGIDEBUG_H)
132 GST_DEBUG_CATEGORY_INIT (gst_d3d11_debug_layer_debug,
133 "d3d11debuglayer", 0, "native d3d11 and dxgi debug");
137 #define gst_d3d11_device_parent_class parent_class
138 G_DEFINE_TYPE_WITH_CODE (GstD3D11Device, gst_d3d11_device, GST_TYPE_OBJECT,
139 G_ADD_PRIVATE (GstD3D11Device); do_debug_init ());
141 static void gst_d3d11_device_set_property (GObject * object, guint prop_id,
142 const GValue * value, GParamSpec * pspec);
143 static void gst_d3d11_device_get_property (GObject * object, guint prop_id,
144 GValue * value, GParamSpec * pspec);
145 static void gst_d3d11_device_constructed (GObject * object);
146 static void gst_d3d11_device_dispose (GObject * object);
147 static void gst_d3d11_device_finalize (GObject * object);
149 #if HAVE_D3D11SDKLAYERS_H
151 gst_d3d11_device_enable_d3d11_debug (void)
153 static volatile gsize _init = 0;
155 /* If all below libraries are unavailable, d3d11 device would fail with
156 * D3D11_CREATE_DEVICE_DEBUG flag */
157 if (g_once_init_enter (&_init)) {
159 g_module_open ("d3d11sdklayers.dll", G_MODULE_BIND_LAZY);
161 if (!d3d11_debug_module)
163 g_module_open ("d3d11_1sdklayers.dll", G_MODULE_BIND_LAZY);
165 g_once_init_leave (&_init, 1);
168 return ! !d3d11_debug_module;
171 static inline GstDebugLevel
172 d3d11_message_severity_to_gst (D3D11_MESSAGE_SEVERITY level)
175 case D3D11_MESSAGE_SEVERITY_CORRUPTION:
176 case D3D11_MESSAGE_SEVERITY_ERROR:
177 return GST_LEVEL_ERROR;
178 case D3D11_MESSAGE_SEVERITY_WARNING:
179 return GST_LEVEL_WARNING;
180 case D3D11_MESSAGE_SEVERITY_INFO:
181 return GST_LEVEL_INFO;
182 case D3D11_MESSAGE_SEVERITY_MESSAGE:
183 return GST_LEVEL_DEBUG;
188 return GST_LEVEL_LOG;
192 gst_d3d11_device_d3d11_debug (GstD3D11Device * device,
193 const gchar * file, const gchar * function, gint line)
195 GstD3D11DevicePrivate *priv = device->priv;
201 if (!priv->d3d11_info_queue)
204 num_msg = ID3D11InfoQueue_GetNumStoredMessages (priv->d3d11_info_queue);
206 for (i = 0; i < num_msg; i++) {
209 hr = ID3D11InfoQueue_GetMessage (priv->d3d11_info_queue, i, NULL, &msg_len);
211 if (FAILED (hr) || msg_len == 0) {
215 msg = (D3D11_MESSAGE *) g_alloca (msg_len);
216 hr = ID3D11InfoQueue_GetMessage (priv->d3d11_info_queue, i, msg, &msg_len);
218 level = d3d11_message_severity_to_gst (msg->Severity);
219 if (msg->Category == D3D11_MESSAGE_CATEGORY_STATE_CREATION &&
220 level > GST_LEVEL_ERROR) {
221 /* Do not warn for live object, since there would be live object
222 * when ReportLiveDeviceObjects was called */
223 level = GST_LEVEL_INFO;
226 gst_debug_log (gst_d3d11_debug_layer_debug, level, file, function, line,
227 G_OBJECT (device), "D3D11InfoQueue: %s", msg->pDescription);
230 ID3D11InfoQueue_ClearStoredMessages (priv->d3d11_info_queue);
236 gst_d3d11_device_d3d11_debug (GstD3D11Device * device,
237 const gchar * file, const gchar * function, gint line)
246 gst_d3d11_device_enable_dxgi_debug (void)
248 static volatile gsize _init = 0;
249 gboolean ret = FALSE;
251 /* If all below libraries are unavailable, d3d11 device would fail with
252 * D3D11_CREATE_DEVICE_DEBUG flag */
253 if (g_once_init_enter (&_init)) {
254 #if (!GST_D3D11_WINAPI_ONLY_APP)
255 dxgi_debug_module = g_module_open ("dxgidebug.dll", G_MODULE_BIND_LAZY);
257 if (dxgi_debug_module)
258 g_module_symbol (dxgi_debug_module,
259 "DXGIGetDebugInterface", (gpointer *) & GstDXGIGetDebugInterface);
260 ret = ! !GstDXGIGetDebugInterface;
261 #elif (GST_D3D11_DXGI_HEADER_VERSION >= 3)
264 g_once_init_leave (&_init, 1);
271 gst_d3d11_device_dxgi_get_device_interface (REFIID riid, void **debug)
273 #if (!GST_D3D11_WINAPI_ONLY_APP)
274 if (GstDXGIGetDebugInterface) {
275 return GstDXGIGetDebugInterface (riid, debug);
277 #elif (GST_D3D11_DXGI_HEADER_VERSION >= 3)
278 return DXGIGetDebugInterface1 (0, riid, debug);
281 return E_NOINTERFACE;
284 static inline GstDebugLevel
285 dxgi_info_queue_message_severity_to_gst (DXGI_INFO_QUEUE_MESSAGE_SEVERITY level)
288 case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_CORRUPTION:
289 case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_ERROR:
290 return GST_LEVEL_ERROR;
291 case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_WARNING:
292 return GST_LEVEL_WARNING;
293 case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_INFO:
294 return GST_LEVEL_INFO;
295 case DXGI_INFO_QUEUE_MESSAGE_SEVERITY_MESSAGE:
296 return GST_LEVEL_DEBUG;
301 return GST_LEVEL_LOG;
305 gst_d3d11_device_dxgi_debug (GstD3D11Device * device,
306 const gchar * file, const gchar * function, gint line)
308 GstD3D11DevicePrivate *priv = device->priv;
309 DXGI_INFO_QUEUE_MESSAGE *msg;
314 if (!priv->dxgi_info_queue)
317 num_msg = IDXGIInfoQueue_GetNumStoredMessages (priv->dxgi_info_queue,
320 for (i = 0; i < num_msg; i++) {
323 hr = IDXGIInfoQueue_GetMessage (priv->dxgi_info_queue,
324 DXGI_DEBUG_ALL, i, NULL, &msg_len);
326 if (FAILED (hr) || msg_len == 0) {
330 msg = (DXGI_INFO_QUEUE_MESSAGE *) g_alloca (msg_len);
331 hr = IDXGIInfoQueue_GetMessage (priv->dxgi_info_queue,
332 DXGI_DEBUG_ALL, i, msg, &msg_len);
334 level = dxgi_info_queue_message_severity_to_gst (msg->Severity);
335 gst_debug_log (gst_d3d11_debug_layer_debug, level, file, function, line,
336 G_OBJECT (device), "DXGIInfoQueue: %s", msg->pDescription);
339 IDXGIInfoQueue_ClearStoredMessages (priv->dxgi_info_queue, DXGI_DEBUG_ALL);
345 gst_d3d11_device_dxgi_debug (GstD3D11Device * device,
346 const gchar * file, const gchar * function, gint line)
354 gst_d3d11_device_class_init (GstD3D11DeviceClass * klass)
356 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
358 gobject_class->set_property = gst_d3d11_device_set_property;
359 gobject_class->get_property = gst_d3d11_device_get_property;
360 gobject_class->constructed = gst_d3d11_device_constructed;
361 gobject_class->dispose = gst_d3d11_device_dispose;
362 gobject_class->finalize = gst_d3d11_device_finalize;
364 g_object_class_install_property (gobject_class, PROP_ADAPTER,
365 g_param_spec_uint ("adapter", "Adapter",
366 "DXGI Adapter index for creating device",
367 0, G_MAXUINT32, DEFAULT_ADAPTER,
368 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
370 g_object_class_install_property (gobject_class, PROP_DEVICE_ID,
371 g_param_spec_uint ("device-id", "Device Id",
372 "DXGI Device ID", 0, G_MAXUINT32, 0,
373 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
375 g_object_class_install_property (gobject_class, PROP_VENDOR_ID,
376 g_param_spec_uint ("vendor-id", "Vendor Id",
377 "DXGI Vendor ID", 0, G_MAXUINT32, 0,
378 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
380 g_object_class_install_property (gobject_class, PROP_HARDWARE,
381 g_param_spec_boolean ("hardware", "Hardware",
382 "Whether hardware device or not", TRUE,
383 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
385 g_object_class_install_property (gobject_class, PROP_DESCRIPTION,
386 g_param_spec_string ("description", "Description",
387 "Human readable device description", NULL,
388 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
390 g_object_class_install_property (gobject_class, PROP_ALLOW_TEARING,
391 g_param_spec_boolean ("allow-tearing", "Allow tearing",
392 "Whether dxgi device supports allow-tearing feature or not", FALSE,
393 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
395 g_object_class_install_property (gobject_class, PROP_CREATE_FLAGS,
396 g_param_spec_uint ("create-flags", "Create flags",
397 "D3D11_CREATE_DEVICE_FLAG flags used for D3D11CreateDevice",
398 0, G_MAXUINT32, DEFAULT_CREATE_FLAGS,
399 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
401 g_object_class_install_property (gobject_class, PROP_ADAPTER_LUID,
402 g_param_spec_int64 ("adapter-luid", "Adapter LUID",
403 "DXGI Adapter LUID (Locally Unique Identifier) of created device",
404 0, G_MAXINT64, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
408 gst_d3d11_device_init (GstD3D11Device * self)
410 GstD3D11DevicePrivate *priv;
412 priv = gst_d3d11_device_get_instance_private (self);
413 priv->adapter = DEFAULT_ADAPTER;
415 g_rec_mutex_init (&priv->extern_lock);
416 g_mutex_init (&priv->resource_lock);
422 is_windows_8_or_greater (void)
424 static gsize version_once = 0;
425 static gboolean ret = FALSE;
427 if (g_once_init_enter (&version_once)) {
428 #if (!GST_D3D11_WINAPI_ONLY_APP)
429 if (IsWindows8OrGreater ())
435 g_once_init_leave (&version_once, 1);
442 can_support_format (GstD3D11Device * self, DXGI_FORMAT format,
443 D3D11_FORMAT_SUPPORT extra_flags)
445 GstD3D11DevicePrivate *priv = self->priv;
446 ID3D11Device *handle = priv->device;
449 D3D11_FORMAT_SUPPORT flags = D3D11_FORMAT_SUPPORT_TEXTURE2D;
451 flags |= extra_flags;
453 if (!is_windows_8_or_greater ()) {
454 GST_INFO_OBJECT (self, "DXGI format %d needs Windows 8 or greater",
459 hr = ID3D11Device_CheckFormatSupport (handle, format, &supported);
461 GST_DEBUG_OBJECT (self, "DXGI format %d is not supported by device",
466 if ((supported & flags) != flags) {
467 GST_DEBUG_OBJECT (self,
468 "DXGI format %d doesn't support flag 0x%x (supported flag 0x%x)",
469 (guint) format, (guint) supported, (guint) flags);
473 GST_INFO_OBJECT (self, "Device supports DXGI format %d", (guint) format);
479 gst_d3d11_device_setup_format_table (GstD3D11Device * self)
481 GstD3D11DevicePrivate *priv = self->priv;
485 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_BGRA;
486 priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_B8G8R8A8_UNORM;
487 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_B8G8R8A8_UNORM;
490 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_RGBA;
491 priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
492 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R8G8B8A8_UNORM;
495 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_RGB10A2_LE;
496 priv->format_table[n_formats].resource_format[0] =
497 DXGI_FORMAT_R10G10B10A2_UNORM;
498 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_R10G10B10A2_UNORM;
502 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_VUYA;
503 priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8G8B8A8_UNORM;
504 if (can_support_format (self, DXGI_FORMAT_AYUV,
505 D3D11_FORMAT_SUPPORT_RENDER_TARGET |
506 D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
507 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_AYUV;
509 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
512 /* NOTE: packted yuv 4:2:2 YUY2, UYVY, and VYUY formats are not natively
513 * supported render target view formats
514 * (i.e., cannot be output format of shader pipeline) */
515 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_YUY2;
516 if (can_support_format (self, DXGI_FORMAT_YUY2,
517 D3D11_FORMAT_SUPPORT_SHADER_SAMPLE)) {
518 priv->format_table[n_formats].resource_format[0] =
519 DXGI_FORMAT_R8G8B8A8_UNORM;
520 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_YUY2;
522 /* If DXGI_FORMAT_YUY2 format is not supported, use this format,
523 * it's analogous to YUY2 */
524 priv->format_table[n_formats].resource_format[0] =
525 DXGI_FORMAT_G8R8_G8B8_UNORM;
529 /* No native DXGI format available for UYVY */
530 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_UYVY;
531 priv->format_table[n_formats].resource_format[0] =
532 DXGI_FORMAT_R8G8_B8G8_UNORM;
535 /* No native DXGI format available for VYUY */
536 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_VYUY;
537 priv->format_table[n_formats].resource_format[0] =
538 DXGI_FORMAT_R8G8_B8G8_UNORM;
541 /* Y210 and Y410 formats cannot support rtv */
542 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y210;
543 priv->format_table[n_formats].resource_format[0] =
544 DXGI_FORMAT_R16G16B16A16_UNORM;
545 if (can_support_format (self, DXGI_FORMAT_Y210,
546 D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
547 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_Y210;
549 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
552 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_Y410;
553 priv->format_table[n_formats].resource_format[0] =
554 DXGI_FORMAT_R10G10B10A2_UNORM;
555 if (can_support_format (self, DXGI_FORMAT_Y410,
556 D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
557 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_Y410;
559 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
562 /* YUV semi-planar */
563 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_NV12;
564 priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
565 priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8G8_UNORM;
566 if (can_support_format (self, DXGI_FORMAT_NV12,
567 D3D11_FORMAT_SUPPORT_RENDER_TARGET |
568 D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
569 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_NV12;
571 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
574 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_P010_10LE;
575 priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
576 priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
577 if (can_support_format (self, DXGI_FORMAT_P010,
578 D3D11_FORMAT_SUPPORT_RENDER_TARGET |
579 D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
580 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_P010;
582 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
585 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_P016_LE;
586 priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
587 priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16G16_UNORM;
588 if (can_support_format (self, DXGI_FORMAT_P016,
589 D3D11_FORMAT_SUPPORT_RENDER_TARGET |
590 D3D11_FORMAT_SUPPORT_SHADER_SAMPLE))
591 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_P016;
593 priv->format_table[n_formats].dxgi_format = DXGI_FORMAT_UNKNOWN;
597 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I420;
598 priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R8_UNORM;
599 priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R8_UNORM;
600 priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R8_UNORM;
603 priv->format_table[n_formats].format = GST_VIDEO_FORMAT_I420_10LE;
604 priv->format_table[n_formats].resource_format[0] = DXGI_FORMAT_R16_UNORM;
605 priv->format_table[n_formats].resource_format[1] = DXGI_FORMAT_R16_UNORM;
606 priv->format_table[n_formats].resource_format[2] = DXGI_FORMAT_R16_UNORM;
609 g_assert (n_formats == GST_D3D11_N_FORMATS);
613 gst_d3d11_device_constructed (GObject * object)
615 GstD3D11Device *self = GST_D3D11_DEVICE (object);
616 GstD3D11DevicePrivate *priv = self->priv;
617 IDXGIAdapter1 *adapter = NULL;
618 IDXGIFactory1 *factory = NULL;
620 UINT d3d11_flags = priv->create_flags;
622 static const D3D_FEATURE_LEVEL feature_levels[] = {
623 D3D_FEATURE_LEVEL_11_1,
624 D3D_FEATURE_LEVEL_11_0,
625 D3D_FEATURE_LEVEL_10_1,
626 D3D_FEATURE_LEVEL_10_0,
627 D3D_FEATURE_LEVEL_9_3,
628 D3D_FEATURE_LEVEL_9_2,
629 D3D_FEATURE_LEVEL_9_1
631 D3D_FEATURE_LEVEL selected_level;
633 GST_DEBUG_OBJECT (self,
634 "Built with DXGI header version %d", GST_D3D11_DXGI_HEADER_VERSION);
637 if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) >
639 if (gst_d3d11_device_enable_dxgi_debug ()) {
640 IDXGIDebug *debug = NULL;
641 IDXGIInfoQueue *info_queue = NULL;
643 GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
644 "dxgi debug library was loaded");
645 hr = gst_d3d11_device_dxgi_get_device_interface (&IID_IDXGIDebug,
648 if (SUCCEEDED (hr)) {
649 GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
650 "IDXGIDebug interface available");
651 priv->dxgi_debug = debug;
653 hr = gst_d3d11_device_dxgi_get_device_interface (&IID_IDXGIInfoQueue,
654 (void **) &info_queue);
655 if (SUCCEEDED (hr)) {
656 GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
657 "IDXGIInfoQueue interface available");
658 priv->dxgi_info_queue = info_queue;
662 GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
663 "couldn't load dxgi debug library");
668 #if (GST_D3D11_DXGI_HEADER_VERSION >= 5)
669 hr = CreateDXGIFactory1 (&IID_IDXGIFactory5, (void **) &factory);
670 if (!gst_d3d11_result (hr, NULL)) {
671 GST_INFO_OBJECT (self, "IDXGIFactory5 was unavailable");
676 hr = IDXGIFactory5_CheckFeatureSupport ((IDXGIFactory5 *) factory,
677 DXGI_FEATURE_PRESENT_ALLOW_TEARING, (void *) &allow_tearing,
678 sizeof (allow_tearing));
680 priv->allow_tearing = SUCCEEDED (hr) && allow_tearing;
687 hr = CreateDXGIFactory1 (&IID_IDXGIFactory1, (void **) &factory);
690 if (!gst_d3d11_result (hr, NULL)) {
691 GST_ERROR_OBJECT (self, "cannot create dxgi factory, hr: 0x%x", (guint) hr);
695 if (IDXGIFactory1_EnumAdapters1 (factory, priv->adapter,
696 &adapter) == DXGI_ERROR_NOT_FOUND) {
697 GST_DEBUG_OBJECT (self, "No adapter for index %d", priv->adapter);
700 DXGI_ADAPTER_DESC1 desc;
702 hr = IDXGIAdapter1_GetDesc1 (adapter, &desc);
703 if (SUCCEEDED (hr)) {
704 gchar *description = NULL;
705 gboolean is_hardware = FALSE;
708 /* DXGI_ADAPTER_FLAG_SOFTWARE is missing in dxgi.h of mingw */
709 if ((desc.Flags & 0x2) != 0x2) {
713 adapter_luid = (((gint64) desc.AdapterLuid.HighPart) << 32) |
714 ((gint64) desc.AdapterLuid.LowPart);
715 description = g_utf16_to_utf8 (desc.Description, -1, NULL, NULL, NULL);
716 GST_DEBUG_OBJECT (self,
717 "adapter index %d: D3D11 device vendor-id: 0x%04x, device-id: 0x%04x, "
718 "Flags: 0x%x, adapter-luid: %" G_GINT64_FORMAT ", %s",
719 priv->adapter, desc.VendorId, desc.DeviceId, desc.Flags, adapter_luid,
722 priv->vendor_id = desc.VendorId;
723 priv->device_id = desc.DeviceId;
724 priv->hardware = is_hardware;
725 priv->description = description;
726 priv->adapter_luid = adapter_luid;
730 #if HAVE_D3D11SDKLAYERS_H
731 if (gst_debug_category_get_threshold (gst_d3d11_debug_layer_debug) >
733 /* DirectX SDK should be installed on system for this */
734 if (gst_d3d11_device_enable_d3d11_debug ()) {
735 GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
736 "d3d11 debug library was loaded");
737 d3d11_flags |= D3D11_CREATE_DEVICE_DEBUG;
739 GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
740 "couldn't load d3d11 debug library");
745 hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
746 NULL, d3d11_flags, feature_levels, G_N_ELEMENTS (feature_levels),
747 D3D11_SDK_VERSION, &priv->device, &selected_level, &priv->device_context);
749 if (!gst_d3d11_result (hr, NULL)) {
750 /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
751 hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
752 NULL, d3d11_flags, &feature_levels[1],
753 G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &priv->device,
754 &selected_level, &priv->device_context);
757 /* if D3D11_CREATE_DEVICE_DEBUG was enabled but couldn't create device,
758 * try it without the flag again */
759 if (FAILED (hr) && (d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) ==
760 D3D11_CREATE_DEVICE_DEBUG) {
761 GST_WARNING_OBJECT (self, "Couldn't create d3d11 device with debug flag");
763 d3d11_flags &= ~D3D11_CREATE_DEVICE_DEBUG;
765 hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
766 NULL, d3d11_flags, feature_levels, G_N_ELEMENTS (feature_levels),
767 D3D11_SDK_VERSION, &priv->device, &selected_level,
768 &priv->device_context);
770 if (!gst_d3d11_result (hr, NULL)) {
771 /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
772 hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
773 NULL, d3d11_flags, &feature_levels[1],
774 G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &priv->device,
775 &selected_level, &priv->device_context);
779 if (gst_d3d11_result (hr, NULL)) {
780 GST_DEBUG_OBJECT (self, "Selected feature level 0x%x", selected_level);
782 GST_WARNING_OBJECT (self,
783 "cannot create d3d11 device, hr: 0x%x", (guint) hr);
787 priv->factory = factory;
789 #if HAVE_D3D11SDKLAYERS_H
790 if ((d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) == D3D11_CREATE_DEVICE_DEBUG) {
792 ID3D11InfoQueue *info_queue;
794 hr = ID3D11Device_QueryInterface (priv->device,
795 &IID_ID3D11Debug, (void **) &debug);
797 if (SUCCEEDED (hr)) {
798 GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
799 "D3D11Debug interface available");
800 priv->d3d11_debug = debug;
802 hr = ID3D11Device_QueryInterface (priv->device,
803 &IID_ID3D11InfoQueue, (void **) &info_queue);
804 if (SUCCEEDED (hr)) {
805 GST_CAT_INFO_OBJECT (gst_d3d11_debug_layer_debug, self,
806 "ID3D11InfoQueue interface available");
807 priv->d3d11_info_queue = info_queue;
813 /* Update final create flags here, since D3D11_CREATE_DEVICE_DEBUG
814 * might be added by us */
815 priv->create_flags = d3d11_flags;
817 IDXGIAdapter1_Release (adapter);
818 gst_d3d11_device_setup_format_table (self);
820 G_OBJECT_CLASS (parent_class)->constructed (object);
826 IDXGIFactory1_Release (factory);
829 IDXGIAdapter1_Release (adapter);
831 G_OBJECT_CLASS (parent_class)->constructed (object);
837 gst_d3d11_device_set_property (GObject * object, guint prop_id,
838 const GValue * value, GParamSpec * pspec)
840 GstD3D11Device *self = GST_D3D11_DEVICE (object);
841 GstD3D11DevicePrivate *priv = self->priv;
845 priv->adapter = g_value_get_uint (value);
847 case PROP_CREATE_FLAGS:
848 priv->create_flags = g_value_get_uint (value);
851 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
857 gst_d3d11_device_get_property (GObject * object, guint prop_id,
858 GValue * value, GParamSpec * pspec)
860 GstD3D11Device *self = GST_D3D11_DEVICE (object);
861 GstD3D11DevicePrivate *priv = self->priv;
865 g_value_set_uint (value, priv->adapter);
868 g_value_set_uint (value, priv->device_id);
871 g_value_set_uint (value, priv->vendor_id);
874 g_value_set_boolean (value, priv->hardware);
876 case PROP_DESCRIPTION:
877 g_value_set_string (value, priv->description);
879 case PROP_ALLOW_TEARING:
880 g_value_set_boolean (value, priv->allow_tearing);
882 case PROP_CREATE_FLAGS:
883 g_value_set_uint (value, priv->create_flags);
885 case PROP_ADAPTER_LUID:
886 g_value_set_int64 (value, priv->adapter_luid);
889 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
895 gst_d3d11_device_dispose (GObject * object)
897 GstD3D11Device *self = GST_D3D11_DEVICE (object);
898 GstD3D11DevicePrivate *priv = self->priv;
900 GST_LOG_OBJECT (self, "dispose");
902 if (priv->video_device) {
903 ID3D11VideoDevice_Release (priv->video_device);
904 priv->video_device = NULL;
907 if (priv->video_context) {
908 ID3D11VideoContext_Release (priv->video_context);
909 priv->video_context = NULL;
913 ID3D11Device_Release (priv->device);
917 if (priv->device_context) {
918 ID3D11DeviceContext_Release (priv->device_context);
919 priv->device_context = NULL;
923 IDXGIFactory1_Release (priv->factory);
924 priv->factory = NULL;
926 #if HAVE_D3D11SDKLAYERS_H
927 if (priv->d3d11_debug) {
928 ID3D11Debug_ReportLiveDeviceObjects (priv->d3d11_debug,
929 (D3D11_RLDO_FLAGS) GST_D3D11_RLDO_FLAGS);
930 ID3D11Debug_Release (priv->d3d11_debug);
931 priv->d3d11_debug = NULL;
934 if (priv->d3d11_info_queue) {
935 gst_d3d11_device_d3d11_debug (self, __FILE__, GST_FUNCTION, __LINE__);
937 ID3D11InfoQueue_Release (priv->d3d11_info_queue);
938 priv->d3d11_info_queue = NULL;
943 if (priv->dxgi_debug) {
944 IDXGIDebug_ReportLiveObjects (priv->dxgi_debug, DXGI_DEBUG_ALL,
945 (DXGI_DEBUG_RLO_FLAGS) GST_D3D11_RLDO_FLAGS);
946 IDXGIDebug_Release (priv->dxgi_debug);
947 priv->dxgi_debug = NULL;
950 if (priv->dxgi_info_queue) {
951 gst_d3d11_device_dxgi_debug (self, __FILE__, GST_FUNCTION, __LINE__);
953 IDXGIInfoQueue_Release (priv->dxgi_info_queue);
954 priv->dxgi_info_queue = NULL;
958 G_OBJECT_CLASS (parent_class)->dispose (object);
962 gst_d3d11_device_finalize (GObject * object)
964 GstD3D11Device *self = GST_D3D11_DEVICE (object);
965 GstD3D11DevicePrivate *priv = self->priv;
967 GST_LOG_OBJECT (self, "finalize");
969 g_rec_mutex_clear (&priv->extern_lock);
970 g_mutex_clear (&priv->resource_lock);
971 g_free (priv->description);
973 G_OBJECT_CLASS (parent_class)->finalize (object);
977 * gst_d3d11_device_new:
978 * @adapter: the index of adapter for creating d3d11 device
979 * @flags: a D3D11_CREATE_DEVICE_FLAG value used for creating d3d11 device
981 * Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter
982 * or %NULL when failed to create D3D11 device with given adapter index.
987 gst_d3d11_device_new (guint adapter, guint flags)
989 GstD3D11Device *device = NULL;
990 GstD3D11DevicePrivate *priv;
992 device = g_object_new (GST_TYPE_D3D11_DEVICE, "adapter", adapter,
993 "create-flags", flags, NULL);
997 if (!priv->device || !priv->device_context) {
998 GST_DEBUG ("Cannot create d3d11 device with adapter %d", adapter);
999 gst_clear_object (&device);
1001 gst_object_ref_sink (device);
1008 * gst_d3d11_device_get_device_handle:
1009 * @device: a #GstD3D11Device
1011 * Used for various D3D11 APIs directly. Caller must not destroy returned device
1014 * Returns: (transfer none): the ID3D11Device handle
1019 gst_d3d11_device_get_device_handle (GstD3D11Device * device)
1021 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1023 return device->priv->device;
1027 * gst_d3d11_device_get_device_context_handle:
1028 * @device: a #GstD3D11Device
1030 * Used for various D3D11 APIs directly. Caller must not destroy returned device
1031 * object. Any ID3D11DeviceContext call needs to be protected by
1032 * gst_d3d11_device_lock() and gst_d3d11_device_unlock() method.
1034 * Returns: (transfer none): the immeidate ID3D11DeviceContext handle
1038 ID3D11DeviceContext *
1039 gst_d3d11_device_get_device_context_handle (GstD3D11Device * device)
1041 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1043 return device->priv->device_context;
1047 * gst_d3d11_device_get_dxgi_factory_handle:
1048 * @device: a #GstD3D11Device
1050 * Used for various D3D11 APIs directly. Caller must not destroy returned device
1053 * Returns: (transfer none): the IDXGIFactory1 handle
1058 gst_d3d11_device_get_dxgi_factory_handle (GstD3D11Device * device)
1060 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1062 return device->priv->factory;
1066 * gst_d3d11_device_get_video_device_handle:
1067 * @device: a #GstD3D11Device
1069 * Used for various D3D11 APIs directly. Caller must not destroy returned device
1072 * Returns: (nullable) (transfer none) : the ID3D11VideoDevice handle or %NULL
1073 * if ID3D11VideoDevice is unavailable.
1078 gst_d3d11_device_get_video_device_handle (GstD3D11Device * device)
1080 GstD3D11DevicePrivate *priv;
1082 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1084 priv = device->priv;
1085 g_mutex_lock (&priv->resource_lock);
1086 if (!priv->video_device) {
1089 hr = ID3D11Device_QueryInterface (priv->device, &IID_ID3D11VideoDevice,
1090 (void **) &priv->video_device);
1091 gst_d3d11_result (hr, device);
1093 g_mutex_unlock (&priv->resource_lock);
1095 return priv->video_device;
1099 * gst_d3d11_device_get_video_context_handle:
1100 * @device: a #GstD3D11Device
1102 * Used for various D3D11 APIs directly. Caller must not destroy returned device
1105 * Returns: (nullable) (transfer none): the ID3D11VideoContext handle or %NULL
1106 * if ID3D11VideoContext is unavailable.
1110 ID3D11VideoContext *
1111 gst_d3d11_device_get_video_context_handle (GstD3D11Device * device)
1113 GstD3D11DevicePrivate *priv;
1115 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1117 priv = device->priv;
1118 g_mutex_lock (&priv->resource_lock);
1119 if (!priv->video_context) {
1122 hr = ID3D11DeviceContext_QueryInterface (priv->device_context,
1123 &IID_ID3D11VideoContext, (void **) &priv->video_context);
1124 gst_d3d11_result (hr, device);
1126 g_mutex_unlock (&priv->resource_lock);
1128 return priv->video_context;
1132 * gst_d3d11_device_lock:
1133 * @device: a #GstD3D11Device
1135 * Take lock for @device. Any thread-unsafe API call needs to be
1136 * protected by this method. This call must be paired with
1137 * gst_d3d11_device_unlock()
1142 gst_d3d11_device_lock (GstD3D11Device * device)
1144 GstD3D11DevicePrivate *priv;
1146 g_return_if_fail (GST_IS_D3D11_DEVICE (device));
1148 priv = device->priv;
1150 GST_TRACE_OBJECT (device, "device locking");
1151 g_rec_mutex_lock (&priv->extern_lock);
1152 GST_TRACE_OBJECT (device, "device locked");
1156 * gst_d3d11_device_unlock:
1157 * @device: a #GstD3D11Device
1159 * Release lock for @device. This call must be paired with
1160 * gst_d3d11_device_lock()
1165 gst_d3d11_device_unlock (GstD3D11Device * device)
1167 GstD3D11DevicePrivate *priv;
1169 g_return_if_fail (GST_IS_D3D11_DEVICE (device));
1171 priv = device->priv;
1173 g_rec_mutex_unlock (&priv->extern_lock);
1174 GST_TRACE_OBJECT (device, "device unlocked");
1178 * gst_d3d11_device_format_from_gst:
1179 * @device: a #GstD3D11Device
1180 * @format: a #GstVideoFormat
1182 * Returns: (transfer none) (nullable): a pointer to #GstD3D11Format
1183 * or %NULL if @format is not supported by @device
1187 const GstD3D11Format *
1188 gst_d3d11_device_format_from_gst (GstD3D11Device * device,
1189 GstVideoFormat format)
1191 GstD3D11DevicePrivate *priv;
1194 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1196 priv = device->priv;
1198 for (i = 0; i < G_N_ELEMENTS (priv->format_table); i++) {
1199 if (priv->format_table[i].format == format)
1200 return &priv->format_table[i];