ed68aea0cef204aa79b39102fd44923b4e8daab9
[platform/upstream/gstreamer.git] / sys / d3d11 / gstd3d11device.c
1 /* GStreamer
2  * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstd3d11device.h"
25 #include "gmodule.h"
26
27 #ifdef HAVE_D3D11SDKLAYER_H
28 #include <d3d11sdklayers.h>
29 #endif
30
31 GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
32 GST_DEBUG_CATEGORY_STATIC (gst_d3d11_device_debug);
33 #define GST_CAT_DEFAULT gst_d3d11_device_debug
34
35 #ifdef HAVE_D3D11SDKLAYER_H
36 static GModule *sdk_layer = NULL;
37 #endif
38
39 enum
40 {
41   PROP_0,
42   PROP_ADAPTER
43 };
44
45 #define DEFAULT_ADAPTER -1
46
47 struct _GstD3D11DevicePrivate
48 {
49   gint adapter;
50
51   ID3D11Device *device;
52   ID3D11DeviceContext *device_context;
53
54   IDXGIFactory1 *factory;
55   GstD3D11DXGIFactoryVersion factory_ver;
56
57   ID3D11VideoDevice *video_device;
58   ID3D11VideoContext *video_context;
59
60   GMutex lock;
61   GCond cond;
62   GThread *thread;
63   GThread *active_thread;
64   GMainLoop *loop;
65   GMainContext *main_context;
66
67 #ifdef HAVE_D3D11SDKLAYER_H
68   ID3D11Debug *debug;
69   ID3D11InfoQueue *info_queue;
70 #endif
71 };
72
73 #define gst_d3d11_device_parent_class parent_class
74 G_DEFINE_TYPE_WITH_PRIVATE (GstD3D11Device, gst_d3d11_device, GST_TYPE_OBJECT);
75
76 static void gst_d3d11_device_set_property (GObject * object, guint prop_id,
77     const GValue * value, GParamSpec * pspec);
78 static void gst_d3d11_device_get_property (GObject * object, guint prop_id,
79     GValue * value, GParamSpec * pspec);
80 static void gst_d3d11_device_constructed (GObject * object);
81 static void gst_d3d11_device_dispose (GObject * object);
82 static void gst_d3d11_device_finalize (GObject * object);
83
84 static gpointer gst_d3d11_device_thread_func (gpointer data);
85
86 #ifdef HAVE_D3D11SDKLAYER_H
87 static gboolean
88 gst_d3d11_device_enable_debug_layer (void)
89 {
90   static volatile gsize _init = 0;
91
92   if (g_once_init_enter (&_init)) {
93     sdk_layer = g_module_open ("d3d11sdklayers.dll", G_MODULE_BIND_LAZY);
94
95     if (!sdk_layer)
96       sdk_layer = g_module_open ("d3d11_1sdklayers.dll", G_MODULE_BIND_LAZY);
97
98     g_once_init_leave (&_init, 1);
99   }
100
101   return ! !sdk_layer;
102 }
103
104 static gboolean
105 gst_d3d11_device_get_message (GstD3D11Device * self)
106 {
107   GstD3D11DevicePrivate *priv = self->priv;
108   D3D11_MESSAGE *msg;
109   SIZE_T msg_len = 0;
110   HRESULT hr;
111   UINT64 num_msg, i;
112
113   num_msg = ID3D11InfoQueue_GetNumStoredMessages (priv->info_queue);
114
115   for (i = 0; i < num_msg; i++) {
116     hr = ID3D11InfoQueue_GetMessage (priv->info_queue, i, NULL, &msg_len);
117
118     if (FAILED (hr) || msg_len == 0) {
119       return G_SOURCE_CONTINUE;
120     }
121
122     msg = (D3D11_MESSAGE *) g_malloc0 (msg_len);
123     hr = ID3D11InfoQueue_GetMessage (priv->info_queue, i, msg, &msg_len);
124
125     GST_TRACE_OBJECT (self, "D3D11 Message - %s", msg->pDescription);
126     g_free (msg);
127   }
128
129   ID3D11InfoQueue_ClearStoredMessages (priv->info_queue);
130
131   return G_SOURCE_CONTINUE;
132 }
133 #endif
134
135 static void
136 gst_d3d11_device_class_init (GstD3D11DeviceClass * klass)
137 {
138   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
139
140   gobject_class->set_property = gst_d3d11_device_set_property;
141   gobject_class->get_property = gst_d3d11_device_get_property;
142   gobject_class->constructed = gst_d3d11_device_constructed;
143   gobject_class->dispose = gst_d3d11_device_dispose;
144   gobject_class->finalize = gst_d3d11_device_finalize;
145
146   g_object_class_install_property (gobject_class, PROP_ADAPTER,
147       g_param_spec_int ("adapter", "Adapter",
148           "Adapter index for creating device (-1 for default)",
149           -1, G_MAXINT32, DEFAULT_ADAPTER,
150           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
151
152   GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug,
153       "d3d11device", 0, "d3d11 device");
154   GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
155 }
156
157 static void
158 gst_d3d11_device_init (GstD3D11Device * self)
159 {
160   GstD3D11DevicePrivate *priv;
161
162   priv = gst_d3d11_device_get_instance_private (self);
163   priv->adapter = DEFAULT_ADAPTER;
164
165   g_mutex_init (&priv->lock);
166   g_cond_init (&priv->cond);
167
168   priv->main_context = g_main_context_new ();
169   priv->loop = g_main_loop_new (priv->main_context, FALSE);
170
171   self->priv = priv;
172 }
173
174 static void
175 _relase_adapter (IDXGIAdapter1 * adapter)
176 {
177   IDXGIAdapter1_Release (adapter);
178 }
179
180 static void
181 gst_d3d11_device_constructed (GObject * object)
182 {
183   GstD3D11Device *self = GST_D3D11_DEVICE (object);
184   GstD3D11DevicePrivate *priv = self->priv;
185   IDXGIAdapter1 *adapter = NULL;
186   GList *adapter_list = NULL;
187   GList *hw_adapter_list = NULL;
188   IDXGIFactory1 *factory = NULL;
189   HRESULT hr;
190   guint i;
191   guint num_adapter = 0;
192   UINT d3d11_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
193
194   static const D3D_DRIVER_TYPE driver_types[] = {
195     D3D_DRIVER_TYPE_HARDWARE,
196     D3D_DRIVER_TYPE_WARP,
197     D3D_DRIVER_TYPE_UNKNOWN
198   };
199   static const D3D_FEATURE_LEVEL feature_levels[] = {
200     D3D_FEATURE_LEVEL_11_1,
201     D3D_FEATURE_LEVEL_11_0,
202     D3D_FEATURE_LEVEL_10_1,
203     D3D_FEATURE_LEVEL_10_0,
204     D3D_FEATURE_LEVEL_9_3,
205     D3D_FEATURE_LEVEL_9_2,
206     D3D_FEATURE_LEVEL_9_1
207   };
208   D3D_FEATURE_LEVEL selected_level;
209
210 #ifdef HAVE_DXGI_1_5_H
211   hr = CreateDXGIFactory1 (&IID_IDXGIFactory5, (void **) &factory);
212   if (FAILED (hr)) {
213     GST_INFO_OBJECT (self, "IDXGIFactory5 was unavailable");
214     factory = NULL;
215   }
216
217   priv->factory_ver = GST_D3D11_DXGI_FACTORY_5;
218 #endif
219
220   if (!factory) {
221     priv->factory_ver = GST_D3D11_DXGI_FACTORY_1;
222     hr = CreateDXGIFactory1 (&IID_IDXGIFactory1, (void **) &factory);
223   }
224
225   if (FAILED (hr)) {
226     GST_ERROR_OBJECT (self, "cannot create dxgi factory, hr: 0x%x", (guint) hr);
227     goto error;
228   }
229
230   while (IDXGIFactory1_EnumAdapters1 (factory, num_adapter,
231           &adapter) != DXGI_ERROR_NOT_FOUND) {
232     DXGI_ADAPTER_DESC1 desc;
233
234     hr = IDXGIAdapter1_GetDesc1 (adapter, &desc);
235     if (SUCCEEDED (hr)) {
236       gchar *vender = NULL;
237
238       vender = g_utf16_to_utf8 (desc.Description, -1, NULL, NULL, NULL);
239       GST_DEBUG_OBJECT (self,
240           "adapter index %d: D3D11 device vendor-id: 0x%04x, device-id: 0x%04x, "
241           "Flags: 0x%x, %s",
242           num_adapter, desc.VendorId, desc.DeviceId, desc.Flags, vender);
243       g_free (vender);
244
245       /* DXGI_ADAPTER_FLAG_SOFTWARE is missing in dxgi.h of mingw */
246       if ((desc.Flags & 0x2) != 0x2) {
247         hw_adapter_list = g_list_append (hw_adapter_list, adapter);
248         IDXGIAdapter1_AddRef (adapter);
249       }
250     }
251
252     adapter_list = g_list_append (adapter_list, adapter);
253
254     num_adapter++;
255
256     if (priv->adapter >= 0 && priv->adapter < num_adapter)
257       break;
258   }
259
260   adapter = NULL;
261   if (priv->adapter >= 0) {
262     if (priv->adapter >= num_adapter) {
263       GST_WARNING_OBJECT (self,
264           "Requested index %d is out of scope for adapter", priv->adapter);
265     } else {
266       adapter = (IDXGIAdapter1 *) g_list_nth_data (adapter_list, priv->adapter);
267     }
268   } else if (hw_adapter_list) {
269     adapter = (IDXGIAdapter1 *) g_list_nth_data (hw_adapter_list, 0);
270   } else if (adapter_list) {
271     adapter = (IDXGIAdapter1 *) g_list_nth_data (adapter_list, 0);
272   }
273
274   if (adapter)
275     IDXGIAdapter1_AddRef (adapter);
276
277 #ifdef HAVE_D3D11SDKLAYER_H
278   if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= GST_LEVEL_TRACE) {
279     /* DirectX SDK should be installed on system for this */
280     if (gst_d3d11_device_enable_debug_layer ()) {
281       GST_INFO_OBJECT (self, "sdk layer library was loaded");
282       d3d11_flags |= D3D11_CREATE_DEVICE_DEBUG;
283     }
284   }
285 #endif
286
287   if (adapter) {
288     hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
289         NULL, d3d11_flags, feature_levels, G_N_ELEMENTS (feature_levels),
290         D3D11_SDK_VERSION, &priv->device, &selected_level,
291         &priv->device_context);
292
293     if (FAILED (hr)) {
294       /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
295       hr = D3D11CreateDevice ((IDXGIAdapter *) adapter, D3D_DRIVER_TYPE_UNKNOWN,
296           NULL, d3d11_flags, &feature_levels[1],
297           G_N_ELEMENTS (feature_levels) - 1, D3D11_SDK_VERSION, &priv->device,
298           &selected_level, &priv->device_context);
299     }
300
301     if (SUCCEEDED (hr)) {
302       GST_DEBUG_OBJECT (self, "Selected feature level 0x%x", selected_level);
303     }
304   } else {
305     for (i = 0; i < G_N_ELEMENTS (driver_types); i++) {
306       hr = D3D11CreateDevice (NULL, driver_types[i], NULL,
307           d3d11_flags,
308           feature_levels, G_N_ELEMENTS (feature_levels),
309           D3D11_SDK_VERSION, &priv->device, &selected_level,
310           &priv->device_context);
311
312       if (FAILED (hr)) {
313         /* Retry if the system could not recognize D3D_FEATURE_LEVEL_11_1 */
314         hr = D3D11CreateDevice (NULL, driver_types[i], NULL,
315             d3d11_flags,
316             &feature_levels[1], G_N_ELEMENTS (feature_levels) - 1,
317             D3D11_SDK_VERSION, &priv->device, &selected_level,
318             &priv->device_context);
319       }
320
321       if (SUCCEEDED (hr)) {
322         GST_DEBUG_OBJECT (self, "Selected driver type 0x%x, feature level 0x%x",
323             driver_types[i], selected_level);
324         break;
325       }
326     }
327   }
328
329   if (FAILED (hr)) {
330     GST_ERROR_OBJECT (self, "cannot create d3d11 device, hr: 0x%x", (guint) hr);
331     goto error;
332   }
333
334   priv->factory = factory;
335
336   if (adapter)
337     IDXGIAdapter1_Release (adapter);
338
339   if (adapter_list)
340     g_list_free_full (adapter_list, (GDestroyNotify) _relase_adapter);
341
342   if (hw_adapter_list)
343     g_list_free_full (hw_adapter_list, (GDestroyNotify) _relase_adapter);
344
345 #ifdef HAVE_D3D11SDKLAYER_H
346   if ((d3d11_flags & D3D11_CREATE_DEVICE_DEBUG) == D3D11_CREATE_DEVICE_DEBUG) {
347     ID3D11Debug *debug;
348     ID3D11InfoQueue *info_queue;
349
350     hr = ID3D11Device_QueryInterface (priv->device,
351         &IID_ID3D11Debug, (void **) &debug);
352
353     if (SUCCEEDED (hr)) {
354       GST_DEBUG_OBJECT (self, "D3D11Debug interface available");
355       ID3D11Debug_ReportLiveDeviceObjects (debug, D3D11_RLDO_DETAIL);
356       priv->debug = debug;
357     }
358
359     hr = ID3D11Device_QueryInterface (priv->device,
360         &IID_ID3D11InfoQueue, (void **) &info_queue);
361     if (SUCCEEDED (hr)) {
362       GSource *source;
363
364       GST_DEBUG_OBJECT (self, "D3D11InfoQueue interface available");
365       priv->info_queue = info_queue;
366
367       source = g_idle_source_new ();
368       g_source_set_callback (source, (GSourceFunc) gst_d3d11_device_get_message,
369           self, NULL);
370
371       g_source_attach (source, priv->main_context);
372       g_source_unref (source);
373     }
374   }
375 #endif
376
377   g_mutex_lock (&priv->lock);
378   priv->thread = g_thread_new ("GstD3D11Device",
379       (GThreadFunc) gst_d3d11_device_thread_func, self);
380   while (!g_main_loop_is_running (priv->loop))
381     g_cond_wait (&priv->cond, &priv->lock);
382   g_mutex_unlock (&priv->lock);
383
384   G_OBJECT_CLASS (parent_class)->constructed (object);
385
386   return;
387
388 error:
389   if (factory)
390     IDXGIFactory1_Release (factory);
391
392   if (adapter)
393     IDXGIAdapter1_Release (adapter);
394
395   if (adapter_list)
396     g_list_free_full (adapter_list, (GDestroyNotify) _relase_adapter);
397
398   if (hw_adapter_list)
399     g_list_free_full (hw_adapter_list, (GDestroyNotify) _relase_adapter);
400
401   G_OBJECT_CLASS (parent_class)->constructed (object);
402
403   return;
404 }
405
406 static void
407 gst_d3d11_device_set_property (GObject * object, guint prop_id,
408     const GValue * value, GParamSpec * pspec)
409 {
410   GstD3D11Device *self = GST_D3D11_DEVICE (object);
411   GstD3D11DevicePrivate *priv = self->priv;
412
413   switch (prop_id) {
414     case PROP_ADAPTER:
415       priv->adapter = g_value_get_int (value);
416       break;
417     default:
418       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
419       break;
420   }
421 }
422
423 static void
424 gst_d3d11_device_get_property (GObject * object, guint prop_id,
425     GValue * value, GParamSpec * pspec)
426 {
427   GstD3D11Device *self = GST_D3D11_DEVICE (object);
428   GstD3D11DevicePrivate *priv = self->priv;
429
430   switch (prop_id) {
431     case PROP_ADAPTER:
432       g_value_set_int (value, priv->adapter);
433       break;
434     default:
435       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
436       break;
437   }
438 }
439
440 static void
441 gst_d3d11_device_dispose (GObject * object)
442 {
443   GstD3D11Device *self = GST_D3D11_DEVICE (object);
444   GstD3D11DevicePrivate *priv = self->priv;
445
446   GST_LOG_OBJECT (self, "dispose");
447
448   if (priv->loop) {
449     g_main_loop_quit (priv->loop);
450   }
451
452   if (priv->thread) {
453     g_thread_join (priv->thread);
454     priv->thread = NULL;
455   }
456
457   if (priv->loop) {
458     g_main_loop_unref (priv->loop);
459     priv->loop = NULL;
460   }
461
462   if (priv->main_context) {
463     g_main_context_unref (priv->main_context);
464     priv->main_context = NULL;
465   }
466 #ifdef HAVE_D3D11SDKLAYER_H
467   if (priv->debug) {
468     ID3D11Debug_Release (priv->debug);
469     priv->debug = NULL;
470   }
471
472   if (priv->info_queue) {
473     ID3D11InfoQueue_ClearStoredMessages (priv->info_queue);
474     ID3D11InfoQueue_Release (priv->info_queue);
475     priv->info_queue = NULL;
476   }
477 #endif
478
479   if (priv->device) {
480     ID3D11Device_Release (priv->device);
481     priv->device = NULL;
482   }
483
484   if (priv->device_context) {
485     ID3D11DeviceContext_Release (priv->device_context);
486     priv->device_context = NULL;
487   }
488
489   if (priv->video_device) {
490     ID3D11VideoDevice_Release (priv->video_device);
491     priv->video_device = NULL;
492   }
493
494   if (priv->video_context) {
495     ID3D11VideoContext_Release (priv->video_context);
496     priv->video_context = NULL;
497   }
498
499   if (priv->factory) {
500     IDXGIFactory1_Release (priv->factory);
501     priv->factory = NULL;
502   }
503
504   G_OBJECT_CLASS (parent_class)->dispose (object);
505 }
506
507 static void
508 gst_d3d11_device_finalize (GObject * object)
509 {
510   GstD3D11Device *self = GST_D3D11_DEVICE (object);
511   GstD3D11DevicePrivate *priv = self->priv;
512
513   GST_LOG_OBJECT (self, "finalize");
514
515   g_mutex_clear (&priv->lock);
516   g_cond_clear (&priv->cond);
517
518   G_OBJECT_CLASS (parent_class)->finalize (object);
519 }
520
521 static gboolean
522 running_cb (gpointer user_data)
523 {
524   GstD3D11Device *self = GST_D3D11_DEVICE (user_data);
525   GstD3D11DevicePrivate *priv = self->priv;
526
527   GST_TRACE_OBJECT (self, "Main loop running now");
528
529   g_mutex_lock (&priv->lock);
530   g_cond_signal (&priv->cond);
531   g_mutex_unlock (&priv->lock);
532
533   return G_SOURCE_REMOVE;
534 }
535
536 static gpointer
537 gst_d3d11_device_thread_func (gpointer data)
538 {
539   GstD3D11Device *self = GST_D3D11_DEVICE (data);
540   GstD3D11DevicePrivate *priv = self->priv;
541   GSource *source;
542
543   GST_DEBUG_OBJECT (self, "Enter loop");
544   g_main_context_push_thread_default (priv->main_context);
545
546   source = g_idle_source_new ();
547   g_source_set_callback (source, (GSourceFunc) running_cb, self, NULL);
548   g_source_attach (source, priv->main_context);
549   g_source_unref (source);
550
551   priv->active_thread = g_thread_self ();
552   g_main_loop_run (priv->loop);
553
554   g_main_context_pop_thread_default (priv->main_context);
555
556   GST_DEBUG_OBJECT (self, "Exit loop");
557
558   return NULL;
559 }
560
561 /**
562  * gst_d3d11_device_new:
563  * @adapter: the index of adapter for creating d3d11 device (-1 for default)
564  *
565  * Returns: (transfer full) (nullable): a new #GstD3D11Device for @adapter or %NULL
566  * when failed to create D3D11 device with given adapter index.
567  */
568 GstD3D11Device *
569 gst_d3d11_device_new (gint adapter)
570 {
571   GstD3D11Device *device = NULL;
572   GstD3D11DevicePrivate *priv;
573   static volatile gsize _init = 0;
574
575   if (g_once_init_enter (&_init)) {
576     GST_DEBUG_CATEGORY_INIT (gst_d3d11_device_debug, "d3d11device", 0,
577         "d3d11 device");
578     g_once_init_leave (&_init, 1);
579   }
580
581   device = g_object_new (GST_TYPE_D3D11_DEVICE, "adapter", adapter, NULL);
582
583   priv = device->priv;
584
585   if (!priv->device || !priv->device_context) {
586     GST_ERROR ("Cannot create d3d11 device");
587     g_object_unref (device);
588     device = NULL;
589   }
590
591   return device;
592 }
593
594 /**
595  * gst_d3d11_device_get_device:
596  * @device: a #GstD3D11Device
597  *
598  * Used for various D3D11 APIs directly.
599  * Caller must not destroy returned device object.
600  *
601  * Returns: (transfer none): the ID3D11Device
602  */
603 ID3D11Device *
604 gst_d3d11_device_get_device (GstD3D11Device * device)
605 {
606   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
607
608   return device->priv->device;
609 }
610
611 /**
612  * gst_d3d11_device_get_device_context:
613  * @device: a #GstD3D11Device
614  *
615  * Used for various D3D11 APIs directly.
616  * Caller must not destroy returned device object.
617  *
618  * Returns: (transfer none): the ID3D11DeviceContext
619  */
620 ID3D11DeviceContext *
621 gst_d3d11_device_get_device_context (GstD3D11Device * device)
622 {
623   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
624
625   return device->priv->device_context;
626 }
627
628 GstD3D11DXGIFactoryVersion
629 gst_d3d11_device_get_chosen_dxgi_factory_version (GstD3D11Device * device)
630 {
631   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device),
632       GST_D3D11_DXGI_FACTORY_UNKNOWN);
633
634   return device->priv->factory_ver;
635 }
636
637 typedef struct
638 {
639   GstD3D11Device *device;
640   GstD3D11DeviceThreadFunc func;
641
642   gpointer data;
643   gboolean fired;
644 } MessageData;
645
646 static gboolean
647 gst_d3d11_device_message_callback (MessageData * msg)
648 {
649   GstD3D11Device *self = msg->device;
650   GstD3D11DevicePrivate *priv = self->priv;
651
652   msg->func (self, msg->data);
653
654   g_mutex_lock (&priv->lock);
655   msg->fired = TRUE;
656   g_cond_broadcast (&priv->cond);
657   g_mutex_unlock (&priv->lock);
658
659   return G_SOURCE_REMOVE;
660 }
661
662 /**
663  * gst_d3d11_device_thread_add:
664  * @device: a #GstD3D11Device
665  * @func: (scope call): a #GstD3D11DeviceThreadFunc
666  * @data: (closure): user data to call @func with
667  *
668  * Execute @func in the D3DDevice thread of @device with @data
669  *
670  * MT-safe
671  */
672 void
673 gst_d3d11_device_thread_add (GstD3D11Device * device,
674     GstD3D11DeviceThreadFunc func, gpointer data)
675 {
676   GstD3D11DevicePrivate *priv;
677   MessageData msg = { 0, };
678
679   g_return_if_fail (GST_IS_D3D11_DEVICE (device));
680   g_return_if_fail (func != NULL);
681
682   priv = device->priv;
683
684   if (priv->active_thread == g_thread_self ()) {
685     func (device, data);
686     return;
687   }
688
689   msg.device = gst_object_ref (device);
690   msg.func = func;
691   msg.data = data;
692   msg.fired = FALSE;
693
694   g_main_context_invoke (priv->main_context,
695       (GSourceFunc) gst_d3d11_device_message_callback, &msg);
696
697   g_mutex_lock (&priv->lock);
698   while (!msg.fired)
699     g_cond_wait (&priv->cond, &priv->lock);
700   g_mutex_unlock (&priv->lock);
701
702   gst_object_unref (device);
703 }
704
705 typedef struct
706 {
707   IDXGISwapChain *swap_chain;
708   const DXGI_SWAP_CHAIN_DESC *desc;
709 } CreateSwapChainData;
710
711 static void
712 gst_d3d11_device_create_swap_chain_internal (GstD3D11Device * device,
713     CreateSwapChainData * data)
714 {
715   GstD3D11DevicePrivate *priv = device->priv;
716   HRESULT hr;
717
718   hr = IDXGIFactory1_CreateSwapChain (priv->factory, (IUnknown *) priv->device,
719       (DXGI_SWAP_CHAIN_DESC *) data->desc, &data->swap_chain);
720
721   if (FAILED (hr)) {
722     GST_ERROR_OBJECT (device, "Cannot create SwapChain Object: 0x%x",
723         (guint) hr);
724     data->swap_chain = NULL;
725   }
726 }
727
728 /**
729  * gst_d3d11_device_create_swap_chain:
730  * @device: a #GstD3D11Device
731  * @desc: a DXGI_SWAP_CHAIN_DESC structure for swapchain
732  *
733  * Creat a IDXGISwapChain object. Caller must release returned swap chain object
734  * via IDXGISwapChain_Release()
735  *
736  * Returns: (transfer full) (nullable): a new IDXGISwapChain or %NULL
737  * when failed to create swap chain with given @desc
738  */
739 IDXGISwapChain *
740 gst_d3d11_device_create_swap_chain (GstD3D11Device * device,
741     const DXGI_SWAP_CHAIN_DESC * desc)
742 {
743   CreateSwapChainData data = { 0, };
744
745   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
746
747   data.swap_chain = NULL;
748   data.desc = desc;
749
750   gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
751       gst_d3d11_device_create_swap_chain_internal, &data);
752
753   return data.swap_chain;
754 }
755
756 static void
757 gst_d3d11_device_release_swap_chain_internal (GstD3D11Device * device,
758     IDXGISwapChain * swap_chain)
759 {
760   IDXGISwapChain_Release (swap_chain);
761 }
762
763 /**
764  * gst_d3d11_device_release_swap_chain:
765  * @device: a #GstD3D11Device
766  * @swap_chain: a IDXGISwapChain
767  *
768  * Release a @swap_chain from device thread
769  *
770  */
771 void
772 gst_d3d11_device_release_swap_chain (GstD3D11Device * device,
773     IDXGISwapChain * swap_chain)
774 {
775   g_return_if_fail (GST_IS_D3D11_DEVICE (device));
776
777   gst_d3d11_device_thread_add (device,
778       (GstD3D11DeviceThreadFunc) gst_d3d11_device_release_swap_chain_internal,
779       swap_chain);
780 }
781
782 typedef struct
783 {
784   ID3D11Texture2D *texture;
785   const D3D11_TEXTURE2D_DESC *desc;
786   const D3D11_SUBRESOURCE_DATA *inital_data;
787 } CreateTextureData;
788
789 static void
790 gst_d3d11_device_create_texture_internal (GstD3D11Device * device,
791     CreateTextureData * data)
792 {
793   GstD3D11DevicePrivate *priv = device->priv;
794   HRESULT hr;
795
796   hr = ID3D11Device_CreateTexture2D (priv->device, data->desc,
797       data->inital_data, &data->texture);
798   if (FAILED (hr)) {
799     GST_ERROR ("Failed to create staging texture (0x%x)", (guint) hr);
800     data->texture = NULL;
801   }
802 }
803
804 ID3D11Texture2D *
805 gst_d3d11_device_create_texture (GstD3D11Device * device,
806     const D3D11_TEXTURE2D_DESC * desc,
807     const D3D11_SUBRESOURCE_DATA * inital_data)
808 {
809   CreateTextureData data;
810
811   g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
812   g_return_val_if_fail (desc != NULL, NULL);
813
814   data.texture = NULL;
815   data.desc = desc;
816   data.inital_data = inital_data;
817
818   gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
819       gst_d3d11_device_create_texture_internal, &data);
820
821   return data.texture;
822 }
823
824 static void
825 gst_d3d11_device_release_texture_internal (GstD3D11Device * device,
826     ID3D11Texture2D * texture)
827 {
828   ID3D11Texture2D_Release (texture);
829 }
830
831 void
832 gst_d3d11_device_release_texture (GstD3D11Device * device,
833     ID3D11Texture2D * texture)
834 {
835   g_return_if_fail (GST_IS_D3D11_DEVICE (device));
836   g_return_if_fail (texture != NULL);
837
838   gst_d3d11_device_thread_add (device, (GstD3D11DeviceThreadFunc)
839       gst_d3d11_device_release_texture_internal, texture);
840 }
841
842 /**
843  * gst_context_set_d3d11_device:
844  * @context: a #GstContext
845  * @device: (transfer none): resulting #GstD3D11Device
846  *
847  * Sets @device on @context
848  */
849 void
850 gst_context_set_d3d11_device (GstContext * context, GstD3D11Device * device)
851 {
852   GstStructure *s;
853   const gchar *context_type;
854
855   g_return_if_fail (GST_IS_CONTEXT (context));
856   g_return_if_fail (GST_IS_D3D11_DEVICE (device));
857
858   context_type = gst_context_get_context_type (context);
859   if (g_strcmp0 (context_type, GST_D3D11_DEVICE_HANDLE_CONTEXT_TYPE) != 0)
860     return;
861
862   GST_CAT_LOG (GST_CAT_CONTEXT,
863       "setting GstD3DDevice(%" GST_PTR_FORMAT ") on context(%" GST_PTR_FORMAT
864       ")", device, context);
865
866   s = gst_context_writable_structure (context);
867   gst_structure_set (s, "device", GST_TYPE_D3D11_DEVICE, device, NULL);
868 }
869
870 /**
871  * gst_context_get_d3d11_device:
872  * @context: a #GstContext
873  * @device: (out) (transfer full): resulting #GstD3D11Device
874  *
875  * Returns: Whether @device was in @context
876  */
877 gboolean
878 gst_context_get_d3d11_device (GstContext * context, GstD3D11Device ** device)
879 {
880   const GstStructure *s;
881   const gchar *context_type;
882   gboolean ret;
883
884   g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE);
885   g_return_val_if_fail (device != NULL, FALSE);
886
887   context_type = gst_context_get_context_type (context);
888   if (g_strcmp0 (context_type, GST_D3D11_DEVICE_HANDLE_CONTEXT_TYPE) != 0)
889     return FALSE;
890
891   s = gst_context_get_structure (context);
892   ret = gst_structure_get (s, "device", GST_TYPE_D3D11_DEVICE, device, NULL);
893
894   GST_CAT_LOG (GST_CAT_CONTEXT, "got GstD3DDevice(%p) from context(%p)",
895       *device, context);
896
897   return ret;
898 }