diff --git a/SurrealEngine/GameWindow.cpp b/SurrealEngine/GameWindow.cpp index 86d35c7d..3d8c7834 100644 --- a/SurrealEngine/GameWindow.cpp +++ b/SurrealEngine/GameWindow.cpp @@ -5,16 +5,16 @@ #include #include #include -#include GameWindow::GameWindow(GameWindowHost* windowHost) : Widget(nullptr, WidgetType::Window, RenderAPI::Vulkan), windowHost(windowHost) { - std::shared_ptr instance = CreateZVulkanInstanceBuilder(this) + std::shared_ptr instance = VulkanInstanceBuilder() + .RequireExtensions(GetVulkanInstanceExtensions()) .OptionalSwapchainColorspace() .DebugLayer(false) .Create(); - std::shared_ptr surface = CreateZVulkanSurface(this, instance); + auto surface = std::make_shared(instance, CreateVulkanSurface(instance->Instance)); if (!surface) Exception::Throw("No vulkan surface found"); diff --git a/SurrealEngine/UI/Editor/EditorMainWindow.cpp b/SurrealEngine/UI/Editor/EditorMainWindow.cpp index 13eff003..a04e41e2 100644 --- a/SurrealEngine/UI/Editor/EditorMainWindow.cpp +++ b/SurrealEngine/UI/Editor/EditorMainWindow.cpp @@ -10,18 +10,18 @@ #include "RenderDevice/RenderDevice.h" #include #include -#include #include #include EditorMainWindow::EditorMainWindow() : MainWindow(RenderAPI::Vulkan) { - std::shared_ptr instance = CreateZVulkanInstanceBuilder(this) + std::shared_ptr instance = VulkanInstanceBuilder() + .RequireExtensions(GetVulkanInstanceExtensions()) .OptionalSwapchainColorspace() .DebugLayer(false) .Create(); - std::shared_ptr surface = CreateZVulkanSurface(this, instance); + auto surface = std::make_shared(instance, CreateVulkanSurface(instance->Instance)); if (!surface) Exception::Throw("No vulkan surface found"); diff --git a/Thirdparty/ZWidget/CMakeLists.txt b/Thirdparty/ZWidget/CMakeLists.txt index 7c5541ca..75137c9b 100644 --- a/Thirdparty/ZWidget/CMakeLists.txt +++ b/Thirdparty/ZWidget/CMakeLists.txt @@ -91,7 +91,6 @@ set(ZWIDGET_INCLUDES include/zwidget/window/waylandnativehandle.h include/zwidget/window/win32nativehandle.h include/zwidget/window/sdl2nativehandle.h - include/zwidget/window/zvulkanwidget.h include/zwidget/systemdialogs/open_folder_dialog.h include/zwidget/systemdialogs/open_file_dialog.h include/zwidget/systemdialogs/save_file_dialog.h diff --git a/Thirdparty/ZWidget/include/zwidget/core/widget.h b/Thirdparty/ZWidget/include/zwidget/core/widget.h index 09e23456..6d87f72a 100644 --- a/Thirdparty/ZWidget/include/zwidget/core/widget.h +++ b/Thirdparty/ZWidget/include/zwidget/core/widget.h @@ -88,7 +88,6 @@ class Widget : DisplayWindowHost void SetVisible(bool enable) { if (enable) Show(); else Hide(); } void Show(); void ShowFullscreen(); - bool IsFullscreen(); void ShowMaximized(); void ShowMinimized(); void ShowNormal(); @@ -105,6 +104,7 @@ class Widget : DisplayWindowHost bool IsEnabled(); bool IsVisible(); bool IsHidden(); + bool IsFullscreen(); void SetFocus(); void SetEnabled(bool value); @@ -155,6 +155,10 @@ class Widget : DisplayWindowHost int GetNativePixelWidth(); int GetNativePixelHeight(); + // Vulkan support: + std::vector GetVulkanInstanceExtensions() { return Window()->DispWindow->GetVulkanInstanceExtensions(); } + VkSurfaceKHR CreateVulkanSurface(VkInstance instance) { return Window()->DispWindow->CreateVulkanSurface(instance); } + protected: virtual void OnPaintFrame(Canvas* canvas); virtual void OnPaint(Canvas* canvas) { } diff --git a/Thirdparty/ZWidget/include/zwidget/window/sdl2nativehandle.h b/Thirdparty/ZWidget/include/zwidget/window/sdl2nativehandle.h index f4b637b5..9e396a80 100644 --- a/Thirdparty/ZWidget/include/zwidget/window/sdl2nativehandle.h +++ b/Thirdparty/ZWidget/include/zwidget/window/sdl2nativehandle.h @@ -5,26 +5,8 @@ struct SDL_Window; -#ifndef VULKAN_H_ - -#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; - -#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) -#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; -#else -#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; -#endif - -VK_DEFINE_HANDLE(VkInstance) -VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) - -#endif - class SDL2NativeHandle { public: SDL_Window* window = nullptr; - - std::vector VulkanGetInstanceExtensions(); - VkSurfaceKHR VulkanCreateSurface(VkInstance instance); }; diff --git a/Thirdparty/ZWidget/include/zwidget/window/window.h b/Thirdparty/ZWidget/include/zwidget/window/window.h index 4aca8d0b..ad59f1f0 100644 --- a/Thirdparty/ZWidget/include/zwidget/window/window.h +++ b/Thirdparty/ZWidget/include/zwidget/window/window.h @@ -7,6 +7,21 @@ #include #include "../core/rect.h" +#ifndef VULKAN_H_ + +#define VK_DEFINE_HANDLE(object) typedef struct object##_T* object; + +#if defined(__LP64__) || defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__) +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef struct object##_T *object; +#else +#define VK_DEFINE_NON_DISPATCHABLE_HANDLE(object) typedef uint64_t object; +#endif + +VK_DEFINE_HANDLE(VkInstance) +VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkSurfaceKHR) + +#endif + class Widget; class OpenFileDialog; class SaveFileDialog; @@ -187,6 +202,9 @@ class DisplayWindow virtual void SetClipboardText(const std::string& text) = 0; virtual void* GetNativeHandle() = 0; + + virtual std::vector GetVulkanInstanceExtensions() = 0; + virtual VkSurfaceKHR CreateVulkanSurface(VkInstance instance) = 0; }; class DisplayBackend diff --git a/Thirdparty/ZWidget/include/zwidget/window/zvulkanwidget.h b/Thirdparty/ZWidget/include/zwidget/window/zvulkanwidget.h deleted file mode 100644 index 368a1861..00000000 --- a/Thirdparty/ZWidget/include/zwidget/window/zvulkanwidget.h +++ /dev/null @@ -1,87 +0,0 @@ -#pragma once - -#include -#include "../core/widget.h" - -#include "sdl2nativehandle.h" - -#if defined(VK_USE_PLATFORM_WIN32_KHR) -#include "win32nativehandle.h" -#endif - -#if defined(VK_USE_PLATFORM_XLIB_KHR) -#include "x11nativehandle.h" -#endif - -#if defined(VK_USE_PLATFORM_WAYLAND_KHR) -#include "waylandnativehandle.h" -#endif - -inline VulkanInstanceBuilder CreateZVulkanInstanceBuilder(Widget* widget) -{ - if (DisplayBackend::Get()->IsSDL2()) - { - auto handle = (SDL2NativeHandle*)widget->GetNativeHandle(); - return VulkanInstanceBuilder().RequireExtensions(handle->VulkanGetInstanceExtensions()); - } - -#if defined(VK_USE_PLATFORM_WIN32_KHR) - if (DisplayBackend::Get()->IsWin32()) - { - return VulkanInstanceBuilder().RequireWin32Surface(); - } -#endif - -#if defined(VK_USE_PLATFORM_XLIB_KHR) - if (DisplayBackend::Get()->IsX11()) - { - return VulkanInstanceBuilder().RequireX11Surface(); - } -#endif - -#if defined(VK_USE_PLATFORM_WAYLAND_KHR) - if (DisplayBackend::Get()->IsWayland()) - { - return VulkanInstanceBuilder().RequireWaylandSurface(); - } -#endif - - VulkanError("Could not create vulkan instance for widget"); - return {}; -} - -inline std::shared_ptr CreateZVulkanSurface(Widget* widget, std::shared_ptr instance) -{ - if (DisplayBackend::Get()->IsSDL2()) - { - auto handle = (SDL2NativeHandle*)widget->GetNativeHandle(); - return std::make_shared(instance, handle->VulkanCreateSurface(instance->Instance)); - } - -#if defined(VK_USE_PLATFORM_WIN32_KHR) - if (DisplayBackend::Get()->IsWin32()) - { - auto handle = (Win32NativeHandle*)widget->GetNativeHandle(); - return std::make_shared(instance, handle->hwnd); - } -#endif - -#if defined(VK_USE_PLATFORM_XLIB_KHR) - if (DisplayBackend::Get()->IsX11()) - { - auto handle = (X11NativeHandle*)widget->GetNativeHandle(); - return std::make_shared(instance, handle->display, handle->window); - } -#endif - -#if defined(VK_USE_PLATFORM_WAYLAND_KHR) - if (DisplayBackend::Get()->IsWayland()) - { - auto handle = (WaylandNativeHandle*)widget->GetNativeHandle(); - return std::make_shared(instance, handle->display, handle->surface); - } -#endif - - VulkanError("Could not create vulkan surface for widget"); - return {}; -} diff --git a/Thirdparty/ZWidget/src/core/nanosvg/nanosvgrast.h b/Thirdparty/ZWidget/src/core/nanosvg/nanosvgrast.h index 89fae383..a3295098 100644 --- a/Thirdparty/ZWidget/src/core/nanosvg/nanosvgrast.h +++ b/Thirdparty/ZWidget/src/core/nanosvg/nanosvgrast.h @@ -331,7 +331,7 @@ static float nsvg__normalize(float *x, float* y) } static float nsvg__absf(float x) { return x < 0 ? -x : x; } -static float nsvg__roundf(float x) { return (x >= 0) ? floorf(x + 0.5) : ceilf(x - 0.5); } +static float nsvg__roundf(float x) { return (x >= 0) ? (float)floorf(x + 0.5f) : (float)ceilf(x - 0.5f); } static void nsvg__flattenCubicBez(NSVGrasterizer* r, float x1, float y1, float x2, float y2, diff --git a/Thirdparty/ZWidget/src/core/widget.cpp b/Thirdparty/ZWidget/src/core/widget.cpp index 4fca86df..e0c637f0 100644 --- a/Thirdparty/ZWidget/src/core/widget.cpp +++ b/Thirdparty/ZWidget/src/core/widget.cpp @@ -13,8 +13,11 @@ Widget::Widget(Widget* parent, WidgetType type, RenderAPI renderAPI) : Type(type { Widget* owner = parent ? parent->Window() : nullptr; DispWindow = DisplayWindow::Create(this, type == WidgetType::Popup, owner ? owner->DispWindow.get() : nullptr, renderAPI); - DispCanvas = Canvas::create(); - DispCanvas->attach(DispWindow.get()); + if (renderAPI == RenderAPI::Unspecified || renderAPI == RenderAPI::Bitmap) + { + DispCanvas = Canvas::create(); + DispCanvas->attach(DispWindow.get()); + } SetStyleState("root"); SetWindowBackground(GetStyleColor("window-background")); @@ -47,7 +50,8 @@ void Widget::SetCanvas(std::unique_ptr canvas) { if (DispWindow) { - DispCanvas->detach(); + if (DispCanvas) + DispCanvas->detach(); DispCanvas = std::move(canvas); DispCanvas->attach(DispWindow.get()); } @@ -224,7 +228,6 @@ bool Widget::IsFullscreen() { return DispWindow->IsWindowFullscreen(); } - return false; } @@ -331,9 +334,12 @@ void Widget::Update() void Widget::Repaint() { Widget* w = Window(); - w->DispCanvas->begin(WindowBackground); - w->Paint(w->DispCanvas.get()); - w->DispCanvas->end(); + if (w->DispCanvas) + { + w->DispCanvas->begin(WindowBackground); + w->Paint(w->DispCanvas.get()); + w->DispCanvas->end(); + } } void Widget::Paint(Canvas* canvas) diff --git a/Thirdparty/ZWidget/src/widgets/listview/listview.cpp b/Thirdparty/ZWidget/src/widgets/listview/listview.cpp index 6a3b1b71..54f48552 100644 --- a/Thirdparty/ZWidget/src/widgets/listview/listview.cpp +++ b/Thirdparty/ZWidget/src/widgets/listview/listview.cpp @@ -25,7 +25,7 @@ void ListView::RemoveItem(int index) if (selectedItem == items.size()) { - selectedItem = !items.empty() ? items.size() - 1 : 0; + selectedItem = !items.empty() ? (int)items.size() - 1 : 0; } } diff --git a/Thirdparty/ZWidget/src/window/sdl2/sdl2_display_window.cpp b/Thirdparty/ZWidget/src/window/sdl2/sdl2_display_window.cpp index 173d7260..b5d2ffad 100644 --- a/Thirdparty/ZWidget/src/window/sdl2/sdl2_display_window.cpp +++ b/Thirdparty/ZWidget/src/window/sdl2/sdl2_display_window.cpp @@ -1,6 +1,7 @@ #include "sdl2_display_window.h" #include +#include Uint32 SDL2DisplayWindow::PaintEventNumber = 0xffffffff; bool SDL2DisplayWindow::ExitRunLoop; @@ -33,8 +34,10 @@ SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWi flags |= SDL_WINDOW_VULKAN; else if (renderAPI == RenderAPI::OpenGL) flags |= SDL_WINDOW_OPENGL; +#if defined(__APPLE__) else if (renderAPI == RenderAPI::Metal) flags |= SDL_WINDOW_METAL; +#endif if (popupWindow) flags |= SDL_WINDOW_BORDERLESS; @@ -73,6 +76,29 @@ SDL2DisplayWindow::~SDL2DisplayWindow() Handle.window = nullptr; } +std::vector SDL2DisplayWindow::GetVulkanInstanceExtensions() +{ + unsigned int extCount = 0; + SDL_Vulkan_GetInstanceExtensions(Handle.window, &extCount, nullptr); + std::vector extNames(extCount); + SDL_Vulkan_GetInstanceExtensions(Handle.window, &extCount, extNames.data()); + + std::vector result; + result.reserve(extNames.size()); + for (const char* ext : extNames) + result.emplace_back(ext); + return result; +} + +VkSurfaceKHR SDL2DisplayWindow::CreateVulkanSurface(VkInstance instance) +{ + VkSurfaceKHR surfaceHandle = {}; + SDL_Vulkan_CreateSurface(Handle.window, instance, &surfaceHandle); + if (surfaceHandle) + throw std::runtime_error("Could not create vulkan surface"); + return surfaceHandle; +} + void SDL2DisplayWindow::SetWindowTitle(const std::string& text) { SDL_SetWindowTitle(Handle.window, text.c_str()); diff --git a/Thirdparty/ZWidget/src/window/sdl2/sdl2_display_window.h b/Thirdparty/ZWidget/src/window/sdl2/sdl2_display_window.h index e6e015ad..f891c672 100644 --- a/Thirdparty/ZWidget/src/window/sdl2/sdl2_display_window.h +++ b/Thirdparty/ZWidget/src/window/sdl2/sdl2_display_window.h @@ -52,6 +52,9 @@ class SDL2DisplayWindow : public DisplayWindow void* GetNativeHandle() override { return &Handle; } + std::vector GetVulkanInstanceExtensions() override; + VkSurfaceKHR CreateVulkanSurface(VkInstance instance) override; + static void DispatchEvent(const SDL_Event& event); static SDL2DisplayWindow* FindEventWindow(const SDL_Event& event); @@ -93,10 +96,9 @@ class SDL2DisplayWindow : public DisplayWindow int BackBufferHeight = 0; bool CursorLocked = false; + bool isFullscreen = false; static bool ExitRunLoop; static Uint32 PaintEventNumber; static std::unordered_map WindowList; - - bool isFullscreen = false; }; diff --git a/Thirdparty/ZWidget/src/window/wayland/wayland_display_window.cpp b/Thirdparty/ZWidget/src/window/wayland/wayland_display_window.cpp index 22a3c51c..c8468888 100644 --- a/Thirdparty/ZWidget/src/window/wayland/wayland_display_window.cpp +++ b/Thirdparty/ZWidget/src/window/wayland/wayland_display_window.cpp @@ -153,11 +153,6 @@ void WaylandDisplayWindow::ShowFullscreen() } } -bool WaylandDisplayWindow::IsWindowFullscreen() -{ - return isFullscreen; -} - void WaylandDisplayWindow::ShowMaximized() { if (m_XDGToplevel) @@ -173,10 +168,12 @@ void WaylandDisplayWindow::ShowMinimized() void WaylandDisplayWindow::ShowNormal() { if (m_XDGToplevel) - { m_XDGToplevel.unset_fullscreen(); - isFullscreen = false; - } +} + +bool WaylandDisplayWindow::IsWindowFullscreen() +{ + return isFullscreen; } void WaylandDisplayWindow::Hide() @@ -381,3 +378,95 @@ std::string WaylandDisplayWindow::GetWaylandWindowID() { return m_windowID; } + +// This is to avoid needing all the Vulkan headers and the volk binding library just for this: +#ifndef VK_VERSION_1_0 + +#define VKAPI_CALL +#define VKAPI_PTR VKAPI_CALL + +typedef uint32_t VkFlags; +typedef enum VkStructureType { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000, VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; +typedef enum VkResult { VK_SUCCESS = 0, VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; +typedef struct VkAllocationCallbacks VkAllocationCallbacks; + +typedef void (VKAPI_PTR* PFN_vkVoidFunction)(void); +typedef PFN_vkVoidFunction(VKAPI_PTR* PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); + +#ifndef VK_KHR_wayland_surface + +typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; +typedef struct VkWaylandSurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkWaylandSurfaceCreateFlagsKHR flags; + struct wl_display* display; + struct wl_surface* surface; +} VkWaylandSurfaceCreateInfoKHR; + +typedef VkResult(VKAPI_PTR* PFN_vkCreateWaylandSurfaceKHR)(VkInstance instance, const VkWaylandSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#endif +#endif + +class ZWidgetWaylandVulkanLoader +{ +public: + ZWidgetWaylandVulkanLoader() + { +#if defined(__APPLE__) + module = dlopen("libvulkan.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libvulkan.1.dylib", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libMoltenVK.dylib", RTLD_NOW | RTLD_LOCAL); +#else + module = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_LOCAL); + if (!module) + module = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); +#endif + + if (!module) + throw std::runtime_error("Could not load vulkan"); + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)dlsym(module, "vkGetInstanceProcAddr"); + if (!vkGetInstanceProcAddr) + { + dlclose(module); + throw std::runtime_error("vkGetInstanceProcAddr not found"); + } + } + + ~ZWidgetWaylandVulkanLoader() + { + dlclose(module); + } + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr; + void* module = nullptr; +}; + +VkSurfaceKHR WaylandDisplayWindow::CreateVulkanSurface(VkInstance instance) +{ + static ZWidgetWaylandVulkanLoader loader; + + auto vkCreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR)loader.vkGetInstanceProcAddr(instance, "vkCreateWaylandSurfaceKHR"); + if (!vkCreateWaylandSurfaceKHR) + throw std::runtime_error("Could not create vulkan surface"); + + VkWaylandSurfaceCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR }; + createInfo.display = m_NativeHandle.display; + createInfo.surface = m_NativeHandle.surface; + + VkSurfaceKHR surface = {}; + VkResult result = vkCreateWaylandSurfaceKHR(instance, &createInfo, nullptr, &surface); + if (result != VK_SUCCESS) + throw std::runtime_error("Could not create vulkan surface"); + return surface; +} + +std::vector WaylandDisplayWindow::GetVulkanInstanceExtensions() +{ + return { "VK_KHR_surface", "VK_KHR_wayland_surface" }; +} diff --git a/Thirdparty/ZWidget/src/window/wayland/wayland_display_window.h b/Thirdparty/ZWidget/src/window/wayland/wayland_display_window.h index 6807601a..24dbf344 100644 --- a/Thirdparty/ZWidget/src/window/wayland/wayland_display_window.h +++ b/Thirdparty/ZWidget/src/window/wayland/wayland_display_window.h @@ -96,7 +96,6 @@ class WaylandDisplayWindow : public DisplayWindow void ShowMaximized() override; void ShowMinimized() override; void ShowNormal() override; - bool IsWindowFullscreen() override; void Hide() override; void Activate() override; void ShowCursor(bool enable) override; @@ -126,8 +125,12 @@ class WaylandDisplayWindow : public DisplayWindow Point MapFromGlobal(const Point& pos) const override; Point MapToGlobal(const Point& pos) const override; - void* GetNativeHandle() override { return (void*)&m_NativeHandle; } - wayland::surface_t GetWindowSurface() { return m_AppSurface; } + void* GetNativeHandle() override { return (void*)&m_NativeHandle; } + + std::vector GetVulkanInstanceExtensions() override; + VkSurfaceKHR CreateVulkanSurface(VkInstance instance) override; + + wayland::surface_t GetWindowSurface() { return m_AppSurface; } private: // Event handlers as otherwise linking DisplayWindowHost On...() functions with Wayland events directly crashes the app @@ -183,7 +186,7 @@ class WaylandDisplayWindow : public DisplayWindow std::shared_ptr shared_mem; - bool isFullscreen; + bool isFullscreen = false; // Helper functions void CreateBuffers(int32_t width, int32_t height); diff --git a/Thirdparty/ZWidget/src/window/win32/win32_display_window.cpp b/Thirdparty/ZWidget/src/window/win32/win32_display_window.cpp index b23b1271..519e5258 100644 --- a/Thirdparty/ZWidget/src/window/win32/win32_display_window.cpp +++ b/Thirdparty/ZWidget/src/window/win32/win32_display_window.cpp @@ -126,10 +126,10 @@ void Win32DisplayWindow::Show() void Win32DisplayWindow::ShowFullscreen() { HDC screenDC = GetDC(0); - DWORD dwStyle = GetWindowLong(WindowHandle.hwnd, GWL_STYLE); int width = GetDeviceCaps(screenDC, HORZRES); int height = GetDeviceCaps(screenDC, VERTRES); ReleaseDC(0, screenDC); + DWORD dwStyle = GetWindowLong(WindowHandle.hwnd, GWL_STYLE); SetWindowLongPtr(WindowHandle.hwnd, GWL_EXSTYLE, WS_EX_APPWINDOW); SetWindowLongPtr(WindowHandle.hwnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW); SetWindowPos(WindowHandle.hwnd, HWND_TOP, 0, 0, width, height, SWP_FRAMECHANGED | SWP_SHOWWINDOW); @@ -148,9 +148,12 @@ void Win32DisplayWindow::ShowMinimized() void Win32DisplayWindow::ShowNormal() { - SetWindowLongPtr(WindowHandle.hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + if (Fullscreen) + { + SetWindowLongPtr(WindowHandle.hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW); + Fullscreen = false; + } ShowWindow(WindowHandle.hwnd, SW_NORMAL); - Fullscreen = false; } bool Win32DisplayWindow::IsWindowFullscreen() @@ -670,6 +673,87 @@ Size Win32DisplayWindow::GetScreenSize() return Size(screenWidth / dpiScale, screenHeight / dpiScale); } +// This is to avoid needing all the Vulkan headers and the volk binding library just for this: +#ifndef VK_VERSION_1_0 + +#define VKAPI_CALL __stdcall +#define VKAPI_PTR VKAPI_CALL + +typedef uint32_t VkFlags; +typedef enum VkStructureType { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000, VK_OBJECT_TYPE_MAX_ENUM = 0x7FFFFFFF } VkStructureType; +typedef enum VkResult { VK_SUCCESS = 0, VK_RESULT_MAX_ENUM = 0x7FFFFFFF } VkResult; +typedef struct VkAllocationCallbacks VkAllocationCallbacks; + +typedef void (VKAPI_PTR* PFN_vkVoidFunction)(void); +typedef PFN_vkVoidFunction(VKAPI_PTR* PFN_vkGetInstanceProcAddr)(VkInstance instance, const char* pName); + +#ifndef VK_KHR_win32_surface + +typedef VkFlags VkWin32SurfaceCreateFlagsKHR; +typedef struct VkWin32SurfaceCreateInfoKHR +{ + VkStructureType sType; + const void* pNext; + VkWin32SurfaceCreateFlagsKHR flags; + HINSTANCE hinstance; + HWND hwnd; +} VkWin32SurfaceCreateInfoKHR; + +typedef VkResult(VKAPI_PTR* PFN_vkCreateWin32SurfaceKHR)(VkInstance instance, const VkWin32SurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface); + +#endif +#endif + +class ZWidgetVulkanLoader +{ +public: + ZWidgetVulkanLoader() + { + module = LoadLibraryA("vulkan-1.dll"); + if (!module) + throw std::runtime_error("Could not load vulkan-1.dll"); + + vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)(void(*)(void))GetProcAddress(module, "vkGetInstanceProcAddr"); + if (!vkGetInstanceProcAddr) + { + FreeLibrary(module); + throw std::runtime_error("vkGetInstanceProcAddr not found in vulkan-1.dll"); + } + } + + ~ZWidgetVulkanLoader() + { + FreeLibrary(module); + } + + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = nullptr; + HMODULE module = {}; +}; + +VkSurfaceKHR Win32DisplayWindow::CreateVulkanSurface(VkInstance instance) +{ + static ZWidgetVulkanLoader loader; + + auto vkCreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR)loader.vkGetInstanceProcAddr(instance, "vkCreateWin32SurfaceKHR"); + if (!vkCreateWin32SurfaceKHR) + throw std::runtime_error("Could not create vulkan surface"); + + VkWin32SurfaceCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; + createInfo.hwnd = WindowHandle.hwnd; + createInfo.hinstance = GetModuleHandle(nullptr); + + VkSurfaceKHR surface = {}; + VkResult result = vkCreateWin32SurfaceKHR(instance, &createInfo, nullptr, &surface); + if (result != VK_SUCCESS) + throw std::runtime_error("Could not create vulkan surface"); + return surface; +} + +std::vector Win32DisplayWindow::GetVulkanInstanceExtensions() +{ + return { "VK_KHR_surface", "VK_KHR_win32_surface" }; +} + static void CALLBACK Win32TimerCallback(HWND handle, UINT message, UINT_PTR timerID, DWORD timestamp) { auto it = Win32DisplayWindow::Timers.find(timerID); diff --git a/Thirdparty/ZWidget/src/window/win32/win32_display_window.h b/Thirdparty/ZWidget/src/window/win32/win32_display_window.h index 60093756..7666274b 100644 --- a/Thirdparty/ZWidget/src/window/win32/win32_display_window.h +++ b/Thirdparty/ZWidget/src/window/win32/win32_display_window.h @@ -57,6 +57,9 @@ class Win32DisplayWindow : public DisplayWindow void* GetNativeHandle() override { return &WindowHandle; } + std::vector GetVulkanInstanceExtensions() override; + VkSurfaceKHR CreateVulkanSurface(VkInstance instance) override; + static void ProcessEvents(); static void RunLoop(); static void ExitLoop(); diff --git a/Thirdparty/ZWidget/src/window/window.cpp b/Thirdparty/ZWidget/src/window/window.cpp index 2d2249bf..5fc35b23 100644 --- a/Thirdparty/ZWidget/src/window/window.cpp +++ b/Thirdparty/ZWidget/src/window/window.cpp @@ -135,34 +135,12 @@ std::unique_ptr DisplayBackend::TryCreateWin32() #ifdef USE_SDL2 #include "sdl2/sdl2_display_backend.h" -#include std::unique_ptr DisplayBackend::TryCreateSDL2() { return std::make_unique(); } -std::vector SDL2NativeHandle::VulkanGetInstanceExtensions() -{ - unsigned int extCount = 0; - SDL_Vulkan_GetInstanceExtensions(window, &extCount, nullptr); - std::vector extNames(extCount); - SDL_Vulkan_GetInstanceExtensions(window, &extCount, extNames.data()); - - std::vector result; - result.reserve(extNames.size()); - for (const char* ext : extNames) - result.emplace_back(ext); - return result; -} - -VkSurfaceKHR SDL2NativeHandle::VulkanCreateSurface(VkInstance instance) -{ - VkSurfaceKHR surfaceHandle = {}; - SDL_Vulkan_CreateSurface(window, instance, &surfaceHandle); - return surfaceHandle; -} - #else std::unique_ptr DisplayBackend::TryCreateSDL2() @@ -170,16 +148,6 @@ std::unique_ptr DisplayBackend::TryCreateSDL2() return nullptr; } -std::vector SDL2NativeHandle::VulkanGetInstanceExtensions() -{ - return {}; -} - -VkSurfaceKHR SDL2NativeHandle::VulkanCreateSurface(VkInstance instance) -{ - return {}; -} - #endif #ifdef USE_X11 diff --git a/Thirdparty/ZWidget/src/window/x11/x11_display_window.cpp b/Thirdparty/ZWidget/src/window/x11/x11_display_window.cpp index 59de5780..cd3fe273 100644 --- a/Thirdparty/ZWidget/src/window/x11/x11_display_window.cpp +++ b/Thirdparty/ZWidget/src/window/x11/x11_display_window.cpp @@ -1067,3 +1067,95 @@ void* X11DisplayWindow::StartTimer(int timeoutMilliseconds, std::function X11DisplayWindow::GetVulkanInstanceExtensions() +{ + return { "VK_KHR_surface", "VK_KHR_xlib_surface" }; +} diff --git a/Thirdparty/ZWidget/src/window/x11/x11_display_window.h b/Thirdparty/ZWidget/src/window/x11/x11_display_window.h index 9174e6a2..bd65d8d1 100644 --- a/Thirdparty/ZWidget/src/window/x11/x11_display_window.h +++ b/Thirdparty/ZWidget/src/window/x11/x11_display_window.h @@ -56,6 +56,9 @@ class X11DisplayWindow : public DisplayWindow void* GetNativeHandle() override; + std::vector GetVulkanInstanceExtensions() override; + VkSurfaceKHR CreateVulkanSurface(VkInstance instance) override; + static void ProcessEvents(); static void RunLoop(); static void ExitLoop(); @@ -109,6 +112,7 @@ class X11DisplayWindow : public DisplayWindow bool isCursorEnabled = true; bool isMapped = false; bool isMinimized = false; + bool isFullscreen = false; double dpiScale = 1.0; Pixmap cursor_bitmap = None; @@ -129,7 +133,5 @@ class X11DisplayWindow : public DisplayWindow bool needsUpdate = false; - bool isFullscreen = false; - friend class X11DisplayBackend; };