diff --git a/CMakeLists.txt b/CMakeLists.txt index b11630d109..a8915f868a 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,33 @@ 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 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) @@ -86,6 +106,12 @@ else() message("Normal Build") endif() +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 #if(NOT DEFINED UNITTEST) # set(UNITTEST OFF) @@ -113,6 +139,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) @@ -325,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} @@ -808,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 @@ -1640,11 +1665,21 @@ 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} ${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) target_link_libraries(${CoreLibName} diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index 02d0282946..c0f7f5f6ba 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -109,6 +109,16 @@ 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_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 + //... #endif if (flags_ & VULKAN_FLAG_VALIDATE) { @@ -424,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_)) { @@ -545,6 +556,7 @@ VkResult VulkanContext::CreateDevice() { } else { VulkanLoadDeviceFunctions(device_); } + ILOG("Device created.\n"); return res; } @@ -563,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); @@ -578,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(); } } @@ -631,6 +643,31 @@ 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; @@ -684,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, @@ -720,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/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..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; @@ -165,6 +167,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; @@ -179,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; @@ -195,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 @@ -214,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"); @@ -237,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); @@ -374,7 +399,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,12 +415,16 @@ 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); +#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."); } @@ -404,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); @@ -421,4 +453,5 @@ void VulkanFree() { #endif vulkanLibrary = nullptr; } +#endif } diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 67042c0c0c..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; @@ -171,6 +174,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; @@ -187,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(); @@ -198,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 660663037f..4f83c5e405 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" @@ -41,34 +30,35 @@ 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" +#include "math.h" + +#if defined(VK_USE_PLATFORM_XLIB_KHR) +#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) +#include "EGL/egl.h" +#endif #include "Core/System.h" #include "Core/Core.h" #include "Core/Config.h" #include "Common/GraphicsContext.h" -class GLDummyGraphicsContext : public DummyGraphicsContext { -public: - GLDummyGraphicsContext() { - CheckGLExtensions(); - draw_ = Draw::T3DCreateGLContext(); - bool success = draw_->CreatePresets(); - assert(success); - } - ~GLDummyGraphicsContext() { delete draw_; } - - Draw::DrawContext *GetDrawContext() override { - return draw_; - } -private: - Draw::DrawContext *draw_; -}; - 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; @@ -76,16 +66,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" - -#if !defined(USING_FBDEV) -#include -#include -#endif - -#include "SDL_syswm.h" -#include "math.h" static EGLDisplay g_eglDisplay = NULL; static EGLContext g_eglContext = NULL; @@ -172,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) @@ -216,6 +196,293 @@ void EGL_Close() { } #endif +class SDLGLGraphicsContext : public DummyGraphicsContext { +public: + SDLGLGraphicsContext() { + } + ~SDLGLGraphicsContext() { + delete draw_; + } + + // 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 + 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; +}; + +// 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; + }; + 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; + return 0; +} + +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) { + window = SDL_CreateWindow("Initializing Vulkan...", x, y, pixel_xres, pixel_yres, mode); + if (!window) { + fprintf(stderr, "Error creating SDL window: %s\n", SDL_GetError()); + exit(1); + } + + 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; + } + +#if !defined(__APPLE__) + 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; + } +#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) + 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(); + 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; @@ -399,11 +666,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) { @@ -411,7 +678,7 @@ void ToggleFullScreenIfFlagSet() { } else { window_flags &= ~SDL_WINDOW_FULLSCREEN_DESKTOP; } - SDL_SetWindowFullscreen(g_Screen, window_flags); + SDL_SetWindowFullscreen(window, window_flags); } } @@ -419,57 +686,20 @@ 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"); - std::string app_name; - std::string app_name_nice; - std::string version; - bool landscape; - NativeGetAppInfo(&app_name, &app_name_nice, &landscape, &version); - - bool joystick_enabled = true; - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) < 0) { - joystick_enabled = false; - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) { - fprintf(stderr, "Unable to initialize SDL: %s\n", SDL_GetError()); - return 1; - } + if (VulkanMayBeAvailable()) { + printf("Vulkan might be available.\n"); + } else { + printf("Vulkan is not available.\n"); } -#ifdef USING_EGL - if (EGL_Open()) - return 1; -#endif - - // Get the video info before doing anything else, so we don't get skewed resolution results. - // TODO: support multiple displays correctly - SDL_DisplayMode displayMode; - int should_be_zero = SDL_GetCurrentDisplayMode(0, &displayMode); - if (should_be_zero != 0) { - fprintf(stderr, "Could not get display mode: %s\n", SDL_GetError()); - return 1; - } - g_DesktopWidth = displayMode.w; - g_DesktopHeight = displayMode.h; - - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetSwapInterval(1); - - Uint32 mode; -#ifdef USING_GLES2 - mode = SDL_WINDOW_OPENGL | SDL_WINDOW_FULLSCREEN; -#else - mode = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; -#endif int set_xres = -1; int set_yres = -1; bool portrait = false; @@ -481,6 +711,7 @@ int main(int argc, char *argv[]) { 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; @@ -509,6 +740,47 @@ int main(int argc, char *argv[]) { } } + std::string app_name; + std::string app_name_nice; + std::string version; + bool landscape; + NativeGetAppInfo(&app_name, &app_name_nice, &landscape, &version); + + 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()); + return 1; + } + } + + // TODO: How do we get this into the GraphicsContext? +#ifdef USING_EGL + if (EGL_Open()) + return 1; +#endif + + // Get the video info before doing anything else, so we don't get skewed resolution results. + // TODO: support multiple displays correctly + SDL_DisplayMode displayMode; + int should_be_zero = SDL_GetCurrentDisplayMode(0, &displayMode); + if (should_be_zero != 0) { + fprintf(stderr, "Could not get display mode: %s\n", SDL_GetError()); + return 1; + } + g_DesktopWidth = displayMode.w; + g_DesktopHeight = displayMode.h; + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetSwapInterval(1); + // Is resolution is too low to run windowed if (g_DesktopWidth < 480 * 2 && g_DesktopHeight < 272 * 2) { mode |= SDL_WINDOW_FULLSCREEN_DESKTOP; @@ -552,12 +824,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"); @@ -569,13 +835,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) @@ -584,107 +845,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_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 - - g_Screen = SDL_CreateWindow(app_name_nice.c_str(), x,y, pixel_xres, pixel_yres, mode); - if (g_Screen == nullptr) { - fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError()); - continue; - } - - glContext = SDL_GL_CreateContext(g_Screen); - 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(g_Screen); - } - - 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); - - 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; - } - - glContext = SDL_GL_CreateContext(g_Screen); - 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(g_Screen, (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; @@ -695,9 +855,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); - glslang::InitializeProcess(); + GraphicsContext *graphicsContext = nullptr; + SDL_Window *window = nullptr; + std::string error_message; + if (g_Config.iGPUBackend == GPU_BACKEND_OPENGL) { + SDLGLGraphicsContext *ctx = new SDLGLGraphicsContext(); + 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) { + SDLVulkanGraphicsContext *ctx = new SDLVulkanGraphicsContext(); + 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; + 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 - GraphicsContext *graphicsContext = new GLDummyGraphicsContext(); NativeInitGraphics(graphicsContext); NativeResized(); @@ -728,18 +914,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) { @@ -758,7 +940,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; @@ -900,11 +1082,9 @@ int main(int argc, char *argv[]) { } break; default: -#ifndef _WIN32 if (joystick) { joystick->ProcessInput(event); } -#endif break; } } @@ -928,44 +1108,25 @@ 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(); 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..0c0b2dcdcf 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(); @@ -190,7 +191,7 @@ void GameSettingsScreen::CreateViews() { } #endif bool vulkanAvailable = false; -#if PPSSPP_PLATFORM(WINDOWS) || PPSSPP_PLATFORM(ANDROID) +#ifndef IOS vulkanAvailable = VulkanMayBeAvailable(); #endif if (!vulkanAvailable) { 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 {