diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index c70e492b72..02d0282946 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -95,13 +95,13 @@ VulkanContext::VulkanContext() { GetInstanceLayerExtensionList(nullptr, instance_extension_properties_); } -VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32_t flags) { +VkResult VulkanContext::CreateInstance(const CreateInfo &info) { if (!vkCreateInstance) { init_error_ = "Vulkan not loaded - can't create instance"; return VK_ERROR_INITIALIZATION_FAILED; } - flags_ = flags; + flags_ = info.flags; // List extensions to try to enable. instance_extensions_enabled_.push_back(VK_KHR_SURFACE_EXTENSION_NAME); @@ -120,9 +120,9 @@ VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32 } VkApplicationInfo app_info { VK_STRUCTURE_TYPE_APPLICATION_INFO }; - app_info.pApplicationName = app_name; - app_info.applicationVersion = app_ver; - app_info.pEngineName = app_name; + app_info.pApplicationName = info.app_name; + app_info.applicationVersion = info.app_ver; + app_info.pEngineName = info.app_name; // Let's increment this when we make major engine/context changes. app_info.engineVersion = 2; app_info.apiVersion = VK_API_VERSION_1_0; @@ -583,65 +583,61 @@ void VulkanContext::DestroyDebugMsgCallback() { } } +void VulkanContext::InitSurface(WindowSystem winsys, void *data1, void *data2, int width, int height) { + winsys_ = winsys; + winsysData1_ = data1; + winsysData2_ = data2; + ReinitSurface(width, height); +} + +void VulkanContext::ReinitSurface(int width, int height) { + if (surface_ != VK_NULL_HANDLE) { + ILOG("Destroying Vulkan surface (%d, %d)", width_, height_); + vkDestroySurfaceKHR(instance_, surface_, nullptr); + surface_ = VK_NULL_HANDLE; + } + + ILOG("Creating Vulkan surface (%d, %d)", width, height); + switch (winsys_) { #ifdef _WIN32 -void VulkanContext::InitSurfaceWin32(HINSTANCE conn, HWND wnd) { - connection = conn; - window = wnd; + case WINDOWSYSTEM_WIN32: + { + HINSTANCE connection = (HINSTANCE)winsysData1_; + HWND window = (HWND)winsysData2_; - ReinitSurfaceWin32(); -} + RECT rc; + GetClientRect(window, &rc); + width = rc.right - rc.left; + height = rc.bottom - rc.top; -void VulkanContext::ReinitSurfaceWin32() { - if (surface_ != VK_NULL_HANDLE) { - vkDestroySurfaceKHR(instance_, surface_, nullptr); - surface_ = VK_NULL_HANDLE; + VkWin32SurfaceCreateInfoKHR win32{ VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; + win32.flags = 0; + win32.hwnd = window; + win32.hinstance = connection; + VkResult res = vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); + assert(res == VK_SUCCESS); + break; } - - RECT rc; - GetClientRect(window, &rc); - width_ = rc.right - rc.left; - height_ = rc.bottom - rc.top; - - VkResult U_ASSERT_ONLY res; - - VkWin32SurfaceCreateInfoKHR win32 = { VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR }; - win32.flags = 0; - win32.hwnd = window; - win32.hinstance = connection; - res = vkCreateWin32SurfaceKHR(instance_, &win32, nullptr, &surface_); - - assert(res == VK_SUCCESS); -} - -#elif defined(__ANDROID__) - -void VulkanContext::InitSurfaceAndroid(ANativeWindow *wnd, int width, int height) { - native_window = wnd; - - ReinitSurfaceAndroid(width, height); -} - -void VulkanContext::ReinitSurfaceAndroid(int width, int height) { - if (surface_ != VK_NULL_HANDLE) { - ILOG("Destroying Android Vulkan surface (%d, %d)", width_, height_); - vkDestroySurfaceKHR(instance_, surface_, nullptr); - surface_ = VK_NULL_HANDLE; +#endif +#if defined(__ANDROID__) + case WINDOWSYSTEM_ANDROID: + { + ANativeWindow *wnd = (ANativeWindow *)winsysData1_; + VkAndroidSurfaceCreateInfoKHR android{ VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; + android.flags = 0; + android.window = wnd; + VkResult res = vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); + assert(res == VK_SUCCESS); + break; + } +#endif + default: + _assert_msg_(G3D, false, "Vulkan support for chosen window system not implemented"); + break; } - - VkResult U_ASSERT_ONLY res; - - ILOG("Creating Android Vulkan surface (%d, %d)", width, height); - - VkAndroidSurfaceCreateInfoKHR android = { VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR }; - android.flags = 0; - android.window = native_window; - res = vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); - assert(res == VK_SUCCESS); - width_ = width; height_ = height; } -#endif bool VulkanContext::InitQueue() { // Iterate over each queue to learn whether it supports presenting: @@ -732,11 +728,8 @@ bool VulkanContext::InitQueue() { } bool VulkanContext::InitSwapchain() { - VkResult U_ASSERT_ONLY res; - - res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_); + VkResult res = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_devices_[physical_device_], surface_, &surfCapabilities_); assert(res == VK_SUCCESS); - uint32_t presentModeCount; res = vkGetPhysicalDeviceSurfacePresentModesKHR(physical_devices_[physical_device_], surface_, &presentModeCount, nullptr); assert(res == VK_SUCCESS); diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index d0de32ca72..0fee12770a 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -1,41 +1,16 @@ -#ifndef UTIL_INIT -#define UTIL_INIT +#pragma once -#ifdef __ANDROID__ -#undef NDEBUG // asserts -#endif #include #include #include #include #include "base/logging.h" - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define VK_USE_PLATFORM_WIN32_KHR -#define NOMINMAX /* Don't let Windows define min() or max() */ -#define APP_NAME_STR_LEN 80 -#include -#elif defined(__ANDROID__) // _WIN32 -#include -#define VK_USE_PLATFORM_ANDROID_KHR -#else -#define VK_USE_PLATFORM_XCB_KHR -#include -#endif // _WIN32 - #include "Common/Vulkan/VulkanLoader.h" // Amount of time, in nanoseconds, to wait for a command buffer to complete #define FENCE_TIMEOUT 10000000000 -#if defined(NDEBUG) && defined(__GNUC__) -#define U_ASSERT_ONLY __attribute__((unused)) -#else -#define U_ASSERT_ONLY -#endif - enum { VULKAN_FLAG_VALIDATE = 1, VULKAN_FLAG_PRESENT_MAILBOX = 2, @@ -54,6 +29,15 @@ enum { std::string VulkanVendorString(uint32_t vendorId); +// Not all will be usable on all platforms, of course... +enum WindowSystem { +#ifdef _WIN32 + WINDOWSYSTEM_WIN32, +#endif +#ifdef __ANDROID__ + WINDOWSYSTEM_ANDROID, +#endif +}; struct VulkanPhysicalDeviceInfo { VkFormat preferredDepthStencilFormat; @@ -117,7 +101,13 @@ public: VulkanContext(); ~VulkanContext(); - VkResult CreateInstance(const char *app_name, int app_ver, uint32_t flags); + struct CreateInfo { + const char *app_name; + int app_ver; + uint32_t flags; + }; + + VkResult CreateInstance(const CreateInfo &info); void DestroyInstance(); int GetBestPhysicalDevice(); @@ -134,13 +124,9 @@ public: VkPipelineCache CreatePipelineCache(); -#ifdef _WIN32 - void InitSurfaceWin32(HINSTANCE conn, HWND wnd); - void ReinitSurfaceWin32(); -#elif __ANDROID__ - void InitSurfaceAndroid(ANativeWindow *native_window, int width, int height); - void ReinitSurfaceAndroid(int width, int height); -#endif + // The parameters are whatever the chosen window system wants. + void InitSurface(WindowSystem winsys, void *data1, void *data2, int width = -1, int height = -1); + void ReinitSurface(int width = -1, int height = -1); bool InitQueue(); bool InitObjects(); bool InitSwapchain(); @@ -238,12 +224,11 @@ private: bool CheckLayers(const std::vector &layer_props, const std::vector &layer_names) const; -#ifdef _WIN32 - HINSTANCE connection = nullptr; // hInstance - Windows Instance - HWND window = nullptr; // hWnd - window handle -#elif __ANDROID__ // _WIN32 - ANativeWindow *native_window = nullptr; -#endif // _WIN32 + WindowSystem winsys_; + // Don't use the real types here to avoid having to include platform-specific stuff + // that we really don't want in everything that uses VulkanContext. + void *winsysData1_; + void *winsysData2_; VkInstance instance_ = VK_NULL_HANDLE; VkDevice device_ = VK_NULL_HANDLE; @@ -320,6 +305,3 @@ void finalize_glslang(); bool GLSLtoSPV(const VkShaderStageFlagBits shader_type, const char *pshader, std::vector &spirv, std::string *errorMessage = nullptr); const char *VulkanResultToString(VkResult res); - -#endif // UTIL_INIT - diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index 05e0f2ac80..e602de3a61 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -21,9 +21,7 @@ void VulkanTexture::CreateMappableImage() { vulkan_->Delete().QueueDeleteDeviceMemory(mappableMemory); } - bool U_ASSERT_ONLY pass; - - VkImageCreateInfo image_create_info = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; + VkImageCreateInfo image_create_info{ VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO }; image_create_info.imageType = VK_IMAGE_TYPE_2D; image_create_info.format = format_; image_create_info.extent.width = tex_width; @@ -40,7 +38,7 @@ void VulkanTexture::CreateMappableImage() { image_create_info.flags = 0; image_create_info.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; - VkMemoryAllocateInfo mem_alloc = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; + VkMemoryAllocateInfo mem_alloc{ VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO }; mem_alloc.allocationSize = 0; mem_alloc.memoryTypeIndex = 0; @@ -55,7 +53,7 @@ void VulkanTexture::CreateMappableImage() { mem_alloc.allocationSize = mem_reqs.size; // Find the memory type that is host mappable. - pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &mem_alloc.memoryTypeIndex); + bool pass = vulkan_->MemoryTypeFromProperties(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &mem_alloc.memoryTypeIndex); assert(pass); res = vkAllocateMemory(vulkan_->GetDevice(), &mem_alloc, NULL, &mappableMemory); diff --git a/Windows/GPU/WindowsVulkanContext.cpp b/Windows/GPU/WindowsVulkanContext.cpp index c6c2259fd8..87ceca5536 100644 --- a/Windows/GPU/WindowsVulkanContext.cpp +++ b/Windows/GPU/WindowsVulkanContext.cpp @@ -46,7 +46,7 @@ // and use the same render pass configuration (clear to black). However, we can later change this so we switch // to a non-clearing render pass in buffered mode, which might be a tiny bit faster. -#include +#include #include #include @@ -93,13 +93,15 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m g_Vulkan = nullptr; return false; } - // int vulkanFlags = VULKAN_FLAG_PRESENT_FIFO_RELAXED; - int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX; + VulkanContext::CreateInfo info{}; + info.app_name = "PPSSPP"; + info.app_ver = gitVer.ToInteger(); + info.flags = VULKAN_FLAG_PRESENT_MAILBOX; if (g_validate_) { - vulkanFlags |= VULKAN_FLAG_VALIDATE; + info.flags |= VULKAN_FLAG_VALIDATE; } - if (VK_SUCCESS != g_Vulkan->CreateInstance("PPSSPP", gitVer.ToInteger(), vulkanFlags)) { + if (VK_SUCCESS != g_Vulkan->CreateInstance(info)) { *error_message = g_Vulkan->InitError(); delete g_Vulkan; g_Vulkan = nullptr; @@ -119,7 +121,7 @@ bool WindowsVulkanContext::Init(HINSTANCE hInst, HWND hWnd, std::string *error_m int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions); } - g_Vulkan->InitSurfaceWin32(hInst, hWnd); + g_Vulkan->InitSurface(WINDOWSYSTEM_WIN32, (void *)hInst, (void *)hWnd); if (!g_Vulkan->InitObjects()) { *error_message = g_Vulkan->InitError(); Shutdown(); @@ -160,22 +162,16 @@ void WindowsVulkanContext::Shutdown() { finalize_glslang(); } -void WindowsVulkanContext::SwapBuffers() { -} - void WindowsVulkanContext::Resize() { draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); g_Vulkan->DestroyObjects(); - g_Vulkan->ReinitSurfaceWin32(); + g_Vulkan->ReinitSurface(); g_Vulkan->InitObjects(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); } -void WindowsVulkanContext::SwapInterval(int interval) { -} - void *WindowsVulkanContext::GetAPIContext() { return g_Vulkan; } diff --git a/Windows/GPU/WindowsVulkanContext.h b/Windows/GPU/WindowsVulkanContext.h index 52088efced..6c9f0f42dd 100644 --- a/Windows/GPU/WindowsVulkanContext.h +++ b/Windows/GPU/WindowsVulkanContext.h @@ -26,8 +26,8 @@ public: WindowsVulkanContext() : draw_(nullptr) {} bool Init(HINSTANCE hInst, HWND window, std::string *error_message) override; void Shutdown() override; - void SwapInterval(int interval) override; - void SwapBuffers() override; + void SwapInterval(int interval) override {} + void SwapBuffers() override {} void Resize() override; void *GetAPIContext(); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 87d5d799c0..970b36d27f 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -284,13 +284,17 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, g_LogOptions.breakOnWarning = true; g_LogOptions.msgBoxOnError = false; - ILOG("Creating vulkan context"); + ILOG("Creating Vulkan context"); Version gitVer(PPSSPP_GIT_VERSION); if (!g_Vulkan) { g_Vulkan = new VulkanContext(); } - if (VK_SUCCESS != g_Vulkan->CreateInstance("PPSSPP", gitVer.ToInteger(), VULKAN_FLAG_PRESENT_MAILBOX | VULKAN_FLAG_PRESENT_FIFO_RELAXED)) { + VulkanContext::CreateInfo info{}; + info.app_name = "PPSSPP"; + info.app_ver = gitVer.ToInteger(); + info.flags = VULKAN_FLAG_PRESENT_MAILBOX | VULKAN_FLAG_PRESENT_FIFO_RELAXED; + if (VK_SUCCESS != g_Vulkan->CreateInstance(info)) { ELOG("Failed to create vulkan context: %s", g_Vulkan->InitError().c_str()); System_SendMessage("toast", "No Vulkan compatible device found. Using OpenGL instead."); delete g_Vulkan; @@ -310,7 +314,7 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, g_Vulkan->ChooseDevice(physicalDevice); // Here we can enable device extensions if we like. - ILOG("Creating vulkan device"); + ILOG("Creating Vulkan device"); if (g_Vulkan->CreateDevice() != VK_SUCCESS) { ILOG("Failed to create vulkan device: %s", g_Vulkan->InitError().c_str()); System_SendMessage("toast", "No Vulkan driver found. Using OpenGL instead."); @@ -326,7 +330,7 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX, height = pixel_yres; } ILOG("InitSurfaceAndroid: width=%d height=%d", width, height); - g_Vulkan->InitSurfaceAndroid(wnd, width, height); + g_Vulkan->InitSurface(WINDOWSYSTEM_ANDROID, (void *)wnd, nullptr, width, height); if (g_validate_) { int bits = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT; g_Vulkan->InitDebugMsgCallback(&Vulkan_Dbg, bits, &g_LogOptions); @@ -386,7 +390,7 @@ void AndroidVulkanContext::Resize() { g_Vulkan->DestroyObjects(); // backbufferResize updated these values. TODO: Notify another way? - g_Vulkan->ReinitSurfaceAndroid(pixel_xres, pixel_yres); + g_Vulkan->ReinitSurface(pixel_xres, pixel_yres); g_Vulkan->InitObjects(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); ILOG("AndroidVulkanContext::Resize end (%d, %d)", g_Vulkan->GetBackbufferWidth(), g_Vulkan->GetBackbufferHeight()); diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp index 169d276ad8..a2c5c0a631 100644 --- a/ext/native/thin3d/VulkanQueueRunner.cpp +++ b/ext/native/thin3d/VulkanQueueRunner.cpp @@ -78,8 +78,6 @@ void VulkanQueueRunner::DestroyDeviceObjects() { } void VulkanQueueRunner::InitBackbufferRenderPass() { - VkResult U_ASSERT_ONLY res; - VkAttachmentDescription attachments[2]; attachments[0].format = vulkan_->GetSwapchainFormat(); attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; @@ -139,7 +137,7 @@ void VulkanQueueRunner::InitBackbufferRenderPass() { rp_info.dependencyCount = 1; rp_info.pDependencies = &dep; - res = vkCreateRenderPass(vulkan_->GetDevice(), &rp_info, nullptr, &backbufferRenderPass_); + VkResult res = vkCreateRenderPass(vulkan_->GetDevice(), &rp_info, nullptr, &backbufferRenderPass_); assert(res == VK_SUCCESS); }