From 2250ef799cad6e507bde4e2cebc2f1ab76c706f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 18 Dec 2017 12:22:12 +0100 Subject: [PATCH 01/16] Avoid including platform-specific headers in VulkanContext.h --- Common/Vulkan/VulkanContext.cpp | 113 +++++++++++------------- Common/Vulkan/VulkanContext.h | 68 ++++++-------- Common/Vulkan/VulkanImage.cpp | 8 +- Windows/GPU/WindowsVulkanContext.cpp | 22 ++--- Windows/GPU/WindowsVulkanContext.h | 4 +- android/jni/app-android.cpp | 14 +-- ext/native/thin3d/VulkanQueueRunner.cpp | 4 +- 7 files changed, 102 insertions(+), 131 deletions(-) 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); } From 2822a4f187519fbbb23fe117eea64272203e4e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 19 Dec 2017 15:20:24 +0100 Subject: [PATCH 02/16] Win32: Use the standard thread APIs to manage the emu thread. --- Windows/EmuThread.cpp | 82 ++++++++++------------------------ ext/native/thread/threadutil.h | 2 - 2 files changed, 24 insertions(+), 60 deletions(-) diff --git a/Windows/EmuThread.cpp b/Windows/EmuThread.cpp index 28626ae301..b48f92e394 100644 --- a/Windows/EmuThread.cpp +++ b/Windows/EmuThread.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include "base/timeutil.h" #include "base/NativeApp.h" @@ -21,20 +23,13 @@ #include "Core/Config.h" #include "thread/threadutil.h" -#include -#include -#include - -#pragma intrinsic(_InterlockedExchange) - static std::mutex emuThreadLock; -static HANDLE emuThread; -static volatile long emuThreadReady; +static std::thread emuThread; +static std::atomic emuThreadState; extern std::vector GetWideCmdLine(); -enum EmuThreadStatus : long -{ +enum EmuThreadStatus : int { THREAD_NONE = 0, THREAD_INIT, THREAD_CORE_LOOP, @@ -42,75 +37,51 @@ enum EmuThreadStatus : long THREAD_END, }; -HANDLE EmuThread_GetThreadHandle() -{ +void EmuThreadFunc(); + +void EmuThread_Start() { std::lock_guard guard(emuThreadLock); - return emuThread; + emuThread = std::thread(&EmuThreadFunc); } -unsigned int WINAPI TheThread(void *); - -void EmuThread_Start() -{ - std::lock_guard guard(emuThreadLock); - emuThread = (HANDLE)_beginthreadex(0, 0, &TheThread, 0, 0, 0); -} - -void EmuThread_Stop() -{ +void EmuThread_Stop() { // Already stopped? { std::lock_guard guard(emuThreadLock); - if (emuThread == NULL || emuThreadReady == THREAD_END) + if (emuThreadState == THREAD_END) return; } UpdateUIState(UISTATE_EXIT); Core_Stop(); Core_WaitInactive(800); - if (WAIT_TIMEOUT == WaitForSingleObject(emuThread, 800)) - { - _dbg_assert_msg_(COMMON, false, "Wait for EmuThread timed out."); - } - { - std::lock_guard guard(emuThreadLock); - CloseHandle(emuThread); - emuThread = 0; - } + emuThread.join(); + PostMessage(MainWindow::GetHWND(), MainWindow::WM_USER_UPDATE_UI, 0, 0); } -bool EmuThread_Ready() -{ - return emuThreadReady == THREAD_CORE_LOOP; +bool EmuThread_Ready() { + return emuThreadState == THREAD_CORE_LOOP; } -unsigned int WINAPI TheThread(void *) -{ - _InterlockedExchange(&emuThreadReady, THREAD_INIT); +void EmuThreadFunc() { + emuThreadState = THREAD_INIT; - setCurrentThreadName("Emu"); // And graphics... + setCurrentThreadName("Emu"); host = new WindowsHost(MainWindow::GetHInstance(), MainWindow::GetHWND(), MainWindow::GetDisplayHWND()); host->SetWindowTitle(nullptr); - // Convert the command-line arguments to Unicode, then to proper UTF-8 - // (the benefit being that we don't have to pollute the UI project with win32 ifdefs and lots of ConvertTo). - // This avoids issues with PPSSPP inadvertently destroying paths with Unicode glyphs - // (using the ANSI args resulted in Japanese/Chinese glyphs being turned into question marks, at least for me..). - // -TheDax + // We convert command line arguments to UTF-8 immediately. std::vector wideArgs = GetWideCmdLine(); std::vector argsUTF8; for (auto& string : wideArgs) { argsUTF8.push_back(ConvertWStringToUTF8(string)); } - std::vector args; - for (auto& string : argsUTF8) { args.push_back(string.c_str()); } - bool performingRestart = NativeIsRestarting(); NativeInit(static_cast(args.size()), &args[0], "1234", "1234", nullptr); @@ -165,7 +136,7 @@ unsigned int WINAPI TheThread(void *) } // No safe way out without graphics. - ExitProcess(1); + exit(1); } NativeInitGraphics(graphicsContext); @@ -179,34 +150,29 @@ unsigned int WINAPI TheThread(void *) goto shutdown; } - _InterlockedExchange(&emuThreadReady, THREAD_CORE_LOOP); + emuThreadState = THREAD_CORE_LOOP; if (g_Config.bBrowse) PostMessage(MainWindow::GetHWND(), WM_COMMAND, ID_FILE_LOAD, 0); Core_EnableStepping(FALSE); - while (GetUIState() != UISTATE_EXIT) - { + while (GetUIState() != UISTATE_EXIT) { // We're here again, so the game quit. Restart Core_Run() which controls the UI. // This way they can load a new game. if (!Core_IsActive()) UpdateUIState(UISTATE_MENU); - Core_Run(graphicsContext); } shutdown: - _InterlockedExchange(&emuThreadReady, THREAD_SHUTDOWN); + emuThreadState = THREAD_SHUTDOWN; NativeShutdownGraphics(); // NativeShutdown deletes the graphics context through host->ShutdownGraphics(). NativeShutdown(); - - _InterlockedExchange(&emuThreadReady, THREAD_END); - - return 0; + emuThreadState = THREAD_END; } diff --git a/ext/native/thread/threadutil.h b/ext/native/thread/threadutil.h index 512c15d0bb..aa6d3ee2e1 100644 --- a/ext/native/thread/threadutil.h +++ b/ext/native/thread/threadutil.h @@ -15,8 +15,6 @@ public: cond_.notify_one(); } - // notify_all is not really possible to implement with win32 events? - void wait(std::mutex &mtx) { // broken logic std::unique_lock guard(mtx); From 1a5d1081f9a797efd915ea66304085ae421c83f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 19 Dec 2017 15:38:18 +0100 Subject: [PATCH 03/16] Get rid of the old custom "Event" sync primitive. --- Core/Core.cpp | 28 +++++++++++++++++----------- ext/native/thread/threadutil.h | 29 +---------------------------- 2 files changed, 18 insertions(+), 39 deletions(-) diff --git a/Core/Core.cpp b/Core/Core.cpp index 73696842f6..f45c630ae3 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -18,7 +18,9 @@ #include "ppsspp_config.h" #include +#include #include +#include #include "base/NativeApp.h" #include "base/display.h" @@ -46,9 +48,9 @@ // Should this be configurable? 2 hours currently. static const double ACTIVITY_IDLE_TIMEOUT = 2.0 * 3600.0; -static event m_hStepEvent; +static std::condition_variable m_StepCond; static std::mutex m_hStepMutex; -static event m_hInactiveEvent; +static std::condition_variable m_InactiveCond; static std::mutex m_hInactiveMutex; static bool singleStepPending = false; static std::set shutdownFuncs; @@ -95,7 +97,7 @@ void Core_Halt(const char *msg) { void Core_Stop() { Core_UpdateState(CORE_POWERDOWN); Core_NotifyShutdown(); - m_hStepEvent.notify_one(); + m_StepCond.notify_one(); } bool Core_IsStepping() { @@ -112,13 +114,15 @@ bool Core_IsInactive() { void Core_WaitInactive() { while (Core_IsActive()) { - m_hInactiveEvent.wait(m_hInactiveMutex); + std::unique_lock guard(m_hInactiveMutex); + m_InactiveCond.wait(guard); } } void Core_WaitInactive(int milliseconds) { if (Core_IsActive()) { - m_hInactiveEvent.wait_for(m_hInactiveMutex, milliseconds); + std::unique_lock guard(m_hInactiveMutex); + m_InactiveCond.wait_for(guard, std::chrono::milliseconds(milliseconds)); } } @@ -237,11 +241,11 @@ void Core_RunLoop(GraphicsContext *ctx) { void Core_DoSingleStep() { singleStepPending = true; - m_hStepEvent.notify_one(); + m_StepCond.notify_one(); } void Core_UpdateSingleStep() { - m_hStepEvent.notify_one(); + m_StepCond.notify_one(); } void Core_SingleStep() { @@ -251,7 +255,7 @@ void Core_SingleStep() { static inline void CoreStateProcessed() { if (coreStatePending) { coreStatePending = false; - m_hInactiveEvent.notify_one(); + m_InactiveCond.notify_one(); } } @@ -304,7 +308,10 @@ reswitch: host->SendCoreWait(true); #endif - m_hStepEvent.wait(m_hStepMutex); + { + std::unique_lock guard(m_hStepMutex); + m_StepCond.wait(guard); + } #if defined(USING_QT_UI) || defined(_DEBUG) host->SendCoreWait(false); @@ -349,7 +356,6 @@ void Core_EnableStepping(bool step) { #if defined(_DEBUG) host->SetDebugMode(true); #endif - m_hStepEvent.reset(); Core_UpdateState(CORE_STEPPING); } else { #if defined(_DEBUG) @@ -357,6 +363,6 @@ void Core_EnableStepping(bool step) { #endif coreState = CORE_RUNNING; coreStatePending = false; - m_hStepEvent.notify_one(); + m_StepCond.notify_one(); } } diff --git a/ext/native/thread/threadutil.h b/ext/native/thread/threadutil.h index aa6d3ee2e1..2723e2864f 100644 --- a/ext/native/thread/threadutil.h +++ b/ext/native/thread/threadutil.h @@ -1,33 +1,6 @@ #pragma once -#include -#include -#include - // Note that name must be a global string that lives until the end of the process, // for assertThreadName to work. void setCurrentThreadName(const char *threadName); -void AssertCurrentThreadName(const char *threadName); - -class event { -public: - void notify_one() { - cond_.notify_one(); - } - - void wait(std::mutex &mtx) { - // broken logic - std::unique_lock guard(mtx); - cond_.wait(guard); - } - - void wait_for(std::mutex &mtx, int milliseconds) { - std::unique_lock guard(mtx); - cond_.wait_for(guard, std::chrono::milliseconds(milliseconds)); - } - - void reset() { - } -private: - std::condition_variable cond_; -}; \ No newline at end of file +void AssertCurrentThreadName(const char *threadName); \ No newline at end of file From a1f029fe1f8e87aaa268bf0fe7a57aeb018dd7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 19 Dec 2017 15:42:18 +0100 Subject: [PATCH 04/16] Some ifdef cleanup. --- Core/Core.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/Core.cpp b/Core/Core.cpp index f45c630ae3..f63822f0ab 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -259,13 +259,13 @@ static inline void CoreStateProcessed() { } } -// Some platforms, like Android, do not call this function but handle things on their own. -void Core_Run(GraphicsContext *ctx) -{ +// Many platforms, like Android, do not call this function but handle things on their own. +// Instead they simply call PSP_RunLoopFor() directly, and forgo the debugging machinery. +void Core_Run(GraphicsContext *ctx) { #if defined(_DEBUG) host->UpdateDisassembly(); #endif -#if !defined(USING_QT_UI) || defined(MOBILE_DEVICE) +#if !defined(USING_QT_UI) while (true) #endif { @@ -276,7 +276,7 @@ reswitch: return; } Core_RunLoop(ctx); -#if defined(USING_QT_UI) && !defined(MOBILE_DEVICE) +#if defined(USING_QT_UI) return; #else continue; @@ -316,7 +316,7 @@ reswitch: #if defined(USING_QT_UI) || defined(_DEBUG) host->SendCoreWait(false); #endif -#if defined(USING_QT_UI) && !defined(MOBILE_DEVICE) +#if defined(USING_QT_UI) if (coreState != CORE_STEPPING) return; #endif From 5c1dad9909f5b5731a8e0fb74272cd6781eda912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 19 Dec 2017 17:59:00 +0100 Subject: [PATCH 05/16] Remove more obsolete ifdefs --- Core/Config.cpp | 7 ++--- Core/Core.cpp | 44 ++++++++----------------------- GPU/Common/TextureCacheCommon.cpp | 7 +---- GPU/GLES/GPU_GLES.cpp | 5 ---- GPU/GPUState.h | 1 - 5 files changed, 14 insertions(+), 50 deletions(-) diff --git a/Core/Config.cpp b/Core/Config.cpp index c844d1138b..7b62504554 100644 --- a/Core/Config.cpp +++ b/Core/Config.cpp @@ -525,12 +525,9 @@ static ConfigSetting graphicsSettings[] = { #endif ReportedConfigSetting("ForceMaxEmulatedFPS", &g_Config.iForceMaxEmulatedFPS, 60, true, true), - // TODO: Hm, on fast mobile GPUs we should definitely default to at least 4 (setting = 2)... -#ifdef MOBILE_DEVICE - ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 0, true, true), -#else + // Most low-performance (and many high performance) mobile GPUs do not support aniso anyway so defaulting to 4 is fine. ConfigSetting("AnisotropyLevel", &g_Config.iAnisotropyLevel, 4, true, true), -#endif + ReportedConfigSetting("VertexDecCache", &g_Config.bVertexCache, &DefaultVertexCache, true, true), ReportedConfigSetting("TextureBackoffCache", &g_Config.bTextureBackoffCache, false, true, true), ReportedConfigSetting("TextureSecondaryCache", &g_Config.bTextureSecondaryCache, false, true, true), diff --git a/Core/Core.cpp b/Core/Core.cpp index f63822f0ab..352df80c76 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -195,11 +195,16 @@ void UpdateRunLoop() { } } +void KeepScreenAwake() { +#ifdef _WIN32 + SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); +#endif +} + void Core_RunLoop(GraphicsContext *ctx) { graphicsContext = ctx; while ((GetUIState() != UISTATE_INGAME || !PSP_IsInited()) && GetUIState() != UISTATE_EXIT) { time_update(); -#if defined(USING_WIN_UI) double startTime = time_now_d(); UpdateRunLoop(); @@ -212,15 +217,11 @@ void Core_RunLoop(GraphicsContext *ctx) { if (!windowHidden) { ctx->SwapBuffers(); } -#else - UpdateRunLoop(); -#endif } while (!coreState && GetUIState() == UISTATE_INGAME) { time_update(); UpdateRunLoop(); -#if defined(USING_WIN_UI) if (!windowHidden && !Core_IsStepping()) { ctx->SwapBuffers(); @@ -230,12 +231,11 @@ void Core_RunLoop(GraphicsContext *ctx) { // Only resetting it ever prime number seconds in case the call is expensive. // Using a prime number to ensure there's no interaction with other periodic events. if (now - lastKeepAwake > 89.0 || now < lastKeepAwake) { - SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); + KeepScreenAwake(); lastKeepAwake = now; } } } -#endif } } @@ -260,15 +260,10 @@ static inline void CoreStateProcessed() { } // Many platforms, like Android, do not call this function but handle things on their own. -// Instead they simply call PSP_RunLoopFor() directly, and forgo the debugging machinery. +// Instead they simply call NativeRender and NativeUpdate directly. void Core_Run(GraphicsContext *ctx) { -#if defined(_DEBUG) host->UpdateDisassembly(); -#endif -#if !defined(USING_QT_UI) - while (true) -#endif - { + while (true) { reswitch: if (GetUIState() != UISTATE_INGAME) { CoreStateProcessed(); @@ -276,15 +271,10 @@ reswitch: return; } Core_RunLoop(ctx); -#if defined(USING_QT_UI) - return; -#else continue; -#endif } - switch (coreState) - { + switch (coreState) { case CORE_RUNNING: // enter a fast runloop Core_RunLoop(ctx); @@ -302,7 +292,7 @@ reswitch: } // wait for step command.. -#if defined(USING_QT_UI) || defined(_DEBUG) +#if defined(_DEBUG) host->UpdateDisassembly(); host->UpdateMemView(); host->SendCoreWait(true); @@ -313,13 +303,7 @@ reswitch: m_StepCond.wait(guard); } -#if defined(USING_QT_UI) || defined(_DEBUG) host->SendCoreWait(false); -#endif -#if defined(USING_QT_UI) - if (coreState != CORE_STEPPING) - return; -#endif // No step pending? Let's go back to the wait. if (!singleStepPending || coreState != CORE_STEPPING) { if (coreState == CORE_POWERDOWN) { @@ -330,10 +314,8 @@ reswitch: Core_SingleStep(); // update disasm dialog -#if defined(USING_QT_UI) || defined(_DEBUG) host->UpdateDisassembly(); host->UpdateMemView(); -#endif break; case CORE_POWERUP: @@ -353,14 +335,10 @@ reswitch: void Core_EnableStepping(bool step) { if (step) { sleep_ms(1); -#if defined(_DEBUG) host->SetDebugMode(true); -#endif Core_UpdateState(CORE_STEPPING); } else { -#if defined(_DEBUG) host->SetDebugMode(false); -#endif coreState = CORE_RUNNING; coreStatePending = false; m_StepCond.notify_one(); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 806aec4bfc..953d64c202 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -910,12 +910,7 @@ void TextureCacheCommon::NotifyConfigChanged() { } } - // Mobile devices don't get the higher scale factors, too expensive. Very rough way to decide though... - if (!gstate_c.Supports(GPU_IS_MOBILE)) { - scaleFactor = std::min(5, scaleFactor); - } else { - scaleFactor = std::min(3, scaleFactor); - } + scaleFactor = std::min(5, scaleFactor); } else { scaleFactor = g_Config.iTexScalingLevel; } diff --git a/GPU/GLES/GPU_GLES.cpp b/GPU/GLES/GPU_GLES.cpp index 8ba73cbd87..6fc70b7ef7 100644 --- a/GPU/GLES/GPU_GLES.cpp +++ b/GPU/GLES/GPU_GLES.cpp @@ -342,11 +342,6 @@ void GPU_GLES::CheckGPUFeatures() { features |= GPU_USE_CLEAR_RAM_HACK; } -#ifdef MOBILE_DEVICE - // Arguably, we should turn off GPU_IS_MOBILE on like modern Tegras, etc. - features |= GPU_IS_MOBILE; -#endif - gstate_c.featureFlags = features; } diff --git a/GPU/GPUState.h b/GPU/GPUState.h index 58fd4b127b..060fffb47d 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -490,7 +490,6 @@ enum { GPU_SUPPORTS_ARB_FRAMEBUFFER_BLIT = FLAG_BIT(26), GPU_SUPPORTS_NV_FRAMEBUFFER_BLIT = FLAG_BIT(27), GPU_SUPPORTS_OES_TEXTURE_NPOT = FLAG_BIT(28), - GPU_IS_MOBILE = FLAG_BIT(29), GPU_PREFER_CPU_DOWNLOAD = FLAG_BIT(30), GPU_PREFER_REVERSE_COLOR_ORDER = FLAG_BIT(31), }; From 740d0504ad4f4cd0efb0baa4b836c3b167dcee4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 19 Dec 2017 18:04:26 +0100 Subject: [PATCH 06/16] Move QtMain.cpp and PCMain.cpp to more sensible locations. Native isn't standalone anymore... --- CMakeLists.txt | 6 +++--- {ext/native/base => Qt}/QtMain.cpp | 0 {ext/native/base => Qt}/QtMain.h | 0 Qt/mainwindow.h | 2 +- ext/native/base/PCMain.cpp => SDL/SDLMain.cpp | 0 ext/native/base/NativeApp.h | 2 +- ext/native/native.vcxproj | 6 +++--- ext/native/native.vcxproj.filters | 6 +++--- 8 files changed, 11 insertions(+), 11 deletions(-) rename {ext/native/base => Qt}/QtMain.cpp (100%) rename {ext/native/base => Qt}/QtMain.h (100%) rename ext/native/base/PCMain.cpp => SDL/SDLMain.cpp (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 628831ba30..d885888ae6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -696,8 +696,8 @@ elseif(USING_QT_UI) qt5_wrap_ui(QT_UI_GEN ${Qt_UI}) list(APPEND NativeAppSource ${QT_UI_GEN} - ext/native/base/QtMain.cpp - ext/native/base/QtMain.h + Qt/QtMain.cpp + Qt/QtMain.h Qt/mainwindow.cpp Qt/mainwindow.h Qt/Debugger/ctrldisasmview.cpp @@ -742,7 +742,7 @@ elseif(TARGET SDL2::SDL2) set(nativeExtra ${nativeExtra} SDL/SDLJoystick.h SDL/SDLJoystick.cpp - ext/native/base/PCMain.cpp) + SDL/SDLMain.cpp) set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2) if(APPLE) set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm) diff --git a/ext/native/base/QtMain.cpp b/Qt/QtMain.cpp similarity index 100% rename from ext/native/base/QtMain.cpp rename to Qt/QtMain.cpp diff --git a/ext/native/base/QtMain.h b/Qt/QtMain.h similarity index 100% rename from ext/native/base/QtMain.h rename to Qt/QtMain.h diff --git a/Qt/mainwindow.h b/Qt/mainwindow.h index 51ffceb0de..c52120820e 100644 --- a/Qt/mainwindow.h +++ b/Qt/mainwindow.h @@ -14,7 +14,7 @@ #include "Debugger/debugger_memory.h" #include "Debugger/debugger_memorytex.h" #include "Debugger/debugger_displaylist.h" -#include "base/QtMain.h" +#include "Qt/QtMain.h" extern bool g_TakeScreenshot; diff --git a/ext/native/base/PCMain.cpp b/SDL/SDLMain.cpp similarity index 100% rename from ext/native/base/PCMain.cpp rename to SDL/SDLMain.cpp diff --git a/ext/native/base/NativeApp.h b/ext/native/base/NativeApp.h index 69bdf90b91..dd07afb996 100644 --- a/ext/native/base/NativeApp.h +++ b/ext/native/base/NativeApp.h @@ -111,7 +111,7 @@ void NativeSaveState(); // onDestroy void NativePermissionStatus(SystemPermission permission, PermissionStatus status); // Calls back into Java / SDL -// These APIs must be implemented by every port (for example app-android.cpp, PCMain.cpp). +// These APIs must be implemented by every port (for example app-android.cpp, SDLMain.cpp). // You are free to call these. void SystemToast(const char *text); void ShowKeyboard(); diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj index ba0d1d399a..b8db0d2f53 100644 --- a/ext/native/native.vcxproj +++ b/ext/native/native.vcxproj @@ -299,13 +299,13 @@ - + true true true true - + true true true @@ -761,4 +761,4 @@ - \ No newline at end of file + diff --git a/ext/native/native.vcxproj.filters b/ext/native/native.vcxproj.filters index 60c65f1746..175c41bf21 100644 --- a/ext/native/native.vcxproj.filters +++ b/ext/native/native.vcxproj.filters @@ -739,10 +739,10 @@ thread - + base - + base @@ -868,4 +868,4 @@ {06c6305a-a646-485b-85b9-645a24dd6553} - \ No newline at end of file + From 20080ba1236c8bff21b74d47235fd7a302af49fd Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Wed, 20 Dec 2017 03:38:01 +0000 Subject: [PATCH 07/16] CMakeLists: relocate EGL library name detection Raspberry Pi targets require a custom EGL library name (configured in cmake/Toolchains/raspberry.armv*.cmake). Move configuration of EGL_LIBRARIES for generic targets out of SDL2 target to ensure correct library name is used everywhere (including QT builds). Fixes build on Raspberry Pi. --- CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 628831ba30..7f998be6a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,7 +130,10 @@ if(NOT OPENGL_LIBRARIES AND USING_GLES2) endif() if(USING_EGL) - set(OPENGL_LIBRARIES ${OPENGL_LIBRARIES} EGL) + if(NOT EGL_LIBRARIES) + set(EGL_LIBRARIES EGL) + endif() + set(OPENGL_LIBRARIES ${OPENGL_LIBRARIES} ${EGL_LIBRARIES}) endif() if(NOT OPENGL_LIBRARIES) @@ -748,10 +751,7 @@ elseif(TARGET SDL2::SDL2) set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm) set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY}) elseif(USING_EGL) - if(NOT EGL_LIBRARIES) - set(EGL_LIBRARIES EGL) - endif() - set(nativeExtraLibs ${nativeExtraLibs} pthread ${EGL_LIBRARIES}) + set(nativeExtraLibs ${nativeExtraLibs} pthread) endif() set(TargetBin PPSSPPSDL) elseif(WIN32) From 4f1e0de9a92ae3747daafcb894fab27f8eb50ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 20 Dec 2017 10:22:15 +0100 Subject: [PATCH 08/16] Add missing includes. Remove some more unnecessary #ifdef _DEBUG checks - the debugger is supposed to work in release mode too. --- Core/Core.cpp | 4 +--- Core/HLE/sceSas.cpp | 1 + Core/Reporting.cpp | 2 ++ Core/System.cpp | 2 ++ UI/RemoteISOScreen.cpp | 2 ++ Windows/InputDevice.cpp | 1 + ext/native/thread/prioritizedworkqueue.h | 1 + 7 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Core/Core.cpp b/Core/Core.cpp index 352df80c76..c93cc683c6 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -213,7 +213,7 @@ void Core_RunLoop(GraphicsContext *ctx) { double diffTime = time_now_d() - startTime; int sleepTime = (int)(1000.0 / 60.0) - (int)(diffTime * 1000.0); if (sleepTime > 0) - Sleep(sleepTime); + sleep_ms(sleepTime); if (!windowHidden) { ctx->SwapBuffers(); } @@ -292,11 +292,9 @@ reswitch: } // wait for step command.. -#if defined(_DEBUG) host->UpdateDisassembly(); host->UpdateMemView(); host->SendCoreWait(true); -#endif { std::unique_lock guard(m_hStepMutex); diff --git a/Core/HLE/sceSas.cpp b/Core/HLE/sceSas.cpp index c6666beb55..73409c5eeb 100644 --- a/Core/HLE/sceSas.cpp +++ b/Core/HLE/sceSas.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "base/basictypes.h" #include "profiler/profiler.h" diff --git a/Core/Reporting.cpp b/Core/Reporting.cpp index 930cc8a180..7b9e40af03 100644 --- a/Core/Reporting.cpp +++ b/Core/Reporting.cpp @@ -16,6 +16,8 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include +#include #include "Core/Reporting.h" diff --git a/Core/System.cpp b/Core/System.cpp index aea38360ea..0c274f58f2 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -24,8 +24,10 @@ #include #include #endif + #include #include +#include #include "math/math_util.h" #include "thread/threadutil.h" diff --git a/UI/RemoteISOScreen.cpp b/UI/RemoteISOScreen.cpp index 638a93a0db..0ae4fec31c 100644 --- a/UI/RemoteISOScreen.cpp +++ b/UI/RemoteISOScreen.cpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include "base/timeutil.h" #include "ext/vjson/json.h" diff --git a/Windows/InputDevice.cpp b/Windows/InputDevice.cpp index 6cdfe36eff..252d7ee94c 100644 --- a/Windows/InputDevice.cpp +++ b/Windows/InputDevice.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "input/input_state.h" #include "thread/threadutil.h" diff --git a/ext/native/thread/prioritizedworkqueue.h b/ext/native/thread/prioritizedworkqueue.h index d7c9ad5f71..032e6a9694 100644 --- a/ext/native/thread/prioritizedworkqueue.h +++ b/ext/native/thread/prioritizedworkqueue.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "base/basictypes.h" #include "thread/threadutil.h" From b0528f3794e4826e02ca11b834853d30c82e8e3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 20 Dec 2017 16:40:09 +0100 Subject: [PATCH 09/16] Vulkan: Fix bug where we'd do the initial layout transition for an image before binding memory to it. Should help the issue uncovered in #10413 --- Common/Vulkan/VulkanImage.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/Common/Vulkan/VulkanImage.cpp b/Common/Vulkan/VulkanImage.cpp index e602de3a61..143ad16332 100644 --- a/Common/Vulkan/VulkanImage.cpp +++ b/Common/Vulkan/VulkanImage.cpp @@ -262,23 +262,6 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, return false; } - // Write a command to transition the image to the requested layout, if it's not already that layout. - if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) { - switch (initialLayout) { - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - TransitionImageLayout2(cmd, image, 0, numMips, VK_IMAGE_ASPECT_COLOR_BIT, - VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, - 0, VK_ACCESS_TRANSFER_WRITE_BIT); - break; - default: - // If you planned to use UploadMip, you want VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. After the - // upload, you can transition. - assert(false); - break; - } - } - vkGetImageMemoryRequirements(vulkan_->GetDevice(), image, &mem_reqs); if (allocator_) { @@ -311,6 +294,23 @@ bool VulkanTexture::CreateDirect(VkCommandBuffer cmd, int w, int h, int numMips, return false; } + // Write a command to transition the image to the requested layout, if it's not already that layout. + if (initialLayout != VK_IMAGE_LAYOUT_UNDEFINED && initialLayout != VK_IMAGE_LAYOUT_PREINITIALIZED) { + switch (initialLayout) { + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + TransitionImageLayout2(cmd, image, 0, numMips, VK_IMAGE_ASPECT_COLOR_BIT, + VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, VK_ACCESS_TRANSFER_WRITE_BIT); + break; + default: + // If you planned to use UploadMip, you want VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL. After the + // upload, you can transition. + assert(false); + break; + } + } + // Create the view while we're at it. VkImageViewCreateInfo view_info = { VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO }; view_info.image = image; From d67d201681f4346f1e05fd95406fa49be5ef106a Mon Sep 17 00:00:00 2001 From: Conn O'Griofa Date: Wed, 20 Dec 2017 07:13:18 +0000 Subject: [PATCH 10/16] SDL: really try lower GL profiles & add GLES context support * When compiled with USING_GLES2, attempt to use only valid ES context versions. * Ensure that lower profiles are attempted correctly rather than prematurely returning from the function after the first failure. Needed for Raspberry Pi to successfully launch. --- SDL/SDLMain.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 128e045d4c..660663037f 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -589,8 +589,12 @@ int main(int argc, char *argv[]) { int minor; }; GLVersionPair attemptVersions[] = { +#ifdef USING_GLES2 + {3, 2}, {3, 1}, {3, 0}, {2, 0}, +#else {4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2}, {3, 1}, {3, 0}, +#endif }; SDL_GLContext glContext = nullptr; @@ -598,17 +602,20 @@ int main(int argc, char *argv[]) { const auto &ver = attemptVersions[i]; // Make sure to request a somewhat modern GL context at least - the // latest supported by MacOS X (really, really sad...) - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, ver.major); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, ver.minor); +#ifdef USING_GLES2 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SetGLCoreContext(false); +#else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); SetGLCoreContext(true); +#endif g_Screen = SDL_CreateWindow(app_name_nice.c_str(), x,y, pixel_xres, pixel_yres, mode); if (g_Screen == nullptr) { - NativeShutdown(); fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); - SDL_Quit(); - return 2; + continue; } glContext = SDL_GL_CreateContext(g_Screen); From ea387b2a48a95be31a07f907fb3adf86c46f47a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 13 Dec 2017 22:58:45 +0100 Subject: [PATCH 11/16] WIP vulkan on linux stuff --- CMakeLists.txt | 24 ++- Common/Vulkan/VulkanContext.cpp | 34 +++++ Common/Vulkan/VulkanContext.h | 13 +- Common/Vulkan/VulkanLoader.cpp | 6 +- Common/Vulkan/VulkanLoader.h | 2 + SDL/SDLMain.cpp | 255 ++++++++++++++++++++++++-------- UI/GameSettingsScreen.cpp | 3 +- assets/lang | 2 +- ext/native/thin3d/DataFormat.h | 1 + 9 files changed, 266 insertions(+), 74 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b11630d109..cc7190270e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,12 +13,6 @@ list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules) add_definitions(-D__STDC_CONSTANT_MACROS) -# Of the CMake platforms, we only support Vulkan on Android and Windows. -if(ANDROID OR WIN32) - set(VULKAN ON) -else() - add_definitions(-DNO_VULKAN) -endif() if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang") set(CLANG ON) @@ -72,7 +66,14 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") endif() if(${CMAKE_SYSTEM_NAME} MATCHES "Android") - set(ANDROID ON) + set(ANDROID ON) +endif() + +# Of the CMake platforms, we only support Vulkan on Android and Windows. +if(ANDROID OR WIN32 OR LINUX) + set(VULKAN ON) +else() + add_definitions(-DNO_VULKAN) endif() if(NOT DEFINED HEADLESS) @@ -86,6 +87,11 @@ else() message("Normal Build") endif() +if(LINUX) + message("Using direct to display extension...") + add_definitions(-DVK_USE_PLATFORM_XLIB_KHR) +endif() + # Doesn't link on some platforms #if(NOT DEFINED UNITTEST) # set(UNITTEST OFF) @@ -113,6 +119,10 @@ option(SIMULATOR "Set to ON when targeting an x86 simulator of an ARM platform" option(USE_FFMPEG "Build with FFMPEG support" ${USE_FFMPEG}) option(USE_SYSTEM_FFMPEG "Dynamically link against system FFMPEG" ${USE_SYSTEM_FFMPEG}) +# Vulkan on Linux options. If none of these are set, X11 is assumed. +OPTION(USE_D2D_WSI "Build the project using Direct to Display swapchain" OFF) +OPTION(USE_WAYLAND_WSI "Build the project using Wayland swapchain" OFF) + if(ANDROID) set(CoreLibName ppsspp_jni) set(CoreLinkType SHARED) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 02d0282946..0c0b0471d2 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -109,6 +109,14 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { instance_extensions_enabled_.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #elif defined(__ANDROID__) instance_extensions_enabled_.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_XLIB_KHR) + instance_extensions_enabled_.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_XCB_KHR) + instance_extensions_enabled_.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_WAYLAND_KHR) + instance_extensions.enabled_.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); +#else + //... #endif if (flags_ & VULKAN_FLAG_VALIDATE) { @@ -631,6 +639,32 @@ void VulkanContext::ReinitSurface(int width, int height) { break; } #endif +#if defined(VK_USE_PLATFORM_XLIB_KHR) + case WINDOWSYSTEM_XLIB: + { + VkXlibSurfaceCreateInfoKHR xlib = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR }; + xlib.flags = 0; + xlib.dpy = (Display *)winsysData1_; + xlib.window = (Window)winsysData2_; + VkResult res = vkCreateXlibSurfaceKHR(instance_, &xlib, nullptr, &surface_); + assert(res == VK_SUCCESS); + break; + } + +#endif +#if defined(VK_USE_PLATFORM_XCB_KHR) + case WINDOWSYSTEM_XCB: + { + VkXCBSurfaceCreateInfoKHR xcb = { VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR }; + xcb.flags = 0; + xcb.connection = (Connection *)winsysData1_; + xcb.window = (Window)(uintptr_t)winsysData2_; + VkResult res = vkCreateXcbSurfaceKHR(instance_, &xcb, nullptr, &surface_); + assert(res == VK_SUCCESS); + break; + } +#endif + default: _assert_msg_(G3D, false, "Vulkan support for chosen window system not implemented"); break; diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 0fee12770a..0c60a3bef2 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -37,6 +37,12 @@ enum WindowSystem { #ifdef __ANDROID__ WINDOWSYSTEM_ANDROID, #endif +#ifdef VK_USE_PLATFORM_XLIB_KHR + WINDOWSYSTEM_XLIB, +#endif +#ifdef VK_USE_PLATFORM_XCB_KHR + WINDOWSYSTEM_XCB, +#endif }; struct VulkanPhysicalDeviceInfo { @@ -127,6 +133,7 @@ public: // 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,16 +245,16 @@ private: std::string init_error_; std::vector instance_layer_names_; std::vector instance_layer_properties_; - + std::vector instance_extensions_enabled_; std::vector instance_extension_properties_; std::vector device_layer_names_; std::vector device_layer_properties_; - + std::vector device_extensions_enabled_; std::vector device_extension_properties_; - + std::vector physical_devices_; int physical_device_ = -1; diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 7b8e83c91f..61d613966f 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -165,6 +165,8 @@ PFN_vkCmdExecuteCommands vkCmdExecuteCommands; PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; #elif defined(_WIN32) PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +#elif defined(VK_USE_PLATFORM_XLIB_KHR) +PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; #endif PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; @@ -374,7 +376,7 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { LOAD_INSTANCE_FUNC(instance, vkCmdNextSubpass); LOAD_INSTANCE_FUNC(instance, vkCmdEndRenderPass); LOAD_INSTANCE_FUNC(instance, vkCmdExecuteCommands); - + LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceSurfaceSupportKHR); LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceSurfaceCapabilitiesKHR); LOAD_INSTANCE_FUNC(instance, vkGetPhysicalDeviceSurfaceFormatsKHR); @@ -390,6 +392,8 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { LOAD_INSTANCE_FUNC(instance, vkCreateWin32SurfaceKHR); #elif defined(__ANDROID__) LOAD_INSTANCE_FUNC(instance, vkCreateAndroidSurfaceKHR); +#elif defined(VK_USE_PLATFORM_XLIB_KHR) + LOAD_INSTANCE_FUNC(instance, vkCreateXlibSurfaceKHR); #endif LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR); diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 67042c0c0c..18ab75555f 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -171,6 +171,8 @@ extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands; extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; #elif defined(_WIN32) extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +#elif defined(VK_USE_PLATFORM_XLIB_KHR) +extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; #endif extern PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 660663037f..2f9f4aefff 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -41,28 +41,156 @@ SDLJoystick *joystick = NULL; #include "base/NKCodeFromSDL.h" #include "util/const_map.h" #include "util/text/utf8.h" +#include "util/text/parsers.h" #include "math/math_util.h" +#include "Common/Vulkan/VulkanContext.h" +#include "Common/Vulkan/VulkanDebug.h" + +#if !defined(USING_FBDEV) +#include +#include +#include "SDL_syswm.h" +#endif #include "Core/System.h" #include "Core/Core.h" #include "Core/Config.h" #include "Common/GraphicsContext.h" -class GLDummyGraphicsContext : public DummyGraphicsContext { +class SDLGLGraphicsContext : public DummyGraphicsContext { public: - GLDummyGraphicsContext() { + SDLGLGraphicsContext() { CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); bool success = draw_->CreatePresets(); assert(success); } - ~GLDummyGraphicsContext() { delete draw_; } + ~SDLGLGraphicsContext() { + delete draw_; + } + + void Shutdown() override { + } + + Draw::DrawContext *GetDrawContext() override { + return draw_; + } + +private: + Draw::DrawContext *draw_ = nullptr; +}; + +static VulkanLogOptions g_LogOptions; + +class SDLVulkanGraphicsContext : public GraphicsContext { +public: + SDLVulkanGraphicsContext() {} + ~SDLVulkanGraphicsContext() { + delete draw_; + } + + bool Init(SDL_Window *sdl_window, std::string *error_message) { + SDL_SysWMinfo sys_info; + SDL_VERSION(&sys_info.version); //Set SDL version + SDL_GetWindowWMInfo(sdl_window, &sys_info); + + Display *display = sys_info.info.x11.display; + Window window = sys_info.info.x11.window; + + init_glslang(); + + g_LogOptions.breakOnError = true; + g_LogOptions.breakOnWarning = true; + g_LogOptions.msgBoxOnError = false; + + Version gitVer(PPSSPP_GIT_VERSION); + + vulkan_ = new VulkanContext(); + if (vulkan_->InitError().size()) { + *error_message = vulkan_->InitError(); + delete vulkan_; + vulkan_ = nullptr; + return false; + } + + int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX; + // vulkanFlags |= VULKAN_FLAG_VALIDATE; + VulkanContext::CreateInfo info{}; + info.app_name = "PPSSPP"; + info.app_ver = gitVer.ToInteger(); + info.flags = VULKAN_FLAG_PRESENT_MAILBOX; + if (VK_SUCCESS != vulkan_->CreateInstance(info)) { + *error_message = vulkan_->InitError(); + delete vulkan_; + vulkan_ = nullptr; + return false; + } + vulkan_->ChooseDevice(vulkan_->GetBestPhysicalDevice()); + if (vulkan_->CreateDevice() != VK_SUCCESS) { + *error_message = vulkan_->InitError(); + delete vulkan_; + vulkan_ = nullptr; + return false; + } + + vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void *)display, (void *)(intptr_t)window, pixel_xres, pixel_yres); + + if (!vulkan_->InitObjects()) { + *error_message = vulkan_->InitError(); + Shutdown(); + return false; + } + + draw_ = Draw::T3DCreateVulkanContext(vulkan_, false); + bool success = draw_->CreatePresets(); + assert(success); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + + return true; + } + + void Shutdown() override { + if (draw_) + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + delete draw_; + draw_ = nullptr; + vulkan_->WaitUntilQueueIdle(); + vulkan_->DestroyObjects(); + vulkan_->DestroyDevice(); + vulkan_->DestroyDebugMsgCallback(); + vulkan_->DestroyInstance(); + delete vulkan_; + vulkan_ = nullptr; + finalize_glslang(); + } + + void SwapBuffers() override { + // We don't do it this way. + } + + void Resize() override { + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + vulkan_->DestroyObjects(); + // TODO: Take from real window dimensions + int width = 1024; + int height = 768; + vulkan_->ReinitSurface(width, height); + vulkan_->InitObjects(); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + } + + void SwapInterval(int interval) override { + } + void *GetAPIContext() override { + return vulkan_; + } Draw::DrawContext *GetDrawContext() override { return draw_; } private: - Draw::DrawContext *draw_; + Draw::DrawContext *draw_ = nullptr; + VulkanContext *vulkan_ = nullptr; }; GlobalUIState lastUIState = UISTATE_MENU; @@ -79,11 +207,6 @@ static int g_DesktopHeight = 0; #if defined(USING_EGL) #include "EGL/egl.h" -#if !defined(USING_FBDEV) -#include -#include -#endif - #include "SDL_syswm.h" #include "math.h" @@ -419,12 +542,54 @@ void ToggleFullScreenIfFlagSet() { #undef main #endif int main(int argc, char *argv[]) { + glslang::InitializeProcess(); + #if PPSSPP_PLATFORM(RPI) bcm_host_init(); #endif putenv((char*)"SDL_VIDEO_CENTERED=1"); SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); + int set_xres = -1; + int set_yres = -1; + bool portrait = false; + bool set_ipad = false; + float set_dpi = 1.0f; + float set_scale = 1.0f; + + // Produce a new set of arguments with the ones we skip. + int remain_argc = 1; + const char *remain_argv[256] = { argv[0] }; + + Uint32 mode = 0; + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i],"--fullscreen")) + mode |= SDL_WINDOW_FULLSCREEN_DESKTOP; + else if (set_xres == -2) + set_xres = parseInt(argv[i]); + else if (set_yres == -2) + set_yres = parseInt(argv[i]); + else if (set_dpi == -2) + set_dpi = parseFloat(argv[i]); + else if (set_scale == -2) + set_scale = parseFloat(argv[i]); + else if (!strcmp(argv[i],"--xres")) + set_xres = -2; + else if (!strcmp(argv[i],"--yres")) + set_yres = -2; + else if (!strcmp(argv[i],"--dpi")) + set_dpi = -2; + else if (!strcmp(argv[i],"--scale")) + set_scale = -2; + else if (!strcmp(argv[i],"--ipad")) + set_ipad = true; + else if (!strcmp(argv[i],"--portrait")) + portrait = true; + else { + remain_argv[remain_argc++] = argv[i]; + } + } + std::string app_name; std::string app_name_nice; std::string version; @@ -464,50 +629,11 @@ int main(int argc, char *argv[]) { SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetSwapInterval(1); - Uint32 mode; #ifdef USING_GLES2 - mode = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN; + mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN; #else - mode = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; #endif - int set_xres = -1; - int set_yres = -1; - bool portrait = false; - bool set_ipad = false; - float set_dpi = 1.0f; - float set_scale = 1.0f; - - // Produce a new set of arguments with the ones we skip. - int remain_argc = 1; - const char *remain_argv[256] = { argv[0] }; - - for (int i = 1; i < argc; i++) { - if (!strcmp(argv[i],"--fullscreen")) - mode |= SDL_WINDOW_FULLSCREEN_DESKTOP; - else if (set_xres == -2) - set_xres = parseInt(argv[i]); - else if (set_yres == -2) - set_yres = parseInt(argv[i]); - else if (set_dpi == -2) - set_dpi = parseFloat(argv[i]); - else if (set_scale == -2) - set_scale = parseFloat(argv[i]); - else if (!strcmp(argv[i],"--xres")) - set_xres = -2; - else if (!strcmp(argv[i],"--yres")) - set_yres = -2; - else if (!strcmp(argv[i],"--dpi")) - set_dpi = -2; - else if (!strcmp(argv[i],"--scale")) - set_scale = -2; - else if (!strcmp(argv[i],"--ipad")) - set_ipad = true; - else if (!strcmp(argv[i],"--portrait")) - portrait = true; - else { - remain_argv[remain_argc++] = argv[i]; - } - } // Is resolution is too low to run windowed if (g_DesktopWidth < 480 * 2 && g_DesktopHeight < 272 * 2) { @@ -695,9 +821,21 @@ int main(int argc, char *argv[]) { printf("Pixels: %i x %i\n", pixel_xres, pixel_yres); printf("Virtual pixels: %i x %i\n", dp_xres, dp_yres); - glslang::InitializeProcess(); - - GraphicsContext *graphicsContext = new GLDummyGraphicsContext(); + GraphicsContext *graphicsContext; + if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) { + graphicsContext = new SDLGLGraphicsContext(); + } else if (g_Config.iGPUBackend == GPU_BACKEND_VULKAN) { + SDLVulkanGraphicsContext *ctx = new SDLVulkanGraphicsContext(); + std::string error_message; + if (!ctx->Init(g_Screen, &error_message)) { + printf("Vulkan init error '%s' - falling back to GL\n", error_message.c_str()); + g_Config.iGPUBackend = GPU_BACKEND_OPENGL; + delete ctx; + graphicsContext = new SDLGLGraphicsContext(); + } else { + graphicsContext = ctx; + } + } NativeInitGraphics(graphicsContext); NativeResized(); @@ -946,26 +1084,21 @@ int main(int argc, char *argv[]) { delete joystick; #endif NativeShutdownGraphics(); + SDL_GL_DeleteContext(glContext); graphicsContext->Shutdown(); NativeShutdown(); delete graphicsContext; - glslang::FinalizeProcess(); - // Faster exit, thanks to the OS. Remove this if you want to debug shutdown - // The speed difference is only really noticable on Linux. On Windows you do notice it though -#ifndef MOBILE_DEVICE - exit(0); -#endif + SDL_PauseAudio(1); SDL_CloseAudio(); #ifdef USING_EGL EGL_Close(); #endif - SDL_GL_DeleteContext(glContext); SDL_Quit(); #if PPSSPP_PLATFORM(RPI) bcm_host_deinit(); #endif - exit(0); + glslang::FinalizeProcess(); return 0; } diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index 9a8dea5b6a..c3dfcd193d 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -48,7 +48,6 @@ #include "Common/KeyMap.h" #include "Common/FileUtil.h" #include "Common/OSVersion.h" -#include "Common/Vulkan/VulkanLoader.h" #include "Core/Config.h" #include "Core/Host.h" #include "Core/System.h" @@ -73,6 +72,8 @@ extern bool iosCanUseJit; extern bool targetIsJailbroken; #endif +extern bool VulkanMayBeAvailable(); + GameSettingsScreen::GameSettingsScreen(std::string gamePath, std::string gameID, bool editThenRestore) : UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), enableReports_(false), editThenRestore_(editThenRestore) { lastVertical_ = UseVerticalLayout(); diff --git a/assets/lang b/assets/lang index 6537fc1bf3..1e3e4a0ba0 160000 --- a/assets/lang +++ b/assets/lang @@ -1 +1 @@ -Subproject commit 6537fc1bf38d0787a1d86375e5b3cb267349d2d5 +Subproject commit 1e3e4a0ba0ca8c0a092e027dfb7c1c4778366db5 diff --git a/ext/native/thin3d/DataFormat.h b/ext/native/thin3d/DataFormat.h index 22cd4d3c07..467f9e4a00 100644 --- a/ext/native/thin3d/DataFormat.h +++ b/ext/native/thin3d/DataFormat.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace Draw { From 6d6ad3ed146b2f65dd0ce0144e82fa3b8e2fd97e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 13 Dec 2017 23:22:21 +0100 Subject: [PATCH 12/16] Cleanups in PCMain.cpp --- SDL/SDLMain.cpp | 94 +++++++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 62 deletions(-) diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 2f9f4aefff..d75581368c 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -3,24 +3,12 @@ // Note: SDL1.2 implementation is deprecated and will soon be replaced by SDL2.0. // If your platform is not supported, it is suggested to use Qt instead. -#ifdef _WIN32 -#pragma warning(disable:4091) // workaround bug in VS2015 headers - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include -#include -#else #include #include -#endif #include "SDL.h" -#ifndef _WIN32 #include "SDL/SDLJoystick.h" SDLJoystick *joystick = NULL; -#endif #if PPSSPP_PLATFORM(RPI) #include @@ -28,6 +16,7 @@ SDLJoystick *joystick = NULL; #include #include +#include #include "base/display.h" #include "base/logging.h" @@ -45,8 +34,9 @@ SDLJoystick *joystick = NULL; #include "math/math_util.h" #include "Common/Vulkan/VulkanContext.h" #include "Common/Vulkan/VulkanDebug.h" +#include "math.h" -#if !defined(USING_FBDEV) +#if defined(VK_USE_PLATFORM_XLIB_KHR) #include #include #include "SDL_syswm.h" @@ -59,7 +49,7 @@ SDLJoystick *joystick = NULL; class SDLGLGraphicsContext : public DummyGraphicsContext { public: - SDLGLGraphicsContext() { + SDLGLGraphicsContext(SDL_Window *window) : window_(window) { CheckGLExtensions(); draw_ = Draw::T3DCreateGLContext(); bool success = draw_->CreatePresets(); @@ -72,12 +62,21 @@ public: void Shutdown() override { } + void SwapBuffers() override { +#ifdef USING_EGL + eglSwapBuffers(g_eglDisplay, g_eglSurface); +#else + SDL_GL_SwapWindow(window_); +#endif + } + Draw::DrawContext *GetDrawContext() override { return draw_; } private: Draw::DrawContext *draw_ = nullptr; + SDL_Window *window_; }; static VulkanLogOptions g_LogOptions; @@ -196,7 +195,6 @@ private: GlobalUIState lastUIState = UISTATE_MENU; GlobalUIState GetUIState(); -static SDL_Window* g_Screen = NULL; static bool g_ToggleFullScreenNextFrame = false; static int g_ToggleFullScreenType; static int g_QuitRequested = 0; @@ -207,9 +205,6 @@ static int g_DesktopHeight = 0; #if defined(USING_EGL) #include "EGL/egl.h" -#include "SDL_syswm.h" -#include "math.h" - static EGLDisplay g_eglDisplay = NULL; static EGLContext g_eglContext = NULL; static EGLSurface g_eglSurface = NULL; @@ -522,11 +517,11 @@ static float parseFloat(const char *str) { } } -void ToggleFullScreenIfFlagSet() { +void ToggleFullScreenIfFlagSet(SDL_Window *window) { if (g_ToggleFullScreenNextFrame) { g_ToggleFullScreenNextFrame = false; - Uint32 window_flags = SDL_GetWindowFlags(g_Screen); + Uint32 window_flags = SDL_GetWindowFlags(window); if (g_ToggleFullScreenType == -1) { window_flags ^= SDL_WINDOW_FULLSCREEN_DESKTOP; } else if (g_ToggleFullScreenType == 1) { @@ -534,7 +529,7 @@ void ToggleFullScreenIfFlagSet() { } else { window_flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP; } - SDL_SetWindowFullscreen(g_Screen, window_flags); + SDL_SetWindowFullscreen(window, window_flags); } } @@ -678,12 +673,6 @@ int main(int argc, char *argv[]) { dp_xres = (float)pixel_xres * dpi_scale; dp_yres = (float)pixel_yres * dpi_scale; -#ifdef _MSC_VER - // VFSRegister("temp/", new DirectoryAssetReader("E:\\Temp\\")); - TCHAR path[MAX_PATH]; - SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, path); - PathAppend(path, (app_name + "\\").c_str()); -#else // Mac / Linux char path[2048]; const char *the_path = getenv("HOME"); @@ -695,13 +684,8 @@ int main(int argc, char *argv[]) { strcpy(path, the_path); if (path[strlen(path)-1] != '/') strcat(path, "/"); -#endif -#ifdef _WIN32 - NativeInit(remain_argc, (const char **)remain_argv, path, "D:\\", nullptr); -#else NativeInit(remain_argc, (const char **)remain_argv, path, "/tmp", nullptr); -#endif // Use the setting from the config when initing the window. if (g_Config.bFullScreen) @@ -723,6 +707,7 @@ int main(int argc, char *argv[]) { #endif }; + SDL_Window *window = nullptr; SDL_GLContext glContext = nullptr; for (size_t i = 0; i < ARRAY_SIZE(attemptVersions); ++i) { const auto &ver = attemptVersions[i]; @@ -738,13 +723,14 @@ int main(int argc, char *argv[]) { SetGLCoreContext(true); #endif - g_Screen = SDL_CreateWindow(app_name_nice.c_str(), x,y, pixel_xres, pixel_yres, mode); - if (g_Screen == nullptr) { + window = SDL_CreateWindow(app_name_nice.c_str(), x,y, pixel_xres, pixel_yres, mode); + if (!window) { + NativeShutdown(); fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); continue; } - glContext = SDL_GL_CreateContext(g_Screen); + glContext = SDL_GL_CreateContext(window); if (glContext != nullptr) { // Victory, got one. break; @@ -752,7 +738,7 @@ int main(int argc, char *argv[]) { // Let's keep trying. To be safe, destroy the window - docs say needed to change profile. // in practice, it doesn't seem to matter, but maybe it differs by platform. - SDL_DestroyWindow(g_Screen); + SDL_DestroyWindow(window); } if (glContext == nullptr) { @@ -761,15 +747,15 @@ int main(int argc, char *argv[]) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); SetGLCoreContext(false); - g_Screen = SDL_CreateWindow(app_name_nice.c_str(), x,y, pixel_xres, pixel_yres, mode); - if (g_Screen == nullptr) { + window = SDL_CreateWindow(app_name_nice.c_str(), x,y, pixel_xres, pixel_yres, mode); + if (window == nullptr) { NativeShutdown(); fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); SDL_Quit(); return 2; } - glContext = SDL_GL_CreateContext(g_Screen); + glContext = SDL_GL_CreateContext(window); if (glContext == nullptr) { NativeShutdown(); fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError()); @@ -782,7 +768,7 @@ int main(int argc, char *argv[]) { EGL_Init(); #endif - SDL_SetWindowTitle(g_Screen, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str()); + SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str()); #ifdef MOBILE_DEVICE SDL_ShowCursor(SDL_DISABLE); @@ -823,15 +809,15 @@ int main(int argc, char *argv[]) { GraphicsContext *graphicsContext; if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) { - graphicsContext = new SDLGLGraphicsContext(); + graphicsContext = new SDLGLGraphicsContext(window); } else if (g_Config.iGPUBackend == GPU_BACKEND_VULKAN) { SDLVulkanGraphicsContext *ctx = new SDLVulkanGraphicsContext(); std::string error_message; - if (!ctx->Init(g_Screen, &error_message)) { + if (!ctx->Init(window, &error_message)) { printf("Vulkan init error '%s' - falling back to GL\n", error_message.c_str()); g_Config.iGPUBackend = GPU_BACKEND_OPENGL; delete ctx; - graphicsContext = new SDLGLGraphicsContext(); + graphicsContext = new SDLGLGraphicsContext(window); } else { graphicsContext = ctx; } @@ -866,18 +852,14 @@ int main(int argc, char *argv[]) { // Audio must be unpaused _after_ NativeInit() SDL_PauseAudio(0); -#ifndef _WIN32 if (joystick_enabled) { joystick = new SDLJoystick(); } else { joystick = nullptr; } -#endif EnableFZ(); int framecount = 0; - float t = 0; - float lastT = 0; bool mouseDown = false; while (true) { @@ -896,7 +878,7 @@ int main(int argc, char *argv[]) { switch (event.window.event) { case SDL_WINDOWEVENT_RESIZED: { - Uint32 window_flags = SDL_GetWindowFlags(g_Screen); + Uint32 window_flags = SDL_GetWindowFlags(window); bool fullscreen = (window_flags & SDL_WINDOW_FULLSCREEN); pixel_xres = event.window.data1; @@ -1038,11 +1020,9 @@ int main(int argc, char *argv[]) { } break; default: -#ifndef _WIN32 if (joystick) { joystick->ProcessInput(event); } -#endif break; } } @@ -1066,23 +1046,13 @@ int main(int argc, char *argv[]) { // glsl_refresh(); // auto-reloads modified GLSL shaders once per second. } -#ifdef USING_EGL - eglSwapBuffers(g_eglDisplay, g_eglSurface); -#else - if (!keys[SDLK_TAB] || t - lastT >= 1.0/60.0) { - SDL_GL_SwapWindow(g_Screen); - lastT = t; - } -#endif + graphicsContext->SwapBuffers(); - ToggleFullScreenIfFlagSet(); + ToggleFullScreenIfFlagSet(window); time_update(); - t = time_now(); framecount++; } -#ifndef _WIN32 delete joystick; -#endif NativeShutdownGraphics(); SDL_GL_DeleteContext(glContext); graphicsContext->Shutdown(); From 7f758d52dcd8d2cc322755ce114e682d04d07c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 15 Dec 2017 15:29:19 +0100 Subject: [PATCH 13/16] Statically link a vulkan loader on Linux. Use to to init vulkan on X11. Unfortunately, it's broken. --- CMakeLists.txt | 21 +- Common/Vulkan/VulkanContext.cpp | 23 +- Common/Vulkan/VulkanLoader.cpp | 49 +- Common/Vulkan/VulkanLoader.h | 14 +- GPU/Vulkan/VertexShaderGeneratorVulkan.cpp | 14 +- SDL/SDLMain.cpp | 555 +++++++++++---------- UI/GameSettingsScreen.cpp | 2 +- 7 files changed, 381 insertions(+), 297 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc7190270e..cb071f54ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,6 +76,25 @@ else() add_definitions(-DNO_VULKAN) endif() +if(NOT ANDROID) + # Use FindVulkan module added with CMAKE 3.7 + if (NOT CMAKE_VERSION VERSION_LESS 3.7.0) + message(STATUS "Using module to find Vulkan") + find_package(Vulkan) + endif() +endif() + +if(NOT WIN32 AND VULKAN) + IF (NOT Vulkan_FOUND) + find_library(Vulkan_LIBRARY NAMES vulkan HINTS "$ENV{VULKAN_SDK}/lib" "${CMAKE_SOURCE_DIR}/ext/vulkan" REQUIRED) + IF (Vulkan_LIBRARY) + set(Vulkan_FOUND ON) + MESSAGE("Using bundled Vulkan library version") + add_definitions(-DVULKAN_STATIC) + ENDIF() + ENDIF() +endif() + if(NOT DEFINED HEADLESS) set(HEADLESS OFF) endif() @@ -1653,7 +1672,7 @@ set(CoreExtraLibs ${CoreExtraLibs} armips) set(GlslangLibs glslang OGLCompiler OSDependent SPIRV SPVRemapper spirv-cross-glsl) target_link_libraries(${CoreLibName} Common native kirk cityhash sfmt19937 xbrz xxhash ${GlslangLibs} - ${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS}) + ${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS} ${Vulkan_LIBRARY}) if(FFmpeg_FOUND) target_compile_definitions(${CoreLibName} PRIVATE USE_FFMPEG=1) diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 0c0b0471d2..c0f7f5f6ba 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -113,6 +113,8 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { instance_extensions_enabled_.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); #elif defined(VK_USE_PLATFORM_XCB_KHR) instance_extensions_enabled_.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); +#elif defined(VK_USE_PLATFORM_MIR_KHR) + instance_extensions_enabled_.push_back(VK_KHR_MIR_SURFACE_EXTENSION_NAME); #elif defined(VK_USE_PLATFORM_WAYLAND_KHR) instance_extensions.enabled_.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); #else @@ -432,6 +434,7 @@ int VulkanContext::GetBestPhysicalDevice() { void VulkanContext::ChooseDevice(int physical_device) { physical_device_ = physical_device; + ILOG("Chose physical device %d: %p", physical_device, physical_devices_[physical_device]); GetDeviceLayerProperties(); if (!CheckLayers(device_layer_properties_, device_layer_names_)) { @@ -553,6 +556,7 @@ VkResult VulkanContext::CreateDevice() { } else { VulkanLoadDeviceFunctions(device_); } + ILOG("Device created.\n"); return res; } @@ -571,7 +575,7 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun cb.flags = bits; cb.pfnCallback = dbgFunc; cb.pUserData = userdata; - VkResult res = vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback); + VkResult res = dyn_vkCreateDebugReportCallbackEXT(instance_, &cb, nullptr, &msg_callback); switch (res) { case VK_SUCCESS: msg_callbacks.push_back(msg_callback); @@ -586,7 +590,7 @@ VkResult VulkanContext::InitDebugMsgCallback(PFN_vkDebugReportCallbackEXT dbgFun void VulkanContext::DestroyDebugMsgCallback() { while (msg_callbacks.size() > 0) { - vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr); + dyn_vkDestroyDebugReportCallbackEXT(instance_, msg_callbacks.back(), nullptr); msg_callbacks.pop_back(); } } @@ -650,7 +654,6 @@ void VulkanContext::ReinitSurface(int width, int height) { assert(res == VK_SUCCESS); break; } - #endif #if defined(VK_USE_PLATFORM_XCB_KHR) case WINDOWSYSTEM_XCB: @@ -718,16 +721,17 @@ bool VulkanContext::InitQueue() { graphics_queue_family_index_ = graphicsQueueNodeIndex; // Get the list of VkFormats that are supported: - uint32_t formatCount; + uint32_t formatCount = 0; VkResult res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, nullptr); - assert(res == VK_SUCCESS); - if (res != VK_SUCCESS) + _assert_msg_(G3D, res == VK_SUCCESS, "Failed to get formats for device %p: %d surface: %p", physical_devices_[physical_device_], (int)res, surface_); + if (res != VK_SUCCESS) { return false; - VkSurfaceFormatKHR *surfFormats = new VkSurfaceFormatKHR[formatCount]; - res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, surfFormats); + } + + std::vector surfFormats(formatCount); + res = vkGetPhysicalDeviceSurfaceFormatsKHR(physical_devices_[physical_device_], surface_, &formatCount, surfFormats.data()); assert(res == VK_SUCCESS); if (res != VK_SUCCESS) { - delete[] surfFormats; return false; } // If the format list includes just one entry of VK_FORMAT_UNDEFINED, @@ -754,7 +758,6 @@ bool VulkanContext::InitQueue() { } ILOG("swapchain_format: %d (/%d)", swapchainFormat_, formatCount); } - delete[] surfFormats; vkGetDeviceQueue(device_, graphics_queue_family_index_, 0, &gfx_queue_); ILOG("gfx_queue_: %p", gfx_queue_); diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 61d613966f..e40c3ec6bf 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -17,11 +17,13 @@ #include "Common/Vulkan/VulkanLoader.h" #include "base/logging.h" +#include "base/basictypes.h" #ifndef _WIN32 #include #endif +#ifndef VULKAN_STATIC PFN_vkCreateInstance vkCreateInstance; PFN_vkDestroyInstance vkDestroyInstance; @@ -181,10 +183,12 @@ PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; PFN_vkQueuePresentKHR vkQueuePresentKHR; +#endif + +// And the DEBUG_REPORT extension. We dynamically load this. +PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; +PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; -// And the DEBUG_REPORT extension. -PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; -PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; #ifdef _WIN32 static HINSTANCE vulkanLibrary; @@ -197,15 +201,26 @@ static void *vulkanLibrary; #define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {ILOG("Missing (device): %s", #x);} #define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {ILOG("Missing (global): %s", #x);} +static const char *so_names[] = { + "libvulkan.so", + "libvulkan.so.1", +}; + bool VulkanMayBeAvailable() { +#ifdef VULKAN_STATIC + return true; +#else if (vulkanLibrary) return true; bool available = false; #ifndef _WIN32 - void *lib = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); - available = lib != nullptr; - if (lib) { - dlclose(lib); + for (int i = 0; i < ARRAY_SIZE(so_names); i++) { + void *lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL); + if (lib) { + available = true; + dlclose(lib); + break; + } } #else // LoadLibrary etc @@ -216,12 +231,18 @@ bool VulkanMayBeAvailable() { } #endif return available; +#endif } bool VulkanLoad() { +#ifndef VULKAN_STATIC if (!vulkanLibrary) { #ifndef _WIN32 - vulkanLibrary = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); + for (int i = 0; i < ARRAY_SIZE(so_names); i++) { + vulkanLibrary = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL); + if (vulkanLibrary) + break; + } #else // LoadLibrary etc vulkanLibrary = LoadLibrary(L"vulkan-1.dll"); @@ -239,10 +260,12 @@ bool VulkanLoad() { LOAD_GLOBAL_FUNC(vkEnumerateInstanceLayerProperties); WLOG("Vulkan base functions loaded."); +#endif return true; } void VulkanLoadInstanceFunctions(VkInstance instance) { +#ifndef VULKAN_STATIC // OK, let's use the above functions to get the rest. LOAD_INSTANCE_FUNC(instance, vkDestroyInstance); LOAD_INSTANCE_FUNC(instance, vkEnumeratePhysicalDevices); @@ -397,9 +420,11 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { #endif LOAD_INSTANCE_FUNC(instance, vkDestroySurfaceKHR); +#endif + + dyn_vkCreateDebugReportCallbackEXT = (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); + dyn_vkDestroyDebugReportCallbackEXT = (PFN_vkDestroyDebugReportCallbackEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); - LOAD_INSTANCE_FUNC(instance, vkCreateDebugReportCallbackEXT); - LOAD_INSTANCE_FUNC(instance, vkDestroyDebugReportCallbackEXT); WLOG("Vulkan instance functions loaded."); } @@ -408,15 +433,18 @@ void VulkanLoadInstanceFunctions(VkInstance instance) { // good for multi-device. void VulkanLoadDeviceFunctions(VkDevice device) { WLOG("Vulkan device functions loaded."); +#ifndef VULKAN_STATIC // TODO: Move more functions VulkanLoadInstanceFunctions to here. LOAD_DEVICE_FUNC(device, vkCreateSwapchainKHR); LOAD_DEVICE_FUNC(device, vkDestroySwapchainKHR); LOAD_DEVICE_FUNC(device, vkGetSwapchainImagesKHR); LOAD_DEVICE_FUNC(device, vkAcquireNextImageKHR); LOAD_DEVICE_FUNC(device, vkQueuePresentKHR); +#endif } void VulkanFree() { +#ifndef VULKAN_STATIC if (vulkanLibrary) { #ifdef _WIN32 FreeLibrary(vulkanLibrary); @@ -425,4 +453,5 @@ void VulkanFree() { #endif vulkanLibrary = nullptr; } +#endif } diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 18ab75555f..16fbe1fd2e 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -25,10 +25,13 @@ #define NOMINMAX #endif +#ifndef VULKAN_STATIC #define VK_NO_PROTOTYPES +#endif #include "ext/vulkan/vulkan.h" +#ifndef VULKAN_STATIC extern PFN_vkCreateInstance vkCreateInstance; extern PFN_vkDestroyInstance vkDestroyInstance; extern PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; @@ -189,9 +192,13 @@ extern PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; extern PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; extern PFN_vkQueuePresentKHR vkQueuePresentKHR; -// And the DEBUG_REPORT extension. -extern PFN_vkCreateDebugReportCallbackEXT vkCreateDebugReportCallbackEXT; -extern PFN_vkDestroyDebugReportCallbackEXT vkDestroyDebugReportCallbackEXT; +#endif + +// And the DEBUG_REPORT extension. Since we load this dynamically even in static +// linked mode, we have to rename it :( +extern PFN_vkCreateDebugReportCallbackEXT dyn_vkCreateDebugReportCallbackEXT; +extern PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT; + // Way to do a quick check before even attempting to load. bool VulkanMayBeAvailable(); @@ -200,4 +207,3 @@ bool VulkanLoad(); void VulkanLoadInstanceFunctions(VkInstance instance); void VulkanLoadDeviceFunctions(VkDevice device); void VulkanFree(); - diff --git a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp index 7f94806fcd..8aa8b1719f 100644 --- a/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp +++ b/GPU/Vulkan/VertexShaderGeneratorVulkan.cpp @@ -169,27 +169,27 @@ bool GenerateVulkanGLSLVertexShader(const VShaderID &id, char *buffer, bool *use } if (useHWTransform) - WRITE(p, "layout (location = %d) in vec3 position;\n", PspAttributeLocation::POSITION); + WRITE(p, "layout (location = %d) in vec3 position;\n", (int)PspAttributeLocation::POSITION); else // we pass the fog coord in w - WRITE(p, "layout (location = %d) in vec4 position;\n", PspAttributeLocation::POSITION); + WRITE(p, "layout (location = %d) in vec4 position;\n", (int)PspAttributeLocation::POSITION); if (useHWTransform && hasNormal) - WRITE(p, "layout (location = %d) in vec3 normal;\n", PspAttributeLocation::NORMAL); + WRITE(p, "layout (location = %d) in vec3 normal;\n", (int)PspAttributeLocation::NORMAL); bool texcoordInVec3 = false; if (doTexture && hasTexcoord) { if (!useHWTransform && doTextureTransform && !throughmode) { - WRITE(p, "layout (location = %d) in vec3 texcoord;\n", PspAttributeLocation::TEXCOORD); + WRITE(p, "layout (location = %d) in vec3 texcoord;\n", (int)PspAttributeLocation::TEXCOORD); texcoordInVec3 = true; } else - WRITE(p, "layout (location = %d) in vec2 texcoord;\n", PspAttributeLocation::TEXCOORD); + WRITE(p, "layout (location = %d) in vec2 texcoord;\n", (int)PspAttributeLocation::TEXCOORD); } if (hasColor) { - WRITE(p, "layout (location = %d) in vec4 color0;\n", PspAttributeLocation::COLOR0); + WRITE(p, "layout (location = %d) in vec4 color0;\n", (int)PspAttributeLocation::COLOR0); if (lmode && !useHWTransform) // only software transform supplies color1 as vertex data - WRITE(p, "layout (location = %d) in vec3 color1;\n", PspAttributeLocation::COLOR1); + WRITE(p, "layout (location = %d) in vec3 color1;\n", (int)PspAttributeLocation::COLOR1); } WRITE(p, "layout (location = 1) %sout vec4 v_color0;\n", shading); diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index d75581368c..c8fa5c32ca 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -42,156 +42,15 @@ SDLJoystick *joystick = NULL; #include "SDL_syswm.h" #endif +#if defined(USING_EGL) +#include "EGL/egl.h" +#endif + #include "Core/System.h" #include "Core/Core.h" #include "Core/Config.h" #include "Common/GraphicsContext.h" -class SDLGLGraphicsContext : public DummyGraphicsContext { -public: - SDLGLGraphicsContext(SDL_Window *window) : window_(window) { - CheckGLExtensions(); - draw_ = Draw::T3DCreateGLContext(); - bool success = draw_->CreatePresets(); - assert(success); - } - ~SDLGLGraphicsContext() { - delete draw_; - } - - void Shutdown() override { - } - - void SwapBuffers() override { -#ifdef USING_EGL - eglSwapBuffers(g_eglDisplay, g_eglSurface); -#else - SDL_GL_SwapWindow(window_); -#endif - } - - Draw::DrawContext *GetDrawContext() override { - return draw_; - } - -private: - Draw::DrawContext *draw_ = nullptr; - SDL_Window *window_; -}; - -static VulkanLogOptions g_LogOptions; - -class SDLVulkanGraphicsContext : public GraphicsContext { -public: - SDLVulkanGraphicsContext() {} - ~SDLVulkanGraphicsContext() { - delete draw_; - } - - bool Init(SDL_Window *sdl_window, std::string *error_message) { - SDL_SysWMinfo sys_info; - SDL_VERSION(&sys_info.version); //Set SDL version - SDL_GetWindowWMInfo(sdl_window, &sys_info); - - Display *display = sys_info.info.x11.display; - Window window = sys_info.info.x11.window; - - init_glslang(); - - g_LogOptions.breakOnError = true; - g_LogOptions.breakOnWarning = true; - g_LogOptions.msgBoxOnError = false; - - Version gitVer(PPSSPP_GIT_VERSION); - - vulkan_ = new VulkanContext(); - if (vulkan_->InitError().size()) { - *error_message = vulkan_->InitError(); - delete vulkan_; - vulkan_ = nullptr; - return false; - } - - int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX; - // vulkanFlags |= VULKAN_FLAG_VALIDATE; - VulkanContext::CreateInfo info{}; - info.app_name = "PPSSPP"; - info.app_ver = gitVer.ToInteger(); - info.flags = VULKAN_FLAG_PRESENT_MAILBOX; - if (VK_SUCCESS != vulkan_->CreateInstance(info)) { - *error_message = vulkan_->InitError(); - delete vulkan_; - vulkan_ = nullptr; - return false; - } - vulkan_->ChooseDevice(vulkan_->GetBestPhysicalDevice()); - if (vulkan_->CreateDevice() != VK_SUCCESS) { - *error_message = vulkan_->InitError(); - delete vulkan_; - vulkan_ = nullptr; - return false; - } - - vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void *)display, (void *)(intptr_t)window, pixel_xres, pixel_yres); - - if (!vulkan_->InitObjects()) { - *error_message = vulkan_->InitError(); - Shutdown(); - return false; - } - - draw_ = Draw::T3DCreateVulkanContext(vulkan_, false); - bool success = draw_->CreatePresets(); - assert(success); - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - - return true; - } - - void Shutdown() override { - if (draw_) - draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - delete draw_; - draw_ = nullptr; - vulkan_->WaitUntilQueueIdle(); - vulkan_->DestroyObjects(); - vulkan_->DestroyDevice(); - vulkan_->DestroyDebugMsgCallback(); - vulkan_->DestroyInstance(); - delete vulkan_; - vulkan_ = nullptr; - finalize_glslang(); - } - - void SwapBuffers() override { - // We don't do it this way. - } - - void Resize() override { - draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - vulkan_->DestroyObjects(); - // TODO: Take from real window dimensions - int width = 1024; - int height = 768; - vulkan_->ReinitSurface(width, height); - vulkan_->InitObjects(); - draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); - } - - void SwapInterval(int interval) override { - } - void *GetAPIContext() override { - return vulkan_; - } - - Draw::DrawContext *GetDrawContext() override { - return draw_; - } -private: - Draw::DrawContext *draw_ = nullptr; - VulkanContext *vulkan_ = nullptr; -}; - GlobalUIState lastUIState = UISTATE_MENU; GlobalUIState GetUIState(); @@ -202,8 +61,9 @@ static int g_QuitRequested = 0; static int g_DesktopWidth = 0; static int g_DesktopHeight = 0; +static VulkanLogOptions g_LogOptions; + #if defined(USING_EGL) -#include "EGL/egl.h" static EGLDisplay g_eglDisplay = NULL; static EGLContext g_eglContext = NULL; @@ -334,6 +194,264 @@ void EGL_Close() { } #endif +class SDLGLGraphicsContext : public DummyGraphicsContext { +public: + SDLGLGraphicsContext() { + } + ~SDLGLGraphicsContext() { + delete draw_; + } + + bool Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message); + + void Shutdown() override { +#ifdef USING_EGL + EGL_Close(); +#else + SDL_GL_DeleteContext(glContext); +#endif + } + + void SwapBuffers() override { +#ifdef USING_EGL + eglSwapBuffers(g_eglDisplay, g_eglSurface); +#else + SDL_GL_SwapWindow(window_); +#endif + } + + Draw::DrawContext *GetDrawContext() override { + return draw_; + } + +private: + Draw::DrawContext *draw_ = nullptr; + SDL_Window *window_; + SDL_GLContext glContext = nullptr; +}; + +bool SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) { + struct GLVersionPair { + int major; + int minor; + }; + GLVersionPair attemptVersions[] = { +#ifdef USING_GLES2 + {3, 2}, {3, 1}, {3, 0}, {2, 0}, +#else + {4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, + {3, 3}, {3, 2}, {3, 1}, {3, 0}, +#endif + }; + + SDL_GLContext glContext = nullptr; + for (size_t i = 0; i < ARRAY_SIZE(attemptVersions); ++i) { + const auto &ver = attemptVersions[i]; + // Make sure to request a somewhat modern GL context at least - the + // latest supported by MacOS X (really, really sad...) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, ver.major); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, ver.minor); +#ifdef USING_GLES2 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SetGLCoreContext(false); +#else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SetGLCoreContext(true); +#endif + + window = SDL_CreateWindow("PPSSPP", x,y, pixel_xres, pixel_yres, mode); + if (!window) { + NativeShutdown(); + fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); + continue; + } + + glContext = SDL_GL_CreateContext(window); + if (glContext != nullptr) { + // Victory, got one. + break; + } + + // Let's keep trying. To be safe, destroy the window - docs say needed to change profile. + // in practice, it doesn't seem to matter, but maybe it differs by platform. + SDL_DestroyWindow(window); + } + + if (glContext == nullptr) { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SetGLCoreContext(false); + + window = SDL_CreateWindow("PPSSPP", x,y, pixel_xres, pixel_yres, mode); + if (window == nullptr) { + NativeShutdown(); + fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); + SDL_Quit(); + return 2; + } + + glContext = SDL_GL_CreateContext(window); + if (glContext == nullptr) { + NativeShutdown(); + fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError()); + SDL_Quit(); + return 2; + } + } + +#ifdef USING_EGL + EGL_Init(); +#endif + +#ifndef USING_GLES2 + // Some core profile drivers elide certain extensions from GL_EXTENSIONS/etc. + // glewExperimental allows us to force GLEW to search for the pointers anyway. + if (gl_extensions.IsCoreContext) { + glewExperimental = true; + } + if (GLEW_OK != glewInit()) { + printf("Failed to initialize glew!\n"); + return 1; + } + // Unfortunately, glew will generate an invalid enum error, ignore. + if (gl_extensions.IsCoreContext) + glGetError(); + + if (GLEW_VERSION_2_0) { + printf("OpenGL 2.0 or higher.\n"); + } else { + printf("Sorry, this program requires OpenGL 2.0.\n"); + return 1; + } +#endif + + // Finally we can do the regular initialization. + CheckGLExtensions(); + draw_ = Draw::T3DCreateGLContext(); + bool success = draw_->CreatePresets(); + assert(success); + window_ = window; +} + +class SDLVulkanGraphicsContext : public GraphicsContext { +public: + SDLVulkanGraphicsContext() {} + ~SDLVulkanGraphicsContext() { + delete draw_; + } + + bool Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message); + + void Shutdown() override; + + void SwapBuffers() override { + // We don't do it this way. + } + + void Resize() override { + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + vulkan_->DestroyObjects(); + // TODO: Take from real window dimensions + int width = 1024; + int height = 768; + vulkan_->ReinitSurface(width, height); + vulkan_->InitObjects(); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + } + + void SwapInterval(int interval) override { + } + void *GetAPIContext() override { + return vulkan_; + } + + Draw::DrawContext *GetDrawContext() override { + return draw_; + } +private: + Draw::DrawContext *draw_ = nullptr; + VulkanContext *vulkan_ = nullptr; +}; + +bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) { + mode |= SDL_WINDOW_VULKAN; + window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode); + SDL_SysWMinfo sys_info; + SDL_VERSION(&sys_info.version); + SDL_GetWindowWMInfo(window, &sys_info); + Display *display = sys_info.info.x11.display; + Window x11_window = sys_info.info.x11.window; + + ILOG("Display: %p", display); + + init_glslang(); + + g_LogOptions.breakOnError = true; + g_LogOptions.breakOnWarning = true; + g_LogOptions.msgBoxOnError = false; + + Version gitVer(PPSSPP_GIT_VERSION); + + vulkan_ = new VulkanContext(); + if (vulkan_->InitError().size()) { + *error_message = vulkan_->InitError(); + delete vulkan_; + vulkan_ = nullptr; + return false; + } + + int vulkanFlags = VULKAN_FLAG_PRESENT_MAILBOX; + // vulkanFlags |= VULKAN_FLAG_VALIDATE; + VulkanContext::CreateInfo info{}; + info.app_name = "PPSSPP"; + info.app_ver = gitVer.ToInteger(); + info.flags = vulkanFlags; + if (VK_SUCCESS != vulkan_->CreateInstance(info)) { + *error_message = vulkan_->InitError(); + delete vulkan_; + vulkan_ = nullptr; + return false; + } + vulkan_->ChooseDevice(vulkan_->GetBestPhysicalDevice()); + if (vulkan_->CreateDevice() != VK_SUCCESS) { + *error_message = vulkan_->InitError(); + delete vulkan_; + vulkan_ = nullptr; + return false; + } + + vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void *)display, (void *)(intptr_t)x11_window, pixel_xres, pixel_yres); + + if (!vulkan_->InitObjects()) { + *error_message = vulkan_->InitError(); + Shutdown(); + return false; + } + + draw_ = Draw::T3DCreateVulkanContext(vulkan_, false); + bool success = draw_->CreatePresets(); + assert(success); + draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + + return true; +} + +void SDLVulkanGraphicsContext::Shutdown() { + if (draw_) + draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + delete draw_; + draw_ = nullptr; + vulkan_->WaitUntilQueueIdle(); + vulkan_->DestroyObjects(); + vulkan_->DestroyDevice(); + vulkan_->DestroyDebugMsgCallback(); + vulkan_->DestroyInstance(); + delete vulkan_; + vulkan_ = nullptr; + finalize_glslang(); +} + int getDisplayNumber(void) { int displayNumber = 0; char * displayNumberStr; @@ -545,6 +663,12 @@ int main(int argc, char *argv[]) { putenv((char*)"SDL_VIDEO_CENTERED=1"); SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0"); + if (VulkanMayBeAvailable()) { + printf("Vulkan might be available.\n"); + } else { + printf("Vulkan is not available.\n"); + } + int set_xres = -1; int set_yres = -1; bool portrait = false; @@ -593,6 +717,7 @@ int main(int argc, char *argv[]) { bool joystick_enabled = true; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) < 0) { + fprintf(stderr, "Failed to initialize SDL with joystick support. Retrying without.\n"); joystick_enabled = false; if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); @@ -600,6 +725,7 @@ int main(int argc, char *argv[]) { } } + // TODO: How do we get this into the GraphicsContext? #ifdef USING_EGL if (EGL_Open()) return 1; @@ -624,12 +750,6 @@ int main(int argc, char *argv[]) { SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetSwapInterval(1); -#ifdef USING_GLES2 - mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN; -#else - mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; -#endif - // Is resolution is too low to run windowed if (g_DesktopWidth < 480 * 2 && g_DesktopHeight < 272 * 2) { mode |= SDL_WINDOW_FULLSCREEN_DESKTOP; @@ -694,109 +814,6 @@ int main(int argc, char *argv[]) { int x = SDL_WINDOWPOS_UNDEFINED_DISPLAY(getDisplayNumber()); int y = SDL_WINDOWPOS_UNDEFINED; - struct GLVersionPair { - int major; - int minor; - }; - GLVersionPair attemptVersions[] = { -#ifdef USING_GLES2 - {3, 2}, {3, 1}, {3, 0}, {2, 0}, -#else - {4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, - {3, 3}, {3, 2}, {3, 1}, {3, 0}, -#endif - }; - - SDL_Window *window = nullptr; - SDL_GLContext glContext = nullptr; - for (size_t i = 0; i < ARRAY_SIZE(attemptVersions); ++i) { - const auto &ver = attemptVersions[i]; - // Make sure to request a somewhat modern GL context at least - the - // latest supported by MacOS X (really, really sad...) - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, ver.major); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, ver.minor); -#ifdef USING_GLES2 - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SetGLCoreContext(false); -#else - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SetGLCoreContext(true); -#endif - - window = SDL_CreateWindow(app_name_nice.c_str(), x,y, pixel_xres, pixel_yres, mode); - if (!window) { - NativeShutdown(); - fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); - continue; - } - - glContext = SDL_GL_CreateContext(window); - if (glContext != nullptr) { - // Victory, got one. - break; - } - - // Let's keep trying. To be safe, destroy the window - docs say needed to change profile. - // in practice, it doesn't seem to matter, but maybe it differs by platform. - SDL_DestroyWindow(window); - } - - if (glContext == nullptr) { - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 0); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); - SetGLCoreContext(false); - - window = SDL_CreateWindow(app_name_nice.c_str(), x,y, pixel_xres, pixel_yres, mode); - if (window == nullptr) { - NativeShutdown(); - fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); - SDL_Quit(); - return 2; - } - - glContext = SDL_GL_CreateContext(window); - if (glContext == nullptr) { - NativeShutdown(); - fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError()); - SDL_Quit(); - return 2; - } - } - -#ifdef USING_EGL - EGL_Init(); -#endif - - SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str()); - -#ifdef MOBILE_DEVICE - SDL_ShowCursor(SDL_DISABLE); -#endif - - -#ifndef USING_GLES2 - // Some core profile drivers elide certain extensions from GL_EXTENSIONS/etc. - // glewExperimental allows us to force GLEW to search for the pointers anyway. - if (gl_extensions.IsCoreContext) - glewExperimental = true; - if (GLEW_OK != glewInit()) { - printf("Failed to initialize glew!\n"); - return 1; - } - // Unfortunately, glew will generate an invalid enum error, ignore. - if (gl_extensions.IsCoreContext) - glGetError(); - - if (GLEW_VERSION_2_0) { - printf("OpenGL 2.0 or higher.\n"); - } else { - printf("Sorry, this program requires OpenGL 2.0.\n"); - return 1; - } -#endif - - pixel_in_dps_x = (float)pixel_xres / dp_xres; pixel_in_dps_y = (float)pixel_yres / dp_yres; g_dpi_scale_x = dp_xres / (float)pixel_xres; @@ -807,21 +824,35 @@ int main(int argc, char *argv[]) { printf("Pixels: %i x %i\n", pixel_xres, pixel_yres); printf("Virtual pixels: %i x %i\n", dp_xres, dp_yres); - GraphicsContext *graphicsContext; + GraphicsContext *graphicsContext = nullptr; + SDL_Window *window = nullptr; + std::string error_message; if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) { - graphicsContext = new SDLGLGraphicsContext(window); + SDLGLGraphicsContext *ctx = new SDLGLGraphicsContext(); + if (!ctx->Init(window, x, y, mode, &error_message)) { + printf("GL init error '%s' - falling back to GL\n", error_message.c_str()); + } + graphicsContext = ctx; } else if (g_Config.iGPUBackend == GPU_BACKEND_VULKAN) { SDLVulkanGraphicsContext *ctx = new SDLVulkanGraphicsContext(); - std::string error_message; - if (!ctx->Init(window, &error_message)) { + if (!ctx->Init(window, x, y, mode, &error_message)) { printf("Vulkan init error '%s' - falling back to GL\n", error_message.c_str()); g_Config.iGPUBackend = GPU_BACKEND_OPENGL; delete ctx; - graphicsContext = new SDLGLGraphicsContext(window); + SDLGLGraphicsContext *glctx = new SDLGLGraphicsContext(); + glctx->Init(window, x, y, mode, &error_message); + graphicsContext = glctx; } else { graphicsContext = ctx; } } + + SDL_SetWindowTitle(window, (app_name_nice + " " + PPSSPP_GIT_VERSION).c_str()); + +#ifdef MOBILE_DEVICE + SDL_ShowCursor(SDL_DISABLE); +#endif + NativeInitGraphics(graphicsContext); NativeResized(); @@ -1054,16 +1085,12 @@ int main(int argc, char *argv[]) { } delete joystick; NativeShutdownGraphics(); - SDL_GL_DeleteContext(glContext); graphicsContext->Shutdown(); NativeShutdown(); delete graphicsContext; SDL_PauseAudio(1); SDL_CloseAudio(); -#ifdef USING_EGL - EGL_Close(); -#endif SDL_Quit(); #if PPSSPP_PLATFORM(RPI) bcm_host_deinit(); diff --git a/UI/GameSettingsScreen.cpp b/UI/GameSettingsScreen.cpp index c3dfcd193d..0c0b2dcdcf 100644 --- a/UI/GameSettingsScreen.cpp +++ b/UI/GameSettingsScreen.cpp @@ -191,7 +191,7 @@ void GameSettingsScreen::CreateViews() { } #endif bool vulkanAvailable = false; -#if PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(ANDROID) +#ifndef IOS vulkanAvailable = VulkanMayBeAvailable(); #endif if (!vulkanAvailable) { From 9007abddbf0d78646b4bc57d21aaf5990746c2f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 15 Dec 2017 16:03:48 +0100 Subject: [PATCH 14/16] Get Vulkan going on Linux --- CMakeLists.txt | 11 +++++++++-- SDL/SDLMain.cpp | 43 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb071f54ce..5be4b7975a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,9 +106,10 @@ else() message("Normal Build") endif() -if(LINUX) - message("Using direct to display extension...") +if(LINUX AND VULKAN) + message("Using XCB extension...") add_definitions(-DVK_USE_PLATFORM_XLIB_KHR) + # add_definitions(-DVK_USE_PLATFORM_XCB_KHR) endif() # Doesn't link on some platforms @@ -1669,6 +1670,12 @@ endif() set(CoreExtraLibs ${CoreExtraLibs} armips) +# needed for VK_USE_PLATFORM_XCB_KHR only +#if(VULKAN AND NOT WIN32) +# target_link_libraries(native X11-xcb X11) +#endif() + + set(GlslangLibs glslang OGLCompiler OSDependent SPIRV SPVRemapper spirv-cross-glsl) target_link_libraries(${CoreLibName} Common native kirk cityhash sfmt19937 xbrz xxhash ${GlslangLibs} diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index c8fa5c32ca..fb7dc5f454 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -40,6 +40,11 @@ SDLJoystick *joystick = NULL; #include #include #include "SDL_syswm.h" +#elif defined(VK_USE_PLATFORM_XCB_KHR) +#include +#include +#include +#include "SDL_syswm.h" #endif #if defined(USING_EGL) @@ -350,6 +355,7 @@ public: } void Resize() override { + /* draw_->HandleEvent(Draw::Event::LOST_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); vulkan_->DestroyObjects(); // TODO: Take from real window dimensions @@ -358,6 +364,7 @@ public: vulkan_->ReinitSurface(width, height); vulkan_->InitObjects(); draw_->HandleEvent(Draw::Event::GOT_BACKBUFFER, vulkan_->GetBackbufferWidth(), vulkan_->GetBackbufferHeight()); + */ } void SwapInterval(int interval) override { @@ -375,15 +382,11 @@ private: }; bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) { - mode |= SDL_WINDOW_VULKAN; window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode); - SDL_SysWMinfo sys_info; - SDL_VERSION(&sys_info.version); - SDL_GetWindowWMInfo(window, &sys_info); - Display *display = sys_info.info.x11.display; - Window x11_window = sys_info.info.x11.window; - - ILOG("Display: %p", display); + if (!window) { + fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError()); + exit(1); + } init_glslang(); @@ -421,7 +424,29 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, return false; } - vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void *)display, (void *)(intptr_t)x11_window, pixel_xres, pixel_yres); + SDL_SysWMinfo sys_info{}; + SDL_VERSION(&sys_info.version); //Set SDL version + if (!SDL_GetWindowWMInfo(window, &sys_info)) { + fprintf(stderr, "Error getting SDL window wm info: %s\n", SDL_GetError()); + exit(1); + } + Display *display = sys_info.info.x11.display; + Window x11_window = sys_info.info.x11.window; + switch (sys_info.subsystem) { + case SDL_SYSWM_X11: + break; + default: + fprintf(stderr, "Vulkan subsystem %d not supported\n", sys_info.subsystem); + exit(1); + break; + } + ILOG("Display: %p", display); + +#if defined(VK_USE_PLATFORM_XLIB_KHR) + vulkan_->InitSurface(WINDOWSYSTEM_XLIB, (void*)display, (void *)(intptr_t)x11_window, pixel_xres, pixel_yres); +#elif defined(VK_USE_PLATFORM_XCB_KHR) + vulkan_->InitSurface(WINDOWSYSTEM_XCB, (void*)XGetXCBConnection(display), (void *)(intptr_t)x11_window, pixel_xres, pixel_yres); +#endif if (!vulkan_->InitObjects()) { *error_message = vulkan_->InitError(); From f73ec4608e72f6ec40861bd6bbaca82d97e51d7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 21 Dec 2017 14:13:55 +0100 Subject: [PATCH 15/16] Build Vulkan on all platforms, won't be used if not supported. --- CMakeLists.txt | 43 +++++++++++++++++++++---------------------- SDL/SDLMain.cpp | 26 ++++++++++++++++---------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5be4b7975a..a8915f868a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,23 +355,19 @@ set(CommonWindows Common/stdafx.h) source_group(Windows FILES ${CommonWindows}) -if(VULKAN) - set(CommonVulkan ${CommonExtra} - Common/Vulkan/SPIRVDisasm.cpp - Common/Vulkan/SPIRVDisasm.h - Common/Vulkan/VulkanContext.cpp - Common/Vulkan/VulkanContext.h - Common/Vulkan/VulkanDebug.cpp - Common/Vulkan/VulkanDebug.h - Common/Vulkan/VulkanImage.cpp - Common/Vulkan/VulkanImage.h - Common/Vulkan/VulkanLoader.cpp - Common/Vulkan/VulkanLoader.h - Common/Vulkan/VulkanMemory.cpp - Common/Vulkan/VulkanMemory.h) -else() - set(CommonVulkan) -endif() +set(CommonVulkan ${CommonExtra} + Common/Vulkan/SPIRVDisasm.cpp + Common/Vulkan/SPIRVDisasm.h + Common/Vulkan/VulkanContext.cpp + Common/Vulkan/VulkanContext.h + Common/Vulkan/VulkanDebug.cpp + Common/Vulkan/VulkanDebug.h + Common/Vulkan/VulkanImage.cpp + Common/Vulkan/VulkanImage.h + Common/Vulkan/VulkanLoader.cpp + Common/Vulkan/VulkanLoader.h + Common/Vulkan/VulkanMemory.cpp + Common/Vulkan/VulkanMemory.h) add_library(Common STATIC ${CommonX86} @@ -838,15 +834,14 @@ if(ANDROID) endif() set(THIN3D_PLATFORMS ext/native/thin3d/thin3d_gl.cpp) -if(VULKAN) - set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} - ext/native/thin3d/thin3d_vulkan.cpp +set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} + ext/native/thin3d/thin3d_vulkan.cpp ext/native/thin3d/VulkanRenderManager.cpp ext/native/thin3d/VulkanRenderManager.h ext/native/thin3d/VulkanQueueRunner.cpp ext/native/thin3d/VulkanQueueRunner.h ext/native/thin3d/DataFormat.h) -endif() + if(WIN32) set(THIN3D_PLATFORMS ${THIN3D_PLATFORMS} ext/native/thin3d/thin3d_d3d9.cpp @@ -1679,7 +1674,11 @@ set(CoreExtraLibs ${CoreExtraLibs} armips) set(GlslangLibs glslang OGLCompiler OSDependent SPIRV SPVRemapper spirv-cross-glsl) target_link_libraries(${CoreLibName} Common native kirk cityhash sfmt19937 xbrz xxhash ${GlslangLibs} - ${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS} ${Vulkan_LIBRARY}) + ${CoreExtraLibs} ${OPENGL_LIBRARIES} ${X11_LIBRARIES} ${CMAKE_DL_LIBS}) + +if(VULKAN) + target_link_libraries(${CoreLibName} ${Vulkan_LIBRARY}) +endif() if(FFmpeg_FOUND) target_compile_definitions(${CoreLibName} PRIVATE USE_FFMPEG=1) diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index fb7dc5f454..4f83c5e405 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -155,16 +155,13 @@ int8_t EGL_Init() { g_eglContext = eglCreateContext(g_eglDisplay, g_eglConfig, NULL, attributes ); if (g_eglContext == EGL_NO_CONTEXT) EGL_ERROR("Unable to create GLES context!", true); -#if !defined(USING_FBDEV) +#if !defined(USING_FBDEV) && !defined(__APPLE__) //Get the SDL window handle SDL_SysWMinfo sysInfo; //Will hold our Window information SDL_VERSION(&sysInfo.version); //Set SDL version -#endif - -#ifdef USING_FBDEV - g_Window = (NativeWindowType)NULL; -#else g_Window = (NativeWindowType)sysInfo.info.x11.window; +#else + g_Window = (NativeWindowType)NULL; #endif g_eglSurface = eglCreateWindowSurface(g_eglDisplay, g_eglConfig, g_Window, 0); if (g_eglSurface == EGL_NO_SURFACE) @@ -207,7 +204,8 @@ public: delete draw_; } - bool Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message); + // Returns 0 on success. + int Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message); void Shutdown() override { #ifdef USING_EGL @@ -235,7 +233,8 @@ private: SDL_GLContext glContext = nullptr; }; -bool SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) { +// Returns 0 on success. +int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std::string *error_message) { struct GLVersionPair { int major; int minor; @@ -337,6 +336,7 @@ bool SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std bool success = draw_->CreatePresets(); assert(success); window_ = window; + return 0; } class SDLVulkanGraphicsContext : public GraphicsContext { @@ -424,6 +424,7 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, return false; } +#if !defined(__APPLE__) SDL_SysWMinfo sys_info{}; SDL_VERSION(&sys_info.version); //Set SDL version if (!SDL_GetWindowWMInfo(window, &sys_info)) { @@ -440,6 +441,11 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, exit(1); break; } +#else + // Fake to make it build on Apple. This code won't run there though. + void *display = nullptr; + int x11_window = 0; +#endif ILOG("Display: %p", display); #if defined(VK_USE_PLATFORM_XLIB_KHR) @@ -854,8 +860,8 @@ int main(int argc, char *argv[]) { std::string error_message; if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) { SDLGLGraphicsContext *ctx = new SDLGLGraphicsContext(); - if (!ctx->Init(window, x, y, mode, &error_message)) { - printf("GL init error '%s' - falling back to GL\n", error_message.c_str()); + if (ctx->Init(window, x, y, mode, &error_message) != 0) { + printf("GL init error '%s'\n", error_message.c_str()); } graphicsContext = ctx; } else if (g_Config.iGPUBackend == GPU_BACKEND_VULKAN) { From fe45a059b5ab8546968e27d65eab9cbde42be6bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 21 Dec 2017 17:36:00 +0100 Subject: [PATCH 16/16] SDL: Fix OpenGL init again. Fixes #10424 --- SDL/SDLMain.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 4f83c5e405..f3202d24bf 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -248,6 +248,11 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std: #endif }; +#ifdef USING_GLES2 + mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN; +#else + mode |= SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; +#endif SDL_GLContext glContext = nullptr; for (size_t i = 0; i < ARRAY_SIZE(attemptVersions); ++i) { const auto &ver = attemptVersions[i];