From 0cb64ce5bd3fc0cded7c06915e58cfe933f77eb7 Mon Sep 17 00:00:00 2001 From: Ryan Pavlik Date: Mon, 23 Nov 2020 13:44:58 -0600 Subject: [PATCH] comp/main: Windows work - got a window to appear! --- CMakeLists.txt | 2 +- src/xrt/compositor/CMakeLists.txt | 6 + src/xrt/compositor/main/comp_compositor.c | 24 +++ src/xrt/compositor/main/comp_settings.h | 1 + src/xrt/compositor/main/comp_window.h | 13 ++ src/xrt/compositor/main/comp_window_mswin.c | 212 ++++++++++++++++++++ 6 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 src/xrt/compositor/main/comp_window_mswin.c diff --git a/CMakeLists.txt b/CMakeLists.txt index ad40df86e..2c4133e01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,7 +117,7 @@ cmake_dependent_option(XRT_HAVE_OPENGL "Enable OpenGL Graphics API support" ON " cmake_dependent_option(XRT_HAVE_OPENGLES "Enable OpenGL-ES Graphics API support" ON "OpenGLES_FOUND" OFF) cmake_dependent_option(XRT_HAVE_EGL "Enable OpenGL on EGL Graphics API support" ON "EGL_FOUND; XRT_HAVE_OPENGL OR XRT_HAVE_OPENGLES" OFF) cmake_dependent_option(XRT_HAVE_DBUS "Enable dbus support (for BLE support)" ON "DBUS_FOUND" OFF) -cmake_dependent_option(XRT_FEATURE_COMPOSITOR_MAIN "Build main compositor host functionality" ON "XRT_HAVE_VULKAN; XRT_HAVE_WAYLAND OR XRT_HAVE_XCB OR ANDROID" OFF) +cmake_dependent_option(XRT_FEATURE_COMPOSITOR_MAIN "Build main compositor host functionality" ON "XRT_HAVE_VULKAN; XRT_HAVE_WAYLAND OR XRT_HAVE_XCB OR ANDROID OR WIN32" OFF) cmake_dependent_option(XRT_FEATURE_OPENXR "Build OpenXR runtime target" ON "XRT_FEATURE_COMPOSITOR_MAIN" OFF) cmake_dependent_option(XRT_FEATURE_SERVICE "Enable separate service module for OpenXR runtime" ON "NOT WIN32" OFF) cmake_dependent_option(XRT_HAVE_SYSTEMD "Enable systemd support (for socket activation of service)" ON "Systemd_FOUND AND XRT_FEATURE_SERVICE" OFF) diff --git a/src/xrt/compositor/CMakeLists.txt b/src/xrt/compositor/CMakeLists.txt index 7e035a242..3537d34e7 100644 --- a/src/xrt/compositor/CMakeLists.txt +++ b/src/xrt/compositor/CMakeLists.txt @@ -112,6 +112,12 @@ if(XRT_FEATURE_COMPOSITOR_MAIN) main/comp_window_direct_nvidia.c ) endif() + if(WIN32) + list(APPEND MAIN_SOURCE_FILES + main/comp_window_mswin.c + ) + endif() + # generate wayland protocols if(XRT_HAVE_WAYLAND) diff --git a/src/xrt/compositor/main/comp_compositor.c b/src/xrt/compositor/main/comp_compositor.c index bcb4624b8..0a8ad26af 100644 --- a/src/xrt/compositor/main/comp_compositor.c +++ b/src/xrt/compositor/main/comp_compositor.c @@ -694,6 +694,11 @@ static const char *instance_extensions_android[] = { COMP_INSTANCE_EXTENSIONS_COMMON, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME}; #endif +#ifdef VK_USE_PLATFORM_WIN32_KHR +static const char *instance_extensions_windows[] = { + COMP_INSTANCE_EXTENSIONS_COMMON, VK_KHR_WIN32_SURFACE_EXTENSION_NAME}; +#endif + // Note: Keep synchronized with comp_vk_glue - we should have everything they // do, plus VK_KHR_SWAPCHAIN_EXTENSION_NAME static const char *device_extensions[] = { @@ -766,6 +771,12 @@ select_instances_extensions(struct comp_compositor *c, *out_exts = instance_extensions_android; *out_num = ARRAY_SIZE(instance_extensions_android); break; +#endif +#ifdef VK_USE_PLATFORM_WIN32_KHR + case WINDOW_MSWIN: + *out_exts = instance_extensions_windows; + *out_num = ARRAY_SIZE(instance_extensions_windows); + break; #endif default: return VK_ERROR_INITIALIZATION_FAILED; } @@ -1138,6 +1149,12 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c) c->settings.window_type = WINDOW_ANDROID; return true; } +#endif +#ifdef XRT_OS_WINDOWS + if (compositor_try_window(c, comp_window_mswin_create(c))) { + c->settings.window_type = WINDOW_MSWIN; + return true; + } #endif COMP_ERROR(c, "Failed to auto detect window support!"); break; @@ -1169,6 +1186,13 @@ compositor_init_window_pre_vulkan(struct comp_compositor *c) COMP_ERROR(c, "Android support not compiled in!"); #endif break; + + case WINDOW_MSWIN: +#ifdef XRT_OS_WINDOWS + compositor_try_window(c, comp_window_mswin_create(c)); +#else + COMP_ERROR(c, "Windows support not compiled in!"); +#endif default: COMP_ERROR(c, "Unknown window type!"); break; } diff --git a/src/xrt/compositor/main/comp_settings.h b/src/xrt/compositor/main/comp_settings.h index 60714840e..c1ab5fe0e 100644 --- a/src/xrt/compositor/main/comp_settings.h +++ b/src/xrt/compositor/main/comp_settings.h @@ -49,6 +49,7 @@ enum window_type WINDOW_DIRECT_RANDR, WINDOW_DIRECT_NVIDIA, WINDOW_ANDROID, + WINDOW_MSWIN, }; diff --git a/src/xrt/compositor/main/comp_window.h b/src/xrt/compositor/main/comp_window.h index c630f2681..060f382ce 100644 --- a/src/xrt/compositor/main/comp_window.h +++ b/src/xrt/compositor/main/comp_window.h @@ -82,6 +82,19 @@ comp_window_android_create(struct comp_compositor *c); #endif // XRT_OS_ANDROID +#ifdef XRT_OS_WINDOWS + +/*! + * Create a rendering window on Windows. + * + * @ingroup comp_main + * @public @memberof comp_window_mswin + */ +struct comp_target * +comp_window_mswin_create(struct comp_compositor *c); + +#endif // XRT_OS_WINDOWS + #ifdef __cplusplus } #endif diff --git a/src/xrt/compositor/main/comp_window_mswin.c b/src/xrt/compositor/main/comp_window_mswin.c new file mode 100644 index 000000000..e89917c0e --- /dev/null +++ b/src/xrt/compositor/main/comp_window_mswin.c @@ -0,0 +1,212 @@ +// Copyright 2019-2020, Collabora, Ltd. +// SPDX-License-Identifier: BSL-1.0 +/*! + * @file + * @brief Wayland window code. + * @author Lubosz Sarnecki + * @author Jakob Bornecrantz + * @ingroup comp_main + */ + +#include +#include +#include "xrt/xrt_compiler.h" +#include "main/comp_window.h" +#include "util/u_misc.h" + + +/* + * + * Private structs. + * + */ + +/*! + * A Microsoft Windows window. + * + * @implements comp_target_swapchain + */ +struct comp_window_mswin +{ + struct comp_target_swapchain base; + + HINSTANCE instance; + HWND window; + + + bool fullscreen_requested; +}; + +static WCHAR szWindowClass[] = L"Monado"; + +/* + * + * Functions. + * + */ + +static LRESULT CALLBACK +WndProc(HWND hWnd, unsigned int message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_PAINT: { + // paint the main window + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hWnd, &ps); + // TODO: Add any drawing code that uses hdc here... + EndPaint(hWnd, &ps); + } break; + case WM_DESTROY: + // Post a quit message and return. + //! @todo set quit flag + PostQuitMessage(0); + break; + default: return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + + +static inline struct vk_bundle * +get_vk(struct comp_window_mswin *cwm) +{ + return &cwm->base.base.c->vk; +} + +static void +comp_window_mswin_destroy(struct comp_target *ct) +{ + struct comp_window_mswin *cwm = (struct comp_window_mswin *)ct; + + comp_target_swapchain_cleanup(&cwm->base); + + //! @todo + + free(ct); +} + +static void +comp_window_mswin_update_window_title(struct comp_target *ct, const char *title) +{ + struct comp_window_mswin *cwm = (struct comp_window_mswin *)ct; + //! @todo +} + +static void +comp_window_mswin_fullscreen(struct comp_window_mswin *w) +{ + //! @todo +} + +static VkResult +comp_window_mswin_create_surface(struct comp_window_mswin *w, + VkSurfaceKHR *vk_surface) +{ + struct vk_bundle *vk = get_vk(w); + VkResult ret; + VkWin32SurfaceCreateInfoKHR surface_info = { + .sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR, + .hinstance = w->instance, + .hwnd = w->window, + }; + + ret = vk->vkCreateWin32SurfaceKHR(vk->instance, &surface_info, NULL, + vk_surface); + if (ret != VK_SUCCESS) { + COMP_ERROR(w->base.base.c, "vkCreateWin32SurfaceKHR: %s", + vk_result_string(ret)); + return ret; + } + + return VK_SUCCESS; +} + +static bool +comp_window_mswin_init_swapchain(struct comp_target *ct, + uint32_t width, + uint32_t height) +{ + struct comp_window_mswin *cwm = (struct comp_window_mswin *)ct; + VkResult ret; + + ret = comp_window_mswin_create_surface(cwm, &cwm->base.surface.handle); + if (ret != VK_SUCCESS) { + COMP_ERROR(ct->c, "Failed to create surface!"); + return false; + } + + //! @todo + + return true; +} + + +static void +comp_window_mswin_flush(struct comp_target *ct) +{ + struct comp_window_mswin *cwm = (struct comp_window_mswin *)ct; +} + + +static bool +comp_window_mswin_init(struct comp_target *ct) +{ + struct comp_window_mswin *cwm = (struct comp_window_mswin *)ct; + cwm->instance = GetModuleHandle(NULL); + + WNDCLASSEXW wcex; + U_ZERO(&wcex); + wcex.cbSize = sizeof(WNDCLASSEXW); + wcex.style = CS_HREDRAW | CS_VREDRAW; + + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = cwm->instance; + wcex.lpszClassName = szWindowClass; +//! @todo icon +#if 0 + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SAMPLEGUI)); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = MAKEINTRESOURCEW(IDC_SAMPLEGUI); + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); +#endif + RegisterClassExW(&wcex); + + cwm->window = + CreateWindowW(szWindowClass, L"Monado (Windowed)", + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, + 0, NULL, NULL, cwm->instance, NULL); + + return true; +} + +static void +comp_window_mswin_configure(struct comp_window_mswin *w, + int32_t width, + int32_t height) +{ + if (w->base.base.c->settings.fullscreen && !w->fullscreen_requested) { + COMP_DEBUG(w->base.base.c, "Setting full screen"); + comp_window_mswin_fullscreen(w); + w->fullscreen_requested = true; + } +} + +struct comp_target * +comp_window_mswin_create(struct comp_compositor *c) +{ + struct comp_window_mswin *w = U_TYPED_CALLOC(struct comp_window_mswin); + + comp_target_swapchain_init_set_fnptrs(&w->base); + + w->base.base.name = "MS Windows"; + w->base.base.destroy = comp_window_mswin_destroy; + w->base.base.flush = comp_window_mswin_flush; + w->base.base.init_pre_vulkan = comp_window_mswin_init; + w->base.base.init_post_vulkan = comp_window_mswin_init_swapchain; + w->base.base.set_title = comp_window_mswin_update_window_title; + w->base.base.c = c; + + return &w->base.base; +}