3 * Copyright (C) 2008 Julien Isorce <julien.isorce@gmail.com>
4 * Copyright (C) 2012 Matthew Waters <ystreet00@gmail.com>
5 * Copyright (C) 2019 Seungha Yang <seungha.yang@navercorp.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
27 #include "gstd3d11window_win32.h"
32 GST_DEBUG_CATEGORY_EXTERN (gst_d3d11_window_debug);
33 #define GST_CAT_DEFAULT gst_d3d11_window_debug
38 G_LOCK_DEFINE_STATIC (create_lock);
40 #define EXTERNAL_PROC_PROP_NAME "d3d11_window_external_proc"
41 #define D3D11_WINDOW_PROP_NAME "gst_d3d11_window_win32_object"
43 #define WM_GST_D3D11_FULLSCREEN (WM_USER + 1)
44 #define WM_GST_D3D11_CONSTRUCT_INTERNAL_WINDOW (WM_USER + 2)
46 static LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
48 static LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam,
53 GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE = 0,
54 GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED,
55 GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED,
56 } GstD3D11WindowWin32OverlayState;
58 struct _GstD3D11WindowWin32
60 GstD3D11Window parent;
65 GMainContext *main_context;
71 GIOChannel *msg_io_channel;
77 GstD3D11WindowWin32OverlayState overlay_state;
80 gboolean first_present;
81 gboolean have_swapchain1;
84 volatile gint pending_fullscreen_count;
86 /* fullscreen related */
91 #define gst_d3d11_window_win32_parent_class parent_class
92 G_DEFINE_TYPE (GstD3D11WindowWin32, gst_d3d11_window_win32,
93 GST_TYPE_D3D11_WINDOW);
95 static void gst_d3d11_window_win32_constructed (GObject * object);
96 static void gst_d3d11_window_win32_dispose (GObject * object);
97 static void gst_d3d11_window_win32_finalize (GObject * object);
99 static void gst_d3d11_window_win32_show (GstD3D11Window * window);
100 static void gst_d3d11_window_win32_update_swap_chain (GstD3D11Window * window);
102 gst_d3d11_window_win32_change_fullscreen_mode (GstD3D11Window * window);
104 gst_d3d11_window_win32_create_swap_chain (GstD3D11Window * window,
105 DXGI_FORMAT format, guint width, guint height,
106 guint swapchain_flags, IDXGISwapChain ** swap_chain);
107 static GstFlowReturn gst_d3d11_window_win32_present (GstD3D11Window * window,
108 guint present_flags);
110 static gpointer gst_d3d11_window_win32_thread_func (gpointer data);
112 gst_d3d11_window_win32_create_internal_window (GstD3D11WindowWin32 * self);
113 static void gst_d3d11_window_win32_close_internal_window (GstD3D11WindowWin32 *
115 static void gst_d3d11_window_win32_release_external_handle (GstD3D11WindowWin32
118 gst_d3d11_window_win32_set_window_handle (GstD3D11WindowWin32 * self,
121 gst_d3d11_window_win32_on_resize (GstD3D11Window * window,
122 guint width, guint height);
123 static void gst_d3d11_window_win32_unprepare (GstD3D11Window * window);
126 gst_d3d11_window_win32_class_init (GstD3D11WindowWin32Class * klass)
128 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
129 GstD3D11WindowClass *window_class = GST_D3D11_WINDOW_CLASS (klass);
131 gobject_class->constructed = gst_d3d11_window_win32_constructed;
132 gobject_class->dispose = gst_d3d11_window_win32_dispose;
133 gobject_class->finalize = gst_d3d11_window_win32_finalize;
135 window_class->show = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_show);
136 window_class->update_swap_chain =
137 GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_update_swap_chain);
138 window_class->change_fullscreen_mode =
139 GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_change_fullscreen_mode);
140 window_class->create_swap_chain =
141 GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_create_swap_chain);
142 window_class->present = GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_present);
143 window_class->on_resize =
144 GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_on_resize);
145 window_class->unprepare =
146 GST_DEBUG_FUNCPTR (gst_d3d11_window_win32_unprepare);
150 gst_d3d11_window_win32_init (GstD3D11WindowWin32 * self)
152 g_mutex_init (&self->lock);
153 g_cond_init (&self->cond);
155 self->main_context = g_main_context_new ();
159 gst_d3d11_window_win32_constructed (GObject * object)
161 GstD3D11Window *window = GST_D3D11_WINDOW (object);
162 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (object);
164 if (window->external_handle) {
165 gst_d3d11_window_win32_set_window_handle (self, window->external_handle);
169 g_mutex_lock (&self->lock);
170 self->loop = g_main_loop_new (self->main_context, FALSE);
171 self->thread = g_thread_new ("GstD3D11WindowWin32",
172 (GThreadFunc) gst_d3d11_window_win32_thread_func, self);
173 while (!g_main_loop_is_running (self->loop))
174 g_cond_wait (&self->cond, &self->lock);
175 g_mutex_unlock (&self->lock);
178 G_OBJECT_CLASS (parent_class)->constructed (object);
182 gst_d3d11_window_win32_dispose (GObject * object)
184 gst_d3d11_window_win32_unprepare (GST_D3D11_WINDOW (object));
186 G_OBJECT_CLASS (parent_class)->dispose (object);
190 gst_d3d11_window_win32_unprepare (GstD3D11Window * window)
192 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
194 gst_d3d11_window_win32_release_external_handle (self);
197 g_main_loop_quit (self->loop);
201 g_thread_join (self->thread);
206 g_main_loop_unref (self->loop);
210 if (self->main_context) {
211 g_main_context_unref (self->main_context);
212 self->main_context = NULL;
215 gst_d3d11_window_win32_close_internal_window (self);
219 gst_d3d11_window_win32_finalize (GObject * object)
221 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (object);
223 g_mutex_clear (&self->lock);
224 g_cond_clear (&self->cond);
226 G_OBJECT_CLASS (parent_class)->finalize (object);
230 running_cb (gpointer user_data)
232 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (user_data);
234 GST_TRACE_OBJECT (self, "Main loop running now");
236 g_mutex_lock (&self->lock);
237 g_cond_signal (&self->cond);
238 g_mutex_unlock (&self->lock);
240 return G_SOURCE_REMOVE;
244 msg_cb (GIOChannel * source, GIOCondition condition, gpointer data)
248 if (!PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
249 return G_SOURCE_CONTINUE;
251 TranslateMessage (&msg);
252 DispatchMessage (&msg);
254 return G_SOURCE_CONTINUE;
258 gst_d3d11_window_win32_thread_func (gpointer data)
260 GstD3D11Window *window = GST_D3D11_WINDOW (data);
261 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (data);
264 GST_DEBUG_OBJECT (self, "Enter loop");
265 g_main_context_push_thread_default (self->main_context);
267 window->initialized = gst_d3d11_window_win32_create_internal_window (self);
269 self->msg_io_channel =
270 g_io_channel_win32_new_messages ((guintptr) self->internal_hwnd);
271 self->msg_source = g_io_create_watch (self->msg_io_channel, G_IO_IN);
272 g_source_set_callback (self->msg_source, (GSourceFunc) msg_cb, self, NULL);
273 g_source_attach (self->msg_source, self->main_context);
275 source = g_idle_source_new ();
276 g_source_set_callback (source, (GSourceFunc) running_cb, self, NULL);
277 g_source_attach (source, self->main_context);
278 g_source_unref (source);
280 g_main_loop_run (self->loop);
282 gst_d3d11_window_win32_close_internal_window (self);
284 g_main_context_pop_thread_default (self->main_context);
286 GST_DEBUG_OBJECT (self, "Exit loop");
292 gst_d3d11_window_win32_close_internal_window (GstD3D11WindowWin32 * self)
294 if (self->internal_hwnd) {
295 RemoveProp (self->internal_hwnd, D3D11_WINDOW_PROP_NAME);
296 ShowWindow (self->internal_hwnd, SW_HIDE);
297 SetParent (self->internal_hwnd, NULL);
298 if (!DestroyWindow (self->internal_hwnd))
299 GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT
300 ", 0x%x", (guintptr) self->internal_hwnd, (guint) GetLastError ());
301 self->internal_hwnd = NULL;
304 if (self->msg_source) {
305 g_source_destroy (self->msg_source);
306 g_source_unref (self->msg_source);
307 self->msg_source = NULL;
310 if (self->msg_io_channel) {
311 g_io_channel_unref (self->msg_io_channel);
312 self->msg_io_channel = NULL;
317 gst_d3d11_window_win32_set_external_handle (GstD3D11WindowWin32 * self)
319 WNDPROC external_window_proc;
321 external_window_proc =
322 (WNDPROC) GetWindowLongPtr (self->external_hwnd, GWLP_WNDPROC);
324 GST_DEBUG_OBJECT (self, "set external window %" G_GUINTPTR_FORMAT
325 ", original window procedure %p", (guintptr) self->external_hwnd,
326 external_window_proc);
328 SetProp (self->external_hwnd, EXTERNAL_PROC_PROP_NAME,
329 (HANDLE) external_window_proc);
330 SetProp (self->external_hwnd, D3D11_WINDOW_PROP_NAME, self);
331 SetWindowLongPtr (self->external_hwnd, GWLP_WNDPROC,
332 (LONG_PTR) sub_class_proc);
334 /* Will create our internal window on parent window's thread */
335 SendMessage (self->external_hwnd, WM_GST_D3D11_CONSTRUCT_INTERNAL_WINDOW,
340 gst_d3d11_window_win32_release_external_handle (GstD3D11WindowWin32 * self)
342 WNDPROC external_proc;
344 if (!self->external_hwnd)
348 (WNDPROC) GetProp (self->external_hwnd, EXTERNAL_PROC_PROP_NAME);
352 GST_DEBUG_OBJECT (self, "release external window %" G_GUINTPTR_FORMAT
353 ", original window procedure %p", (guintptr) self->external_hwnd,
356 if (!SetWindowLongPtr (self->external_hwnd,
357 GWLP_WNDPROC, (LONG_PTR) external_proc)) {
358 GST_WARNING_OBJECT (self, "Couldn't restore original window procedure");
361 RemoveProp (self->external_hwnd, EXTERNAL_PROC_PROP_NAME);
362 RemoveProp (self->external_hwnd, D3D11_WINDOW_PROP_NAME);
363 self->external_hwnd = NULL;
367 gst_d3d11_window_win32_create_internal_window (GstD3D11WindowWin32 * self)
371 HINSTANCE hinstance = GetModuleHandle (NULL);
373 GST_LOG_OBJECT (self, "Attempting to create a win32 window");
375 G_LOCK (create_lock);
376 atom = GetClassInfoEx (hinstance, "GSTD3D11", &wc);
378 GST_LOG_OBJECT (self, "Register internal window class");
379 ZeroMemory (&wc, sizeof (WNDCLASSEX));
381 wc.cbSize = sizeof (WNDCLASSEX);
382 wc.lpfnWndProc = window_proc;
383 wc.hInstance = hinstance;
384 wc.hIcon = LoadIcon (NULL, IDI_WINLOGO);
385 wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
386 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
387 wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
388 wc.lpszClassName = "GSTD3D11";
390 atom = RegisterClassEx (&wc);
393 G_UNLOCK (create_lock);
394 GST_ERROR_OBJECT (self, "Failed to register window class 0x%x",
395 (unsigned int) GetLastError ());
399 GST_LOG_OBJECT (self, "window class was already registered");
402 self->device_handle = 0;
403 self->internal_hwnd = 0;
404 self->visible = FALSE;
406 self->internal_hwnd = CreateWindowEx (0,
408 "Direct3D11 renderer",
409 WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW,
410 CW_USEDEFAULT, CW_USEDEFAULT,
411 0, 0, (HWND) NULL, (HMENU) NULL, hinstance, self);
413 G_UNLOCK (create_lock);
415 if (!self->internal_hwnd) {
416 GST_ERROR_OBJECT (self, "Failed to create d3d11 window");
420 GST_DEBUG_OBJECT (self, "d3d11 window created: %" G_GUINTPTR_FORMAT,
421 (guintptr) self->internal_hwnd);
423 /* device_handle is set in the window_proc */
424 if (!self->device_handle) {
425 GST_ERROR_OBJECT (self, "device handle is not available");
429 GST_LOG_OBJECT (self,
430 "Created a internal d3d11 window %p", self->internal_hwnd);
435 /* always called from window thread */
437 gst_d3d11_window_win32_change_fullscreen_mode_internal (GstD3D11WindowWin32 *
440 GstD3D11Window *window = GST_D3D11_WINDOW (self);
441 HWND hwnd = self->external_hwnd ? self->external_hwnd : self->internal_hwnd;
443 if (!window->swap_chain)
446 if (window->requested_fullscreen == window->fullscreen)
449 GST_DEBUG_OBJECT (self, "Change mode to %s",
450 window->requested_fullscreen ? "fullscreen" : "windowed");
452 window->fullscreen = !window->fullscreen;
454 if (!window->fullscreen) {
455 /* Restore the window's attributes and size */
456 SetWindowLong (hwnd, GWL_STYLE, self->restore_style);
458 SetWindowPos (hwnd, HWND_NOTOPMOST,
459 self->restore_rect.left,
460 self->restore_rect.top,
461 self->restore_rect.right - self->restore_rect.left,
462 self->restore_rect.bottom - self->restore_rect.top,
463 SWP_FRAMECHANGED | SWP_NOACTIVATE);
465 ShowWindow (hwnd, SW_NORMAL);
468 DXGI_OUTPUT_DESC output_desc;
469 IDXGISwapChain *swap_chain = window->swap_chain;
471 /* show window before change style */
472 ShowWindow (hwnd, SW_SHOW);
474 /* Save the old window rect so we can restore it when exiting
476 GetWindowRect (hwnd, &self->restore_rect);
477 self->restore_style = GetWindowLong (hwnd, GWL_STYLE);
479 /* Make the window borderless so that the client area can fill the screen */
480 SetWindowLong (hwnd, GWL_STYLE,
481 self->restore_style &
482 ~(WS_CAPTION | WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_SYSMENU |
485 swap_chain->GetContainingOutput (&output);
486 output->GetDesc (&output_desc);
489 SetWindowPos (hwnd, HWND_TOPMOST,
490 output_desc.DesktopCoordinates.left,
491 output_desc.DesktopCoordinates.top,
492 output_desc.DesktopCoordinates.right,
493 output_desc.DesktopCoordinates.bottom,
494 SWP_FRAMECHANGED | SWP_NOACTIVATE);
496 ShowWindow (hwnd, SW_MAXIMIZE);
499 GST_DEBUG_OBJECT (self, "Fullscreen mode change done");
503 gst_d3d11_window_win32_on_key_event (GstD3D11WindowWin32 * self,
504 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
506 GstD3D11Window *window = GST_D3D11_WINDOW (self);
507 gunichar2 wcrep[128];
510 if (!window->enable_navigation_events)
513 if (GetKeyNameTextW (lParam, (LPWSTR) wcrep, 128)) {
514 gchar *utfrep = g_utf16_to_utf8 (wcrep, 128, NULL, NULL, NULL);
516 if (uMsg == WM_KEYDOWN)
519 event = "key-release";
521 gst_d3d11_window_on_key_event (window, event, utfrep);
528 gst_d3d11_window_win32_on_mouse_event (GstD3D11WindowWin32 * self,
529 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
531 GstD3D11Window *window = GST_D3D11_WINDOW (self);
533 const gchar *event = NULL;
535 if (!window->enable_navigation_events)
538 /* FIXME: convert to render coordinate */
542 event = "mouse-move";
546 event = "mouse-button-press";
550 event = "mouse-button-release";
554 event = "mouse-button-press";
558 event = "mouse-button-release";
562 event = "mouse-button-press";
566 event = "mouse-button-release";
573 gst_d3d11_window_on_mouse_event (window,
574 event, button, (gdouble) LOWORD (lParam), (gdouble) HIWORD (lParam));
578 gst_d3d11_window_win32_handle_window_proc (GstD3D11WindowWin32 * self,
579 HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
581 GstD3D11Window *window = GST_D3D11_WINDOW (self);
585 gst_d3d11_window_win32_on_resize (window, 0, 0);
588 if (self->internal_hwnd) {
589 ShowWindow (self->internal_hwnd, SW_HIDE);
590 gst_d3d11_window_win32_close_internal_window (self);
595 gst_d3d11_window_win32_on_key_event (self, hWnd, uMsg, wParam, lParam);
604 /* To handle mouse event only once, do this only for internal window */
605 if (self->internal_hwnd && self->internal_hwnd == hWnd)
606 gst_d3d11_window_win32_on_mouse_event (self, hWnd, uMsg, wParam,
609 /* DefWindowProc will not chain up mouse event to parent window */
610 if (self->external_hwnd && self->external_hwnd != hWnd)
611 SendMessage (self->external_hwnd, uMsg, wParam, lParam);
614 if ((window->fullscreen_toggle_mode &
615 GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER)
616 == GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_ALT_ENTER) {
617 WORD state = GetKeyState (VK_RETURN);
618 BYTE high = HIBYTE (state);
621 window->requested_fullscreen = !window->fullscreen;
622 gst_d3d11_window_win32_change_fullscreen_mode_internal (self);
626 case WM_GST_D3D11_FULLSCREEN:
627 if (g_atomic_int_get (&self->pending_fullscreen_count)) {
628 g_atomic_int_dec_and_test (&self->pending_fullscreen_count);
629 if ((window->fullscreen_toggle_mode &
630 GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY)
631 == GST_D3D11_WINDOW_FULLSCREEN_TOGGLE_MODE_PROPERTY)
632 gst_d3d11_window_win32_change_fullscreen_mode_internal (self);
642 static LRESULT CALLBACK
643 window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
645 GstD3D11WindowWin32 *self;
647 if (uMsg == WM_CREATE) {
648 self = GST_D3D11_WINDOW_WIN32 (((LPCREATESTRUCT) lParam)->lpCreateParams);
650 GST_LOG_OBJECT (self, "WM_CREATE");
652 self->device_handle = GetDC (hWnd);
653 /* Do this, otherwise we hang on exit. We can still use it (due to the
654 * CS_OWNDC flag in the WindowClass) after we have Released.
656 ReleaseDC (hWnd, self->device_handle);
658 SetProp (hWnd, D3D11_WINDOW_PROP_NAME, self);
659 } else if (GetProp (hWnd, D3D11_WINDOW_PROP_NAME)) {
660 HANDLE handle = GetProp (hWnd, D3D11_WINDOW_PROP_NAME);
662 if (!GST_IS_D3D11_WINDOW_WIN32 (handle)) {
663 GST_WARNING ("%p is not d3d11window object", handle);
667 self = GST_D3D11_WINDOW_WIN32 (handle);
669 g_assert (self->internal_hwnd == hWnd);
671 gst_d3d11_window_win32_handle_window_proc (self, hWnd, uMsg, wParam,
679 return DefWindowProc (hWnd, uMsg, wParam, lParam);
682 static LRESULT FAR PASCAL
683 sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
685 WNDPROC external_window_proc =
686 (WNDPROC) GetProp (hWnd, EXTERNAL_PROC_PROP_NAME);
687 GstD3D11WindowWin32 *self =
688 (GstD3D11WindowWin32 *) GetProp (hWnd, D3D11_WINDOW_PROP_NAME);
690 if (uMsg == WM_GST_D3D11_CONSTRUCT_INTERNAL_WINDOW) {
691 GstD3D11Window *window = GST_D3D11_WINDOW (self);
694 GST_DEBUG_OBJECT (self, "Create internal window");
696 window->initialized = gst_d3d11_window_win32_create_internal_window (self);
698 SetWindowLongPtr (self->internal_hwnd, GWL_STYLE, WS_CHILD | WS_MAXIMIZE);
699 SetParent (self->internal_hwnd, self->external_hwnd);
701 /* take changes into account: SWP_FRAMECHANGED */
702 GetClientRect (self->external_hwnd, &rect);
703 SetWindowPos (self->internal_hwnd, HWND_TOP, rect.left, rect.top,
704 rect.right, rect.bottom,
705 SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
706 SWP_FRAMECHANGED | SWP_NOACTIVATE);
707 MoveWindow (self->internal_hwnd, rect.left, rect.top, rect.right,
710 /* don't need to be chained up to parent window procedure,
711 * as this is our custom message */
713 } else if (uMsg == WM_SIZE) {
714 MoveWindow (self->internal_hwnd, 0, 0, LOWORD (lParam), HIWORD (lParam),
716 } else if (uMsg == WM_CLOSE || uMsg == WM_DESTROY) {
717 g_mutex_lock (&self->lock);
718 GST_WARNING_OBJECT (self, "external window is closing");
719 gst_d3d11_window_win32_release_external_handle (self);
720 self->external_hwnd = NULL;
721 self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED;
722 g_mutex_unlock (&self->lock);
724 gst_d3d11_window_win32_handle_window_proc (self, hWnd, uMsg, wParam,
728 return CallWindowProc (external_window_proc, hWnd, uMsg, wParam, lParam);
732 gst_d3d11_window_win32_disable_alt_enter (GstD3D11WindowWin32 * self,
733 GstD3D11Device * device, IDXGISwapChain * swap_chain, HWND hwnd)
735 IDXGIFactory1 *factory = NULL;
738 hr = swap_chain->GetParent (IID_IDXGIFactory1, (void **) &factory);
739 if (!gst_d3d11_result (hr, device) || !factory) {
740 GST_WARNING_OBJECT (self,
741 "Cannot get parent dxgi factory for swapchain %p, hr: 0x%x",
742 swap_chain, (guint) hr);
746 hr = factory->MakeWindowAssociation (hwnd, DXGI_MWA_NO_ALT_ENTER);
747 if (!gst_d3d11_result (hr, device)) {
748 GST_WARNING_OBJECT (self,
749 "MakeWindowAssociation failure, hr: 0x%x", (guint) hr);
755 static IDXGISwapChain *
756 create_swap_chain (GstD3D11WindowWin32 * self, GstD3D11Device * device,
757 DXGI_SWAP_CHAIN_DESC * desc)
760 IDXGISwapChain *swap_chain = NULL;
761 ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
762 IDXGIFactory1 *factory = gst_d3d11_device_get_dxgi_factory_handle (device);
764 gst_d3d11_device_lock (device);
765 hr = factory->CreateSwapChain ((IUnknown *) device_handle, desc, &swap_chain);
766 gst_d3d11_device_unlock (device);
768 if (!gst_d3d11_result (hr, device)) {
769 GST_WARNING_OBJECT (self, "Cannot create SwapChain Object: 0x%x",
777 #if (GST_D3D11_DXGI_HEADER_VERSION >= 2)
778 static IDXGISwapChain1 *
779 create_swap_chain_for_hwnd (GstD3D11WindowWin32 * self, GstD3D11Device * device,
780 HWND hwnd, DXGI_SWAP_CHAIN_DESC1 * desc,
781 DXGI_SWAP_CHAIN_FULLSCREEN_DESC * fullscreen_desc, IDXGIOutput * output)
784 IDXGISwapChain1 *swap_chain = NULL;
785 ID3D11Device *device_handle = gst_d3d11_device_get_device_handle (device);
786 IDXGIFactory1 *factory = gst_d3d11_device_get_dxgi_factory_handle (device);
787 IDXGIFactory2 *factory2 = NULL;
789 hr = factory->QueryInterface (IID_PPV_ARGS (&factory2));
790 if (!gst_d3d11_result (hr, device)) {
791 GST_WARNING_OBJECT (self, "IDXGIFactory2 interface is unavailable");
795 gst_d3d11_device_lock (device);
796 hr = factory2->CreateSwapChainForHwnd (
797 (IUnknown *) device_handle, hwnd, desc, fullscreen_desc,
798 output, &swap_chain);
799 gst_d3d11_device_unlock (device);
801 if (!gst_d3d11_result (hr, device)) {
802 GST_WARNING_OBJECT (self, "Cannot create SwapChain Object: 0x%x",
807 factory2->Release ();
814 gst_d3d11_window_win32_create_swap_chain (GstD3D11Window * window,
815 DXGI_FORMAT format, guint width, guint height,
816 guint swapchain_flags, IDXGISwapChain ** swap_chain)
818 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
819 DXGI_SWAP_CHAIN_DESC desc = { 0, };
820 IDXGISwapChain *new_swapchain = NULL;
821 GstD3D11Device *device = window->device;
823 self->have_swapchain1 = FALSE;
825 #if (GST_D3D11_DXGI_HEADER_VERSION >= 2)
827 DXGI_SWAP_CHAIN_DESC1 desc1 = { 0, };
830 desc1.Format = format;
831 /* FIXME: add support stereo */
832 desc1.Stereo = FALSE;
833 desc1.SampleDesc.Count = 1;
834 desc1.SampleDesc.Quality = 0;
835 desc1.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
836 desc1.BufferCount = 2;
837 desc1.Scaling = DXGI_SCALING_STRETCH;
839 /* scaling-stretch would break aspect-ratio so we prefer to use scaling-none,
840 * but Windows7 does not support this method */
841 if (gst_d3d11_is_windows_8_or_greater ())
842 desc1.Scaling = DXGI_SCALING_NONE;
843 desc1.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
844 desc1.AlphaMode = DXGI_ALPHA_MODE_UNSPECIFIED;
845 desc1.Flags = swapchain_flags;
847 new_swapchain = (IDXGISwapChain *)
848 create_swap_chain_for_hwnd (self, device,
849 self->internal_hwnd, &desc1, NULL, NULL);
851 if (!new_swapchain) {
852 GST_WARNING_OBJECT (self, "Failed to create swapchain1");
854 self->have_swapchain1 = TRUE;
859 if (!new_swapchain) {
860 DXGI_SWAP_EFFECT swap_effect = DXGI_SWAP_EFFECT_DISCARD;
862 if (gst_d3d11_is_windows_8_or_greater ())
863 swap_effect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;
865 /* we will get client area at on_resize */
866 desc.BufferDesc.Width = 0;
867 desc.BufferDesc.Height = 0;
868 /* don't care refresh rate */
869 desc.BufferDesc.RefreshRate.Numerator = 0;
870 desc.BufferDesc.RefreshRate.Denominator = 1;
871 desc.BufferDesc.Format = format;
872 desc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
873 desc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
874 desc.SampleDesc.Count = 1;
875 desc.SampleDesc.Quality = 0;
876 desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
877 desc.BufferCount = 2;
878 desc.SwapEffect = swap_effect;
879 desc.OutputWindow = self->internal_hwnd;
880 desc.Windowed = TRUE;
881 desc.Flags = swapchain_flags;
883 new_swapchain = create_swap_chain (self, device, &desc);
886 if (!new_swapchain) {
887 GST_ERROR_OBJECT (self, "Cannot create swapchain");
891 /* disable alt+enter here. It should be manually handled */
892 gst_d3d11_device_lock (device);
893 gst_d3d11_window_win32_disable_alt_enter (self,
894 device, new_swapchain, desc.OutputWindow);
895 gst_d3d11_device_unlock (device);
897 *swap_chain = new_swapchain;
903 gst_d3d11_window_win32_set_window_handle (GstD3D11WindowWin32 * self,
906 self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_NONE;
908 self->external_hwnd = (HWND) handle;
909 gst_d3d11_window_win32_set_external_handle (self);
911 self->overlay_state = GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_OPENED;
915 gst_d3d11_window_win32_show (GstD3D11Window * window)
917 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
920 width = GST_VIDEO_INFO_WIDTH (&window->render_info);
921 height = GST_VIDEO_INFO_HEIGHT (&window->render_info);
923 if (!self->visible) {
924 /* if no parent the real size has to be set now because this has not been done
925 * when at window creation */
926 if (!self->external_hwnd) {
928 GetClientRect (self->internal_hwnd, &rect);
929 width += 2 * GetSystemMetrics (SM_CXSIZEFRAME);
931 2 * GetSystemMetrics (SM_CYSIZEFRAME) +
932 GetSystemMetrics (SM_CYCAPTION);
933 MoveWindow (self->internal_hwnd, rect.left, rect.top, width,
937 ShowWindow (self->internal_hwnd, SW_SHOW);
938 self->visible = TRUE;
943 gst_d3d11_window_win32_present (GstD3D11Window * window, guint present_flags)
945 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
948 if ((!self->external_hwnd &&
949 self->overlay_state == GST_D3D11_WINDOW_WIN32_OVERLAY_STATE_CLOSED)
950 || !self->internal_hwnd) {
951 GST_ERROR_OBJECT (self, "Output window was closed");
953 return GST_D3D11_WINDOW_FLOW_CLOSED;
955 #if (GST_D3D11_DXGI_HEADER_VERSION >= 2)
956 if (self->have_swapchain1) {
957 IDXGISwapChain1 *swap_chain1 = (IDXGISwapChain1 *) window->swap_chain;
958 DXGI_PRESENT_PARAMETERS present_params = { 0, };
960 /* the first present should not specify dirty-rect */
961 if (!window->first_present) {
962 present_params.DirtyRectsCount = 1;
963 present_params.pDirtyRects = &window->render_rect;
966 hr = swap_chain1->Present1 (0, present_flags, &present_params);
970 hr = window->swap_chain->Present (0, present_flags);
973 if (!gst_d3d11_result (hr, window->device)) {
974 GST_WARNING_OBJECT (self, "Direct3D cannot present texture, hr: 0x%x",
982 gst_d3d11_window_win32_on_resize (GstD3D11Window * window,
983 guint width, guint height)
985 /* Set zero width and height here. dxgi will decide client area by itself */
986 GST_D3D11_WINDOW_CLASS (parent_class)->on_resize (window, 0, 0);
990 gst_d3d11_window_win32_update_swap_chain (GstD3D11Window * window)
992 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
994 if (self->internal_hwnd)
995 PostMessage (self->internal_hwnd, WM_SIZE, 0, 0);
1001 gst_d3d11_window_win32_change_fullscreen_mode (GstD3D11Window * window)
1003 GstD3D11WindowWin32 *self = GST_D3D11_WINDOW_WIN32 (window);
1005 if (self->internal_hwnd) {
1006 g_atomic_int_add (&self->pending_fullscreen_count, 1);
1007 PostMessage (self->internal_hwnd, WM_GST_D3D11_FULLSCREEN, 0, 0);
1012 gst_d3d11_window_win32_new (GstD3D11Device * device, guintptr handle)
1014 GstD3D11Window *window;
1016 g_return_val_if_fail (GST_IS_D3D11_DEVICE (device), NULL);
1018 window = (GstD3D11Window *) g_object_new (GST_TYPE_D3D11_WINDOW_WIN32,
1019 "d3d11device", device, "window-handle", handle, NULL);
1020 if (!window->initialized) {
1021 gst_object_unref (window);
1025 g_object_ref_sink (window);