1 /*
2 * GStreamer
3 * Copyright (C) 2019 Nirbheek Chauhan <nirbheek@centricular.com>
4 * Copyright (C) 2020 Seungha Yang <seungha@centricular.com>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <gst/gl/gstglcontext.h>
26 #include <gst/gl/egl/gstglcontext_egl.h>
27
28 #include "gstglwindow_winrt_egl.h"
29 #include "../gstglwindow_private.h"
30
31 /* workaround for GetCurrentTime collision */
32 #ifdef GetCurrentTime
33 #undef GetCurrentTime
34 #endif
35 #include <windows.ui.xaml.h>
36 #include <windows.ui.xaml.media.dxinterop.h>
37 #include <windows.applicationmodel.core.h>
38 #include <windows.graphics.display.h>
39 #include <wrl.h>
40 #include <wrl/wrappers/corewrappers.h>
41
42 using namespace Microsoft::WRL;
43 using namespace Microsoft::WRL::Wrappers;
44 using namespace ABI::Windows::UI;
45 using namespace ABI::Windows::Foundation;
46 using namespace ABI::Windows::Foundation::Collections;
47 using namespace ABI::Windows::Graphics;
48
49 #define GST_CAT_DEFAULT gst_gl_window_debug
50
51 /* timeout to wait busy UI thread, 15 seconds */
52 /* XXX: If UI is not responsible in this amount of time, that means
53 * there were something wrong situation at the application side.
54 * Note that ANGLE uses 10 seconds timeout value, so even if a timeout happens
55 * on our side, it would be a timeout condition of ANGLE as well.
56 */
57 #define DEFAULT_ASYNC_TIMEOUT (15 * 1000)
58
59 static void gst_gl_window_winrt_egl_on_resize (GstGLWindow * window,
60 guint width, guint height);
61
62 typedef enum
63 {
64 GST_GL_WINDOW_WINRT_NATIVE_TYPE_NONE = 0,
65 GST_GL_WINDOW_WINRT_NATIVE_TYPE_CORE_WINDOW,
66 GST_GL_WINDOW_WINRT_NATIVE_TYPE_SWAP_CHAIN_PANEL,
67 } GstGLWindowWinRTNativeType;
68
69 template <typename CB>
70 static HRESULT
run_async(const ComPtr<Core::ICoreDispatcher> & dispatcher,DWORD timeout,CB && cb)71 run_async (const ComPtr<Core::ICoreDispatcher> &dispatcher, DWORD timeout,
72 CB &&cb)
73 {
74 ComPtr<IAsyncAction> async_action;
75 HRESULT hr;
76 HRESULT async_hr;
77 boolean can_now;
78 DWORD wait_ret;
79
80 hr = dispatcher->get_HasThreadAccess (&can_now);
81
82 if (FAILED (hr))
83 return hr;
84
85 if (can_now)
86 return cb ();
87
88 Event event (CreateEventEx (NULL, NULL, CREATE_EVENT_MANUAL_RESET,
89 EVENT_ALL_ACCESS));
90
91 if (!event.IsValid())
92 return E_FAIL;
93
94 auto handler =
95 Callback<Implements<RuntimeClassFlags<ClassicCom>,
96 Core::IDispatchedHandler, FtmBase>>([&async_hr, &cb, &event] {
97 async_hr = cb ();
98 SetEvent (event.Get ());
99 return S_OK;
100 });
101
102 hr = dispatcher->RunAsync (Core::CoreDispatcherPriority_Normal,
103 handler.Get (), &async_action);
104
105 if (FAILED (hr))
106 return hr;
107
108 wait_ret = WaitForSingleObjectEx (event.Get (), timeout, true);
109 if (wait_ret != WAIT_OBJECT_0)
110 return E_FAIL;
111
112 return async_hr;
113 }
114
115 /* ICoreWindow resize event handler */
116 typedef ABI::Windows::Foundation::
117 __FITypedEventHandler_2_Windows__CUI__CCore__CCoreWindow_Windows__CUI__CCore__CWindowSizeChangedEventArgs_t
118 IWindowSizeChangedEventHandler;
119
120 static float
get_logical_dpi(void)121 get_logical_dpi (void)
122 {
123 ComPtr<Display::IDisplayPropertiesStatics> properties;
124 HRESULT hr;
125 HStringReference str_ref =
126 HStringReference (RuntimeClass_Windows_Graphics_Display_DisplayProperties);
127
128 hr = GetActivationFactory (str_ref.Get(), properties.GetAddressOf());
129
130 if (SUCCEEDED (hr)) {
131 float dpi = 96.0f;
132
133 hr = properties->get_LogicalDpi (&dpi);
134 if (SUCCEEDED (hr))
135 return dpi;
136 }
137
138 return 96.0f;
139 }
140
dip_to_pixel(float dip,float logical_dpi)141 static inline float dip_to_pixel (float dip, float logical_dpi)
142 {
143 /* https://docs.microsoft.com/en-us/windows/win32/learnwin32/dpi-and-device-independent-pixels */
144 return dip * logical_dpi / 96.0f;
145 }
146
147 class CoreResizeHandler
148 : public RuntimeClass<RuntimeClassFlags<ClassicCom>,
149 IWindowSizeChangedEventHandler>
150 {
151 public:
CoreResizeHandler()152 CoreResizeHandler () {}
RuntimeClassInitialize(GstGLWindow * window)153 HRESULT RuntimeClassInitialize (GstGLWindow * window)
154 {
155 if (!window)
156 return E_INVALIDARG;
157
158 listener_ = window;
159 return S_OK;
160 }
161
IFACEMETHOD(Invoke)162 IFACEMETHOD(Invoke)
163 (Core::ICoreWindow * sender, Core::IWindowSizeChangedEventArgs * args)
164 {
165 Size new_size;
166 HRESULT hr;
167
168 if (!listener_)
169 return S_OK;
170
171 hr = args->get_Size(&new_size);
172 if (SUCCEEDED (hr)) {
173 gint width, height;
174 float dpi;
175
176 dpi = get_logical_dpi ();
177
178 width = (guint) dip_to_pixel (new_size.Width, dpi);
179 height = (guint) dip_to_pixel (new_size.Height, dpi);
180
181 gst_gl_window_winrt_egl_on_resize (listener_, width, height);
182 }
183
184 return S_OK;
185 }
186
187 private:
188 GstGLWindow * listener_;
189 };
190
191 class PanelResizeHandler
192 : public RuntimeClass<RuntimeClassFlags<ClassicCom>,
193 Xaml::ISizeChangedEventHandler>
194 {
195 public:
PanelResizeHandler()196 PanelResizeHandler () {}
RuntimeClassInitialize(GstGLWindow * window)197 HRESULT RuntimeClassInitialize (GstGLWindow * window)
198 {
199 if (!window)
200 return E_INVALIDARG;
201
202 listener_ = window;
203 return S_OK;
204 }
205
IFACEMETHOD(Invoke)206 IFACEMETHOD(Invoke)
207 (IInspectable * sender, Xaml::ISizeChangedEventArgs * args)
208 {
209 Size new_size;
210 HRESULT hr;
211
212 if (!listener_)
213 return S_OK;
214
215 hr = args->get_NewSize(&new_size);
216 if (SUCCEEDED(hr)) {
217 gst_gl_window_winrt_egl_on_resize (listener_,
218 (guint) new_size.Width, (guint) new_size.Height);
219 }
220
221 return S_OK;
222 }
223
224 private:
225 GstGLWindow * listener_;
226 };
227
228 class GstGLWindowWinRTEGLResizeHandler
229 {
230 public:
GstGLWindowWinRTEGLResizeHandler(IInspectable * native_handle,GstGLWindow * listener)231 GstGLWindowWinRTEGLResizeHandler(IInspectable * native_handle,
232 GstGLWindow * listener)
233 : native_type_ (GST_GL_WINDOW_WINRT_NATIVE_TYPE_NONE)
234 , isValid_ (false)
235 {
236 ComPtr<IInspectable> window;
237 HRESULT hr = E_FAIL;
238
239 if (!native_handle) {
240 GST_WARNING ("Null handler");
241 return;
242 }
243
244 window = native_handle;
245 if (SUCCEEDED (window.As (&core_window_))) {
246 GST_INFO ("Valid ICoreWindow");
247 native_type_ = GST_GL_WINDOW_WINRT_NATIVE_TYPE_CORE_WINDOW;
248 core_window_->get_Dispatcher (&dispatcher_);
249 } else if (SUCCEEDED (window.As (&panel_))) {
250 ComPtr<Xaml::IDependencyObject> dependency_obj;
251
252 GST_INFO ("Valid ISwapChainPanel");
253 native_type_ = GST_GL_WINDOW_WINRT_NATIVE_TYPE_SWAP_CHAIN_PANEL;
254 hr = panel_.As (&dependency_obj);
255 if (FAILED (hr)) {
256 GST_WARNING ("Couldn't get IDependencyObject interface");
257 return;
258 }
259
260 dependency_obj->get_Dispatcher (&dispatcher_);
261 } else {
262 GST_ERROR ("Invalid window handle");
263 return;
264 }
265
266 if (!dispatcher_) {
267 GST_WARNING ("ICoreDispatcher is unavailable");
268 return;
269 }
270
271 switch (native_type_) {
272 case GST_GL_WINDOW_WINRT_NATIVE_TYPE_CORE_WINDOW:
273 if (!registerSizeChangedHandlerForCoreWindow (listener)) {
274 GST_WARNING
275 ("Couldn't install size changed event handler for corewindow");
276 return;
277 }
278 break;
279 case GST_GL_WINDOW_WINRT_NATIVE_TYPE_SWAP_CHAIN_PANEL:
280 if (!registerSizeChangedHandlerForSwapChainPanel (listener)) {
281 GST_WARNING
282 ("Couldn't install size changed event handler for swapchainpanel");
283 return;
284 }
285 break;
286 default:
287 g_assert_not_reached ();
288 return;
289 }
290
291 isValid_ = true;
292 }
293
~GstGLWindowWinRTEGLResizeHandler()294 ~GstGLWindowWinRTEGLResizeHandler()
295 {
296 if (!isValid_ || !dispatcher_)
297 return;
298
299 switch (native_type_) {
300 case GST_GL_WINDOW_WINRT_NATIVE_TYPE_CORE_WINDOW:
301 unregisterSizeChangedHandlerForCoreWindow ();
302 break;
303 case GST_GL_WINDOW_WINRT_NATIVE_TYPE_SWAP_CHAIN_PANEL:
304 unregisterSizeChangedHandlerForSwapChainPanel ();
305 break;
306 default:
307 g_assert_not_reached ();
308 return;
309 }
310 }
311
312 bool
IsValid(void)313 IsValid (void)
314 {
315 return isValid_;
316 }
317
318 bool
GetWindowSize(guint * width,guint * height)319 GetWindowSize (guint * width, guint * height)
320 {
321 bool ret = true;
322
323 if (!isValid_)
324 return false;
325
326 switch (native_type_) {
327 case GST_GL_WINDOW_WINRT_NATIVE_TYPE_CORE_WINDOW:
328 return getWindowSizeForCoreWindow (width, height);
329 case GST_GL_WINDOW_WINRT_NATIVE_TYPE_SWAP_CHAIN_PANEL:
330 return getWindowSizeForSwapChainPanel (width, height);
331 default:
332 g_assert_not_reached ();
333 break;
334 }
335
336 return false;
337 }
338
339 HRESULT
GetHasThreadAccess(bool & has_access)340 GetHasThreadAccess (bool &has_access)
341 {
342 HRESULT hr;
343 boolean val;
344
345 if (!isValid_ || !dispatcher_)
346 return E_FAIL;
347
348 hr = dispatcher_->get_HasThreadAccess (&val);
349 if (FAILED (hr))
350 return hr;
351
352 if (val)
353 has_access = true;
354 else
355 has_access = false;
356
357 return hr;
358 }
359
360 private:
361 bool
registerSizeChangedHandlerForCoreWindow(GstGLWindow * window)362 registerSizeChangedHandlerForCoreWindow (GstGLWindow * window)
363 {
364 ComPtr<IWindowSizeChangedEventHandler> resize_handler;
365 HRESULT hr;
366
367 hr = MakeAndInitialize<CoreResizeHandler>(&resize_handler, window);
368 if (FAILED (hr)) {
369 GST_WARNING ("Couldn't creat resize handler object");
370 return false;
371 }
372
373 hr = run_async (dispatcher_, DEFAULT_ASYNC_TIMEOUT,
374 [this, resize_handler] {
375 return core_window_->add_SizeChanged (resize_handler.Get(),
376 &event_token_);
377 });
378
379 if (FAILED (hr)) {
380 GST_WARNING ("Couldn't install resize handler");
381 return false;
382 }
383
384 return true;
385 }
386
387 bool
registerSizeChangedHandlerForSwapChainPanel(GstGLWindow * window)388 registerSizeChangedHandlerForSwapChainPanel (GstGLWindow * window)
389 {
390 ComPtr<Xaml::ISizeChangedEventHandler> resize_handler;
391 ComPtr<Xaml::IFrameworkElement> framework;
392 HRESULT hr;
393
394 hr = MakeAndInitialize<PanelResizeHandler>(&resize_handler, window);
395 if (FAILED (hr)) {
396 GST_WARNING ("Couldn't creat resize handler object");
397 return false;
398 }
399
400 hr = panel_.As (&framework);
401 if (FAILED (hr)) {
402 GST_WARNING ("Couldn't get IFrameworkElement interface");
403 return false;
404 }
405
406 hr = run_async (dispatcher_, DEFAULT_ASYNC_TIMEOUT,
407 [this, framework, resize_handler] {
408 return framework->add_SizeChanged (resize_handler.Get(),
409 &event_token_);
410 });
411
412 if (FAILED (hr)) {
413 GST_WARNING ("Couldn't install resize handler");
414 return false;
415 }
416
417 return true;
418 }
419
420 void
unregisterSizeChangedHandlerForCoreWindow(void)421 unregisterSizeChangedHandlerForCoreWindow (void)
422 {
423 run_async (dispatcher_, DEFAULT_ASYNC_TIMEOUT,
424 [this] {
425 core_window_->remove_SizeChanged(event_token_);
426 return S_OK;
427 });
428 }
429
430 void
unregisterSizeChangedHandlerForSwapChainPanel(void)431 unregisterSizeChangedHandlerForSwapChainPanel (void)
432 {
433 ComPtr<Xaml::IFrameworkElement> framework;
434 HRESULT hr;
435
436 hr = panel_.As (&framework);
437 if (SUCCEEDED (hr)) {
438 run_async (dispatcher_, DEFAULT_ASYNC_TIMEOUT,
439 [this, framework] {
440 return framework->remove_SizeChanged (event_token_);
441 });
442 }
443 }
444
445 bool
getWindowSizeForCoreWindow(guint * width,guint * height)446 getWindowSizeForCoreWindow (guint * width, guint * height)
447 {
448 HRESULT hr;
449
450 hr = run_async (dispatcher_, DEFAULT_ASYNC_TIMEOUT,
451 [this, width, height] {
452 HRESULT async_hr;
453 Rect bounds;
454
455 async_hr = core_window_->get_Bounds (&bounds);
456 if (SUCCEEDED (async_hr)) {
457 float dpi;
458
459 dpi = get_logical_dpi ();
460
461 *width = (guint) dip_to_pixel (bounds.Width, dpi);
462 *height = (guint) dip_to_pixel (bounds.Height, dpi);
463 }
464
465 return async_hr;
466 });
467
468 return SUCCEEDED (hr);
469 }
470
471 bool
getWindowSizeForSwapChainPanel(guint * width,guint * height)472 getWindowSizeForSwapChainPanel (guint * width, guint * height)
473 {
474 HRESULT hr;
475 ComPtr<Xaml::IUIElement> ui;
476
477 hr = panel_.As (&ui);
478 if (FAILED (hr))
479 return false;
480
481 hr = run_async (dispatcher_, DEFAULT_ASYNC_TIMEOUT,
482 [ui, width, height] {
483 Size size;
484 HRESULT async_hr;
485
486 async_hr = ui->get_RenderSize (&size);
487 if (SUCCEEDED (async_hr)) {
488 *width = (guint) size.Width;
489 *height = (guint) size.Height;
490 }
491
492 return async_hr;
493 });
494
495 return SUCCEEDED (hr);
496 }
497
498 private:
499 GstGLWindowWinRTNativeType native_type_;
500 ComPtr<Core::ICoreDispatcher> dispatcher_;
501
502 ComPtr<Core::ICoreWindow> core_window_;
503 ComPtr<Xaml::Controls::ISwapChainPanel> panel_;
504
505 EventRegistrationToken event_token_;
506 bool isValid_;
507 };
508
509 struct _GstGLWindowWinRTEGLPrivate
510 {
511 GstGLWindowWinRTEGLResizeHandler *resize_handler;
512 guint surface_width;
513 guint surface_height;
514 GMutex event_lock;
515 };
516
517 #define gst_gl_window_winrt_egl_parent_class parent_class
518 G_DEFINE_TYPE_WITH_PRIVATE (GstGLWindowWinRTEGL, gst_gl_window_winrt_egl,
519 GST_TYPE_GL_WINDOW);
520
521 static void gst_gl_window_winrt_egl_dispose (GObject * object);
522 static void gst_gl_window_winrt_egl_finalize (GObject * object);
523 static guintptr gst_gl_window_winrt_egl_get_display (GstGLWindow * window);
524 static guintptr gst_gl_window_winrt_egl_get_window_handle (GstGLWindow *
525 window);
526 static void gst_gl_window_winrt_egl_set_window_handle (GstGLWindow * window,
527 guintptr handle);
528 static void gst_gl_window_winrt_egl_show (GstGLWindow * window);
529 static void gst_gl_window_winrt_egl_quit (GstGLWindow * window);
530
531 static void
gst_gl_window_winrt_egl_class_init(GstGLWindowWinRTEGLClass * klass)532 gst_gl_window_winrt_egl_class_init (GstGLWindowWinRTEGLClass * klass)
533 {
534 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
535 GstGLWindowClass *window_class = (GstGLWindowClass *) klass;
536
537 gobject_class->dispose = gst_gl_window_winrt_egl_dispose;
538 gobject_class->finalize = gst_gl_window_winrt_egl_finalize;
539
540 window_class->get_display =
541 GST_DEBUG_FUNCPTR (gst_gl_window_winrt_egl_get_display);
542 window_class->get_window_handle =
543 GST_DEBUG_FUNCPTR (gst_gl_window_winrt_egl_get_window_handle);
544 window_class->set_window_handle =
545 GST_DEBUG_FUNCPTR (gst_gl_window_winrt_egl_set_window_handle);
546 window_class->show =
547 GST_DEBUG_FUNCPTR (gst_gl_window_winrt_egl_show);
548 window_class->quit =
549 GST_DEBUG_FUNCPTR (gst_gl_window_winrt_egl_quit);
550 }
551
552 static void
gst_gl_window_winrt_egl_init(GstGLWindowWinRTEGL * window_winrt)553 gst_gl_window_winrt_egl_init (GstGLWindowWinRTEGL * window_winrt)
554 {
555 window_winrt->priv = (GstGLWindowWinRTEGLPrivate *)
556 gst_gl_window_winrt_egl_get_instance_private (window_winrt);
557
558 g_mutex_init (&window_winrt->priv->event_lock);
559 }
560
561 static void
gst_gl_window_winrt_egl_dispose(GObject * object)562 gst_gl_window_winrt_egl_dispose (GObject * object)
563 {
564 GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (object);
565 GstGLWindowWinRTEGLPrivate *priv = window_egl->priv;
566
567 if (priv->resize_handler) {
568 delete priv->resize_handler;
569 priv->resize_handler = nullptr;
570 }
571
572 G_OBJECT_CLASS (parent_class)->dispose (object);
573 }
574
575 static void
gst_gl_window_winrt_egl_finalize(GObject * object)576 gst_gl_window_winrt_egl_finalize (GObject * object)
577 {
578 GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (object);
579 GstGLWindowWinRTEGLPrivate *priv = window_egl->priv;
580
581 g_mutex_clear (&priv->event_lock);
582
583 G_OBJECT_CLASS (parent_class)->finalize (object);
584 }
585
586 static void
gst_gl_window_winrt_egl_set_window_handle(GstGLWindow * window,guintptr handle)587 gst_gl_window_winrt_egl_set_window_handle (GstGLWindow * window,
588 guintptr handle)
589 {
590 GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (window);
591 GstGLWindowWinRTEGLPrivate *priv = window_egl->priv;
592
593 GST_INFO_OBJECT (window, "Setting WinRT EGL window handle: %p", handle);
594
595 window_egl->window = (EGLNativeWindowType) handle;
596
597 if (priv->resize_handler)
598 delete priv->resize_handler;
599 priv->resize_handler = nullptr;
600
601 if (!handle) {
602 GST_WARNING_OBJECT (window, "NULL window handle");
603 return;
604 }
605
606 priv->resize_handler =
607 new GstGLWindowWinRTEGLResizeHandler
608 (reinterpret_cast<IInspectable*> (handle), window);
609
610 if (!priv->resize_handler->IsValid ()) {
611 GST_WARNING_OBJECT (window,
612 "Invalid window handle %" G_GUINTPTR_FORMAT, handle);
613 delete priv->resize_handler;
614 priv->resize_handler = nullptr;
615 }
616 }
617
618 static guintptr
gst_gl_window_winrt_egl_get_window_handle(GstGLWindow * window)619 gst_gl_window_winrt_egl_get_window_handle (GstGLWindow * window)
620 {
621 GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (window);
622
623 GST_INFO_OBJECT (window, "Getting WinRT EGL window handle");
624
625 return (guintptr) window_egl->window;
626 }
627
628 /* Must be called in the gl thread */
629 GstGLWindowWinRTEGL *
gst_gl_window_winrt_egl_new(GstGLDisplay * display)630 gst_gl_window_winrt_egl_new (GstGLDisplay * display)
631 {
632 GstGLWindowWinRTEGL *window_egl;
633
634 GST_INFO_OBJECT (display, "Trying to create WinRT EGL window");
635
636 if ((gst_gl_display_get_handle_type (display) & GST_GL_DISPLAY_TYPE_EGL) == 0)
637 /* we require an EGL display to create windows */
638 return NULL;
639
640 GST_INFO_OBJECT (display, "Creating WinRT EGL window");
641
642 window_egl = (GstGLWindowWinRTEGL *)
643 g_object_new (GST_TYPE_GL_WINDOW_WINRT_EGL, NULL);
644
645 return window_egl;
646 }
647
648 static guintptr
gst_gl_window_winrt_egl_get_display(GstGLWindow * window)649 gst_gl_window_winrt_egl_get_display (GstGLWindow * window)
650 {
651 /* EGL_DEFAULT_DISPLAY */
652 return 0;
653 }
654
655 static void
gst_gl_window_winrt_egl_show(GstGLWindow * window)656 gst_gl_window_winrt_egl_show (GstGLWindow * window)
657 {
658 GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (window);
659 GstGLWindowWinRTEGLPrivate *priv = window_egl->priv;
660 guint width, height;
661 gboolean resize = FALSE;
662
663 if (!priv->resize_handler)
664 return;
665
666 g_mutex_lock (&priv->event_lock);
667 if (!priv->surface_width || !priv->surface_height) {
668 if (priv->resize_handler->GetWindowSize (&width, &height)) {
669 GST_INFO_OBJECT (window, "Client window size %dx%d", width, height);
670 priv->surface_width = width;
671 priv->surface_height = height;
672 resize = TRUE;
673 }
674 }
675 g_mutex_unlock (&priv->event_lock);
676
677 if (resize)
678 gst_gl_window_resize (window, width, height);
679 }
680
681 static void
gst_gl_window_winrt_egl_on_resize(GstGLWindow * window,guint width,guint height)682 gst_gl_window_winrt_egl_on_resize (GstGLWindow * window,
683 guint width, guint height)
684 {
685 GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (window);
686 GstGLWindowWinRTEGLPrivate *priv = window_egl->priv;
687
688 GST_DEBUG_OBJECT (window, "New client window size %dx%d", width, height);
689
690 g_mutex_lock (&priv->event_lock);
691 priv->surface_width = width;
692 priv->surface_height = height;
693 g_mutex_unlock (&priv->event_lock);
694
695 gst_gl_window_resize (window, width, height);
696 }
697
698 static void
gst_gl_window_winrt_egl_quit(GstGLWindow * window)699 gst_gl_window_winrt_egl_quit (GstGLWindow * window)
700 {
701 GstGLWindowWinRTEGL *window_egl = GST_GL_WINDOW_WINRT_EGL (window);
702 GstGLWindowWinRTEGLPrivate *priv = window_egl->priv;
703
704 if (priv->resize_handler) {
705 HRESULT hr;
706 bool is_dispatcher_thread = false;
707
708 hr = priv->resize_handler->GetHasThreadAccess (is_dispatcher_thread);
709 if (SUCCEEDED (hr) && is_dispatcher_thread) {
710 /* In GstGLContext::destroy_context() -> eglDestroySurface(),
711 * ANGLE will wait a UI thread for its own operations to be called
712 * from the thread. Note that gst_gl_context_egl_destroy_context() will be
713 * called from GstGLContext's internal GL thread.
714 *
715 * A problem is that if GstGLWindow is being closed from the UI thread,
716 * ANGLE cannot access the UI thread as current thread is the thread.
717 */
718 GST_ERROR_OBJECT (window,
719 "Closing from a UI thread might cause a deadlock or crash");
720
721 g_warning ("GstGLWindowWinRTEGL should be closed from non-UI thread");
722 }
723 }
724
725 GST_GL_WINDOW_CLASS (parent_class)->quit (window);
726 }
727