From 7b1b3327a0c99bce6a1a657df4d687aec552cf68 Mon Sep 17 00:00:00 2001 From: Seungha Yang Date: Sat, 8 Jun 2019 22:57:21 +0900 Subject: [PATCH] vulkan: Add support WIN32 for Windows It's almost a fork of glwindow_win32 implementation. To build on Windows, Vulkan SDK (at https://vulkan.lunarg.com/sdk/home) and VK_SDK_PATH environment are required. Note that VK_SDK_PATH environment setting is a part of the SDK installation. --- gst-libs/gst/vulkan/gstvkapi.h | 6 + gst-libs/gst/vulkan/gstvkconfig.h.meson | 1 + gst-libs/gst/vulkan/gstvkdisplay.c | 14 + gst-libs/gst/vulkan/gstvkdisplay.h | 2 + gst-libs/gst/vulkan/gstvkwindow.c | 7 + gst-libs/gst/vulkan/meson.build | 44 +- gst-libs/gst/vulkan/win32/gstvkwindow_win32.c | 565 ++++++++++++++++++++++++++ gst-libs/gst/vulkan/win32/gstvkwindow_win32.h | 79 ++++ 8 files changed, 716 insertions(+), 2 deletions(-) create mode 100644 gst-libs/gst/vulkan/win32/gstvkwindow_win32.c create mode 100644 gst-libs/gst/vulkan/win32/gstvkwindow_win32.h diff --git a/gst-libs/gst/vulkan/gstvkapi.h b/gst-libs/gst/vulkan/gstvkapi.h index 99b99b1..ddb0267 100644 --- a/gst-libs/gst/vulkan/gstvkapi.h +++ b/gst-libs/gst/vulkan/gstvkapi.h @@ -53,6 +53,12 @@ #endif #endif +#if GST_VULKAN_HAVE_WINDOW_WIN32 +#ifndef VK_USE_PLATFORM_WIN32_KHR +#define VK_USE_PLATFORM_WIN32_KHR +#endif +#endif + #include #endif /* __GST_VULKAN_API_H__ */ diff --git a/gst-libs/gst/vulkan/gstvkconfig.h.meson b/gst-libs/gst/vulkan/gstvkconfig.h.meson index 702b662..5cdb751 100644 --- a/gst-libs/gst/vulkan/gstvkconfig.h.meson +++ b/gst-libs/gst/vulkan/gstvkconfig.h.meson @@ -14,6 +14,7 @@ G_BEGIN_DECLS #mesondefine GST_VULKAN_HAVE_WINDOW_WAYLAND #mesondefine GST_VULKAN_HAVE_WINDOW_COCOA #mesondefine GST_VULKAN_HAVE_WINDOW_IOS +#mesondefine GST_VULKAN_HAVE_WINDOW_WIN32 G_END_DECLS diff --git a/gst-libs/gst/vulkan/gstvkdisplay.c b/gst-libs/gst/vulkan/gstvkdisplay.c index 07bf673..a9c0ef0 100644 --- a/gst-libs/gst/vulkan/gstvkdisplay.c +++ b/gst-libs/gst/vulkan/gstvkdisplay.c @@ -477,6 +477,16 @@ gst_vulkan_display_choose_type (GstVulkanInstance * instance) #undef CHOOSE_WINSYS +#if GST_VULKAN_HAVE_WINDOW_WIN32 + /* CHOOSE_WINSYS macro doesn't work with "WIN32" */ + if (!type && g_strcmp0 (window_str, "win32") == 0) { + type = GST_VULKAN_DISPLAY_TYPE_WIN32; + } + + if (!first_supported) + first_supported = GST_VULKAN_DISPLAY_TYPE_WIN32; +#endif + if (type) return type; @@ -518,6 +528,10 @@ gst_vulkan_display_type_to_extension_string (GstVulkanDisplayType type) if (type & GST_VULKAN_DISPLAY_TYPE_IOS) return VK_MVK_IOS_SURFACE_EXTENSION_NAME; #endif +#if GST_VULKAN_HAVE_WINDOW_WIN32 + if (type & GST_VULKAN_DISPLAY_TYPE_WIN32) + return VK_KHR_WIN32_SURFACE_EXTENSION_NAME; +#endif return NULL; } diff --git a/gst-libs/gst/vulkan/gstvkdisplay.h b/gst-libs/gst/vulkan/gstvkdisplay.h index bcfe45b..2bd6557 100644 --- a/gst-libs/gst/vulkan/gstvkdisplay.h +++ b/gst-libs/gst/vulkan/gstvkdisplay.h @@ -51,6 +51,7 @@ typedef struct _GstVulkanDisplayPrivate GstVulkanDisplayPrivate; * @GST_VULKAN_DISPLAY_TYPE_WAYLAND: wayland display * @GST_VULKAN_DISPLAY_TYPE_COCOA: cocoa display for macOS * @GST_VULKAN_DISPLAY_TYPE_IOS: ios display + * @GST_VULKAN_DISPLAY_TYPE_WIN32: win32 display */ typedef enum { @@ -59,6 +60,7 @@ typedef enum GST_VULKAN_DISPLAY_TYPE_WAYLAND = (1 << 1), GST_VULKAN_DISPLAY_TYPE_COCOA = (1 << 2), GST_VULKAN_DISPLAY_TYPE_IOS = (1 << 3), + GST_VULKAN_DISPLAY_TYPE_WIN32 = (1 << 4), GST_VULKAN_DISPLAY_TYPE_ANY = G_MAXUINT32 } GstVulkanDisplayType; diff --git a/gst-libs/gst/vulkan/gstvkwindow.c b/gst-libs/gst/vulkan/gstvkwindow.c index d2d8092..3eb0361 100644 --- a/gst-libs/gst/vulkan/gstvkwindow.c +++ b/gst-libs/gst/vulkan/gstvkwindow.c @@ -49,6 +49,9 @@ #if GST_VULKAN_HAVE_WINDOW_IOS #include "ios/gstvkwindow_ios.h" #endif +#if GST_VULKAN_HAVE_WINDOW_WIN32 +#include "win32/gstvkwindow_win32.h" +#endif #define GST_CAT_DEFAULT gst_vulkan_window_debug GST_DEBUG_CATEGORY (GST_CAT_DEFAULT); @@ -191,6 +194,10 @@ gst_vulkan_window_new (GstVulkanDisplay * display) if (!window && (!user_choice || g_strstr_len (user_choice, 3, "ios"))) window = GST_VULKAN_WINDOW (gst_vulkan_window_ios_new (display)); #endif +#if GST_VULKAN_HAVE_WINDOW_WIN32 + if (!window && (!user_choice || g_strstr_len (user_choice, 5, "win32"))) + window = GST_VULKAN_WINDOW (gst_vulkan_window_win32_new (display)); +#endif if (!window) { /* subclass returned a NULL window */ GST_WARNING ("Could not create window. user specified %s, creating dummy" diff --git a/gst-libs/gst/vulkan/meson.build b/gst-libs/gst/vulkan/meson.build index 80b6c10..bd0dfbb 100644 --- a/gst-libs/gst/vulkan/meson.build +++ b/gst-libs/gst/vulkan/meson.build @@ -47,6 +47,8 @@ vulkan_windowing = false vulkan_objc_args = [] vulkan_defines = [] optional_deps = [] +has_vulkan_header = false +vulkan_dep = dependency('', required: false) vulkan_conf = configuration_data() vulkan_conf_options = [ @@ -54,6 +56,7 @@ vulkan_conf_options = [ 'GST_VULKAN_HAVE_WINDOW_WAYLAND', 'GST_VULKAN_HAVE_WINDOW_COCOA', 'GST_VULKAN_HAVE_WINDOW_IOS', + 'GST_VULKAN_HAVE_WINDOW_WIN32', ] foreach option : vulkan_conf_options @@ -62,10 +65,36 @@ endforeach if host_system == 'ios' vulkan_dep = cc.find_library('MoltenVK', required : get_option('vulkan')) +elif host_system == 'windows' + vulkan_root = run_command(python3, '-c', 'import os; print(os.environ.get("VK_SDK_PATH"))').stdout().strip() + if vulkan_root != '' and vulkan_root != 'None' + vulkan_lib_dir = '' + if build_machine.cpu_family() == 'x86_64' + vulkan_lib_dir = join_paths(vulkan_root, 'Lib') + else + vulkan_lib_dir = join_paths(vulkan_root, 'Lib32') + endif + + vulkan_lib = cc.find_library('vulkan-1', dirs: vulkan_lib_dir, + required : get_option('vulkan')) + + vulkan_inc_dir = join_paths(vulkan_root, 'Include') + has_vulkan_header = cc.has_header('vulkan/vulkan.h', + args: '-I' + vulkan_inc_dir) + + if vulkan_lib.found() and has_vulkan_header + vulkan_dep = declare_dependency(include_directories: include_directories(vulkan_inc_dir), + dependencies: vulkan_lib) + endif + endif else vulkan_dep = cc.find_library('vulkan', required : get_option('vulkan')) endif -has_vulkan_header = cc.has_header('vulkan/vulkan.h') + +if host_system != 'windows' + has_vulkan_header = cc.has_header('vulkan/vulkan.h') +endif + if not has_vulkan_header and get_option('vulkan').enabled() error('vulkan plugin enabled, but vulkan.h not found') endif @@ -146,6 +175,17 @@ if host_system == 'ios' endif endif +if host_system == 'windows' + gdi_dep = cc.find_library('gdi32', required : get_option('vulkan')) + + if gdi_dep.found() + vulkan_sources += ['win32/gstvkwindow_win32.c'] + optional_deps += [gdi_dep] + vulkan_windowing = true + vulkan_conf.set10('GST_VULKAN_HAVE_WINDOW_WIN32', 1) + endif +endif + if not vulkan_windowing warning('No Windowing system found. vulkansink will not work') endif @@ -203,7 +243,7 @@ if vulkan_dep.found() and has_vulkan_header gstvulkan_dep = declare_dependency(link_with : gstvulkan, include_directories : [libsinc], sources: gen_sources, - dependencies : [gstvideo_dep, gstbase_dep] + optional_deps) + dependencies : [gstvideo_dep, gstbase_dep, vulkan_dep] + optional_deps) elif get_option('vulkan').enabled() error('GStreamer Vulkan integration required via options, but needed dependencies not found.') else diff --git a/gst-libs/gst/vulkan/win32/gstvkwindow_win32.c b/gst-libs/gst/vulkan/win32/gstvkwindow_win32.c new file mode 100644 index 0000000..6b45966 --- /dev/null +++ b/gst-libs/gst/vulkan/win32/gstvkwindow_win32.c @@ -0,0 +1,565 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * Copyright (C) 2012 Matthew Waters + * Copyright (C) 2019 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstvkwindow_win32.h" + +LRESULT CALLBACK window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam); +LRESULT FAR PASCAL sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, + LPARAM lParam); + +enum +{ + PROP_0 +}; + +struct _GstVulkanWindowWin32Private +{ + GIOChannel *msg_io_channel; + + gint preferred_width; + gint preferred_height; +}; + +#define GST_CAT_DEFAULT gst_vulkan_window_win32_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_GET (GST_CAT_DEFAULT, "vulkanwindow"); +#define gst_vulkan_window_win32_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstVulkanWindowWin32, gst_vulkan_window_win32, + GST_TYPE_VULKAN_WINDOW, G_ADD_PRIVATE (GstVulkanWindowWin32) DEBUG_INIT); + +static void gst_vulkan_window_win32_set_window_handle (GstVulkanWindow * window, + guintptr handle); +static VkSurfaceKHR +gst_vulkan_window_win32_get_surface (GstVulkanWindow * window, GError ** error); +static gboolean +gst_vulkan_window_win32_get_presentation_support (GstVulkanWindow * window, + GstVulkanDevice * device, guint32 queue_family_idx); +static gboolean gst_vulkan_window_win32_open (GstVulkanWindow * window, + GError ** error); +static void gst_vulkan_window_win32_close (GstVulkanWindow * window); +static void release_parent_win_id (GstVulkanWindowWin32 * window_win32); +static void gst_vulkan_window_win32_show (GstVulkanWindowWin32 * window); + +static void +gst_vulkan_window_win32_class_init (GstVulkanWindowWin32Class * klass) +{ + GstVulkanWindowClass *window_class = (GstVulkanWindowClass *) klass; + + window_class->set_window_handle = + GST_DEBUG_FUNCPTR (gst_vulkan_window_win32_set_window_handle); + window_class->get_surface = + GST_DEBUG_FUNCPTR (gst_vulkan_window_win32_get_surface); + window_class->open = GST_DEBUG_FUNCPTR (gst_vulkan_window_win32_open); + window_class->close = GST_DEBUG_FUNCPTR (gst_vulkan_window_win32_close); + window_class->get_presentation_support = + GST_DEBUG_FUNCPTR (gst_vulkan_window_win32_get_presentation_support); +} + +static void +gst_vulkan_window_win32_init (GstVulkanWindowWin32 * window) +{ + window->priv = gst_vulkan_window_win32_get_instance_private (window); + + window->priv->preferred_width = 320; + window->priv->preferred_height = 240; +} + +GstVulkanWindowWin32 * +gst_vulkan_window_win32_new (GstVulkanDisplay * display) +{ + GstVulkanWindowWin32 *window; + + if ((gst_vulkan_display_get_handle_type (display) & + GST_VULKAN_DISPLAY_TYPE_WIN32) == 0) + /* we require an win32 display to create win32 windows */ + return NULL; + + window = g_object_new (GST_TYPE_VULKAN_WINDOW_WIN32, NULL); + gst_object_ref_sink (window); + + return window; +} + +static gboolean +msg_cb (GIOChannel * source, GIOCondition condition, gpointer data) +{ + MSG msg; + + if (!PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + return G_SOURCE_CONTINUE; + + GST_TRACE ("handle message"); + TranslateMessage (&msg); + DispatchMessage (&msg); + + return G_SOURCE_CONTINUE; +} + +typedef struct +{ + GstVulkanWindowWin32 *self; + GError **error; + gboolean fired; + gboolean ret; + GMutex lock; + GCond cond; +} CreateWindowData; + +static gboolean +_create_window (CreateWindowData * data) +{ + data->ret = gst_vulkan_window_win32_create_window (data->self, data->error); + + g_mutex_lock (&data->lock); + data->fired = TRUE; + g_cond_signal (&data->cond); + g_mutex_unlock (&data->lock); + + return G_SOURCE_REMOVE; +} + +static gboolean +gst_vulkan_window_win32_open (GstVulkanWindow * window, GError ** error) +{ + GstVulkanWindowWin32 *window_win32 = GST_VULKAN_WINDOW_WIN32 (window); + GstVulkanDisplay *display; + GMainContext *context; + CreateWindowData data = { 0, }; + + if (!GST_VULKAN_WINDOW_CLASS (parent_class)->open (window, error)) + return FALSE; + + display = gst_vulkan_window_get_display (window); + context = g_main_context_ref (display->main_context); + gst_object_unref (display); + + window_win32->priv->msg_io_channel = g_io_channel_win32_new_messages (0); + window_win32->msg_source = + g_io_create_watch (window_win32->priv->msg_io_channel, G_IO_IN); + g_source_set_callback (window_win32->msg_source, (GSourceFunc) msg_cb, NULL, + NULL); + g_source_attach (window_win32->msg_source, context); + + data.self = window_win32; + data.error = error; + g_mutex_init (&data.lock); + g_cond_init (&data.cond); + + g_main_context_invoke (context, (GSourceFunc) _create_window, &data); + g_mutex_lock (&data.lock); + while (!data.fired) + g_cond_wait (&data.cond, &data.lock); + g_mutex_unlock (&data.lock); + + g_mutex_clear (&data.lock); + g_cond_clear (&data.cond); + g_main_context_unref (context); + + if (!data.ret) + return FALSE; + + gst_vulkan_window_win32_show (window_win32); + + return TRUE; +} + +static void +gst_vulkan_window_win32_close (GstVulkanWindow * window) +{ + GstVulkanWindowWin32 *window_win32 = GST_VULKAN_WINDOW_WIN32 (window); + + release_parent_win_id (window_win32); + + if (window_win32->internal_win_id) { + RemoveProp (window_win32->internal_win_id, "vulkan_window"); + ShowWindow (window_win32->internal_win_id, SW_HIDE); + SetParent (window_win32->internal_win_id, NULL); + if (!DestroyWindow (window_win32->internal_win_id)) + GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT + ", 0x%x", (guintptr) window_win32->internal_win_id, + (unsigned int) GetLastError ()); + } + + g_source_destroy (window_win32->msg_source); + g_source_unref (window_win32->msg_source); + window_win32->msg_source = NULL; + g_io_channel_unref (window_win32->priv->msg_io_channel); + window_win32->priv->msg_io_channel = NULL; + + GST_VULKAN_WINDOW_CLASS (parent_class)->close (window); +} + +static void +set_parent_win_id (GstVulkanWindowWin32 * window_win32) +{ + WNDPROC window_parent_proc; + RECT rect; + + if (!window_win32->parent_win_id) { + /* no parent so the internal window needs borders and system menu */ + SetWindowLongPtr (window_win32->internal_win_id, GWL_STYLE, + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW); + SetParent (window_win32->internal_win_id, NULL); + return; + } + + window_parent_proc = + (WNDPROC) GetWindowLongPtr (window_win32->parent_win_id, GWLP_WNDPROC); + + GST_DEBUG ("set parent %" G_GUINTPTR_FORMAT, + (guintptr) window_win32->parent_win_id); + + SetProp (window_win32->parent_win_id, "vulkan_window_id", + window_win32->internal_win_id); + SetProp (window_win32->parent_win_id, "vulkan_window_parent_proc", + (WNDPROC) window_parent_proc); + SetWindowLongPtr (window_win32->parent_win_id, GWLP_WNDPROC, + (LONG_PTR) sub_class_proc); + + SetWindowLongPtr (window_win32->internal_win_id, GWL_STYLE, + WS_CHILD | WS_MAXIMIZE); + SetParent (window_win32->internal_win_id, window_win32->parent_win_id); + + /* take changes into account: SWP_FRAMECHANGED */ + GetClientRect (window_win32->parent_win_id, &rect); + SetWindowPos (window_win32->internal_win_id, HWND_TOP, rect.left, rect.top, + rect.right, rect.bottom, + SWP_ASYNCWINDOWPOS | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | + SWP_FRAMECHANGED | SWP_NOACTIVATE); + MoveWindow (window_win32->internal_win_id, rect.left, rect.top, rect.right, + rect.bottom, FALSE); +} + +static void +release_parent_win_id (GstVulkanWindowWin32 * window_win32) +{ + WNDPROC parent_proc; + + if (!window_win32->parent_win_id) + return; + + parent_proc = + GetProp (window_win32->parent_win_id, "vulkan_window_parent_proc"); + if (!parent_proc) + return; + + GST_DEBUG ("release parent %" G_GUINTPTR_FORMAT, + (guintptr) window_win32->parent_win_id); + + SetWindowLongPtr (window_win32->parent_win_id, GWLP_WNDPROC, + (LONG_PTR) parent_proc); + + RemoveProp (window_win32->parent_win_id, "vulkan_window_parent_proc"); +} + +static gboolean +gst_vulkan_window_win32_create_window (GstVulkanWindowWin32 * window_win32, + GError ** error) +{ + WNDCLASSEX wc; + ATOM atom = 0; + HINSTANCE hinstance = GetModuleHandle (NULL); + + static gint x = 0; + static gint y = 0; + + GST_LOG ("Attempting to create a win32 window"); + + x += 20; + y += 20; + + atom = GetClassInfoEx (hinstance, "GSTVULKAN", &wc); + + if (atom == 0) { + ZeroMemory (&wc, sizeof (WNDCLASSEX)); + + wc.cbSize = sizeof (WNDCLASSEX); + wc.lpfnWndProc = window_proc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hinstance; + wc.hIcon = LoadIcon (NULL, IDI_WINLOGO); + wc.hIconSm = NULL; + wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; + wc.hCursor = LoadCursor (NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = "GSTVULKAN"; + + atom = RegisterClassEx (&wc); + + if (atom == 0) { + g_set_error (error, GST_VULKAN_WINDOW_ERROR, + GST_VULKAN_WINDOW_ERROR_RESOURCE_UNAVAILABLE, + "Failed to register window class 0x%x\n", + (unsigned int) GetLastError ()); + goto failure; + } + } + + window_win32->internal_win_id = 0; + window_win32->device = 0; + window_win32->visible = FALSE; + + window_win32->internal_win_id = CreateWindowEx (0, + "GSTVULKAN", + "Vulkan renderer", + WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, + x, y, 0, 0, (HWND) NULL, (HMENU) NULL, hinstance, window_win32); + + if (!window_win32->internal_win_id) { + g_set_error (error, GST_VULKAN_WINDOW_ERROR, + GST_VULKAN_WINDOW_ERROR_RESOURCE_UNAVAILABLE, + "failed to create vulkan window"); + goto failure; + } + + GST_DEBUG ("vulkan window created: %" G_GUINTPTR_FORMAT, + (guintptr) window_win32->internal_win_id); + + /* device is set in the window_proc */ + if (!window_win32->device) { + g_set_error (error, GST_VULKAN_WINDOW_ERROR, + GST_VULKAN_WINDOW_ERROR_RESOURCE_UNAVAILABLE, + "failed to create device"); + goto failure; + } + + ShowCursor (TRUE); + + GST_LOG ("Created a win32 window"); + + /* The window has been created as if it had no parent, so there is nothing + * else to do in that case. Even if user has already set a window, + * parent_win_id could still be 0 at this point, and in that case calling + * set_parent_win_id() here would steal focus from the parent window. */ + if (window_win32->parent_win_id) + set_parent_win_id (window_win32); + + return TRUE; + +failure: + return FALSE; +} + +static VkSurfaceKHR +gst_vulkan_window_win32_get_surface (GstVulkanWindow * window, GError ** error) +{ + GstVulkanWindowWin32 *window_win32 = GST_VULKAN_WINDOW_WIN32 (window); + VkWin32SurfaceCreateInfoKHR info = { 0, }; + VkSurfaceKHR ret; + VkResult err; + + info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; + info.pNext = NULL; + info.flags = 0; + info.hinstance = GetModuleHandle (NULL); + info.hwnd = window_win32->parent_win_id ? window_win32->parent_win_id : + window_win32->internal_win_id; + + if (!window_win32->CreateWin32Surface) + window_win32->CreateWin32Surface = + gst_vulkan_instance_get_proc_address (window->display->instance, + "vkCreateWin32SurfaceKHR"); + if (!window_win32->CreateWin32Surface) { + g_set_error_literal (error, GST_VULKAN_ERROR, VK_ERROR_FEATURE_NOT_PRESENT, + "Could not retrieve \"vkCreateWin32SurfaceKHR\" function pointer"); + return NULL; + } + + err = + window_win32->CreateWin32Surface (window->display->instance->instance, + &info, NULL, &ret); + + if (gst_vulkan_error_to_g_error (err, error, "vkCreateWin32SurfaceKHR") < 0) + return NULL; + + return ret; +} + +static gboolean +gst_vulkan_window_win32_get_presentation_support (GstVulkanWindow * window, + GstVulkanDevice * device, guint32 queue_family_idx) +{ + GstVulkanWindowWin32 *window_win32 = GST_VULKAN_WINDOW_WIN32 (window); + VkPhysicalDevice gpu; + + if (!window_win32->GetPhysicalDeviceWin32PresentationSupport) + window_win32->GetPhysicalDeviceWin32PresentationSupport = + gst_vulkan_instance_get_proc_address (window->display->instance, + "vkGetPhysicalDeviceWin32PresentationSupportKHR"); + if (!window_win32->GetPhysicalDeviceWin32PresentationSupport) { + GST_WARNING_OBJECT (window, "Could not retrieve " + "\"GetPhysicalDeviceWin32PresentationSupport\" " "function pointer"); + return FALSE; + } + + gpu = gst_vulkan_device_get_physical_device (device); + if (window_win32->GetPhysicalDeviceWin32PresentationSupport (gpu, + queue_family_idx)) + return TRUE; + + return FALSE; +} + + +static void +gst_vulkan_window_win32_set_window_handle (GstVulkanWindow * window, + guintptr id) +{ + GstVulkanWindowWin32 *window_win32; + + window_win32 = GST_VULKAN_WINDOW_WIN32 (window); + + if (!window_win32->internal_win_id) { + window_win32->parent_win_id = (HWND) id; + return; + } + + if (window_win32->visible) { + ShowWindow (window_win32->internal_win_id, SW_HIDE); + window_win32->visible = FALSE; + } + + release_parent_win_id (window_win32); + window_win32->parent_win_id = (HWND) id; + set_parent_win_id (window_win32); +} + +static void +gst_vulkan_window_win32_show (GstVulkanWindowWin32 * window) +{ + gint width = window->priv->preferred_width; + gint height = window->priv->preferred_height; + + if (!window->visible) { + HWND parent_id = window->parent_win_id; + + /* if no parent the real size has to be set now because this has not been done + * when at window creation */ + if (!parent_id) { + RECT rect; + GetClientRect (window->internal_win_id, &rect); + width += 2 * GetSystemMetrics (SM_CXSIZEFRAME); + height += + 2 * GetSystemMetrics (SM_CYSIZEFRAME) + + GetSystemMetrics (SM_CYCAPTION); + MoveWindow (window->internal_win_id, rect.left, rect.top, width, + height, FALSE); + } + + ShowWindowAsync (window->internal_win_id, SW_SHOW); + window->visible = TRUE; + } +} + +/* PRIVATE */ + +LRESULT CALLBACK +window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + GstVulkanWindowWin32 *window_win32; + LRESULT ret = 0; + + if (uMsg == WM_CREATE) { + window_win32 = + GST_VULKAN_WINDOW_WIN32 (((LPCREATESTRUCT) lParam)->lpCreateParams); + + GST_TRACE ("WM_CREATE"); + + window_win32->device = GetDC (hWnd); + /* Do this, otherwise we hang on exit. We can still use it (due to the + * CS_OWNDC flag in the WindowClass) after we have Released. + */ + ReleaseDC (hWnd, window_win32->device); + + SetProp (hWnd, "vulkan_window", window_win32); + } else if (GetProp (hWnd, "vulkan_window")) { + GstVulkanWindow *window; + + window_win32 = GST_VULKAN_WINDOW_WIN32 (GetProp (hWnd, "vulkan_window")); + window = GST_VULKAN_WINDOW (window_win32); + + g_assert (window_win32->internal_win_id == hWnd); + + switch (uMsg) { + case WM_SIZE: + gst_vulkan_window_resize (window, LOWORD (lParam), HIWORD (lParam)); + break; + case WM_PAINT: + { + PAINTSTRUCT ps; + + BeginPaint (hWnd, &ps); + gst_vulkan_window_redraw (window); + EndPaint (hWnd, &ps); + break; + } + case WM_CLOSE: + { + ShowWindowAsync (window_win32->internal_win_id, SW_HIDE); + + gst_vulkan_window_win32_close (window); + break; + } + case WM_ERASEBKGND: + { + ret = TRUE; + break; + } + default: + { + /* transmit messages to the parrent (ex: mouse/keyboard input) */ + HWND parent_id = window_win32->parent_win_id; + if (parent_id) + PostMessage (parent_id, uMsg, wParam, lParam); + ret = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + } + } else { + ret = DefWindowProc (hWnd, uMsg, wParam, lParam); + } + + return ret; +} + +LRESULT FAR PASCAL +sub_class_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC window_parent_proc = GetProp (hWnd, "vulkan_window_parent_proc"); + + if (uMsg == WM_SIZE) { + HWND vulkan_window_id = GetProp (hWnd, "vulkan_window_id"); + MoveWindow (vulkan_window_id, 0, 0, LOWORD (lParam), HIWORD (lParam), + FALSE); + } + + return CallWindowProc (window_parent_proc, hWnd, uMsg, wParam, lParam); +} diff --git a/gst-libs/gst/vulkan/win32/gstvkwindow_win32.h b/gst-libs/gst/vulkan/win32/gstvkwindow_win32.h new file mode 100644 index 0000000..eabedec --- /dev/null +++ b/gst-libs/gst/vulkan/win32/gstvkwindow_win32.h @@ -0,0 +1,79 @@ +/* + * GStreamer + * Copyright (C) 2012 Matthew Waters + * Copyright (C) 2019 Seungha Yang + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __GST_VULKAN_WINDOW_WIN32_H__ +#define __GST_VULKAN_WINDOW_WIN32_H__ + +#undef UNICODE +#include +#define UNICODE + +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VULKAN_WINDOW_WIN32 (gst_vulkan_window_win32_get_type()) +#define GST_VULKAN_WINDOW_WIN32(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_TYPE_VULKAN_WINDOW_WIN32, GstVulkanWindowWin32)) +#define GST_VULKAN_WINDOW_WIN32_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_TYPE_VULKAN_WINDOW_WIN32, GstVulkanWindowWin32Class)) +#define GST_IS_VULKAN_WINDOW_WIN32(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_TYPE_VULKAN_WINDOW_WIN32)) +#define GST_IS_VULKAN_WINDOW_WIN32_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_TYPE_VULKAN_WINDOW_WIN32)) +#define GST_VULKAN_WINDOW_WIN32_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_TYPE_VULKAN_WINDOW_WIN32, GstVulkanWindowWin32Class)) + +typedef struct _GstVulkanWindowWin32 GstVulkanWindowWin32; +typedef struct _GstVulkanWindowWin32Private GstVulkanWindowWin32Private; +typedef struct _GstVulkanWindowWin32Class GstVulkanWindowWin32Class; + +struct _GstVulkanWindowWin32 { + /*< private >*/ + GstVulkanWindow parent; + + PFN_vkCreateWin32SurfaceKHR CreateWin32Surface; + PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR GetPhysicalDeviceWin32PresentationSupport; + + HWND internal_win_id; + HWND parent_win_id; + HDC device; + gboolean is_closed; + gboolean visible; + + GSource *msg_source; + + /*< private >*/ + GstVulkanWindowWin32Private *priv; + + gpointer _reserved[GST_PADDING]; +}; + +struct _GstVulkanWindowWin32Class { + /*< private >*/ + GstVulkanWindowClass parent_class; + + /*< private >*/ + gpointer _reserved[GST_PADDING]; +}; + +GType gst_vulkan_window_win32_get_type (void); + +GstVulkanWindowWin32 * gst_vulkan_window_win32_new (GstVulkanDisplay * display); + +G_END_DECLS + +#endif /* __GST_VULKAN_WINDOW_WIN32_H__ */ -- 2.7.4