diff --git a/CMakeLists.txt b/CMakeLists.txt index 176a4500e9..573235b787 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,8 +84,8 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Android") set(ANDROID ON) endif() -# We only support Vulkan on Unix, Android and Windows. -if(ANDROID OR WIN32 OR (UNIX AND NOT APPLE AND NOT ARM_NO_VULKAN)) +# We only support Vulkan on Unix, macOS (by MoltenVK), Android and Windows. +if(ANDROID OR WIN32 OR (UNIX AND NOT ARM_NO_VULKAN)) set(VULKAN ON) endif() @@ -188,6 +188,7 @@ include(FindThreads) if(APPLE) find_library(COCOA_LIBRARY Cocoa) + find_library(QUARTZ_CORE_LIBRARY QuartzCore) endif() include_directories("${CMAKE_SOURCE_DIR}") @@ -828,8 +829,8 @@ elseif(TARGET SDL2::SDL2) ) set(nativeExtraLibs ${nativeExtraLibs} SDL2::SDL2) if(APPLE) - set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm) - set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY}) + set(nativeExtra ${nativeExtra} SDL/SDLMain.h SDL/SDLMain.mm SDL/SDLCocoaMetalLayer.h SDL/SDLCocoaMetalLayer.mm) + set(nativeExtraLibs ${nativeExtraLibs} ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY}) elseif(USING_EGL) set(nativeExtraLibs ${nativeExtraLibs} pthread) endif() @@ -1955,7 +1956,7 @@ if(HEADLESS) headless/SDLHeadlessHost.cpp headless/SDLHeadlessHost.h ) - target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${LinkCommon}) + target_link_libraries(PPSSPPHeadless ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${LinkCommon}) setup_target_project(PPSSPPHeadless headless) endif() @@ -1970,7 +1971,7 @@ if(UNITTEST) Core/MIPS/ARM/ArmRegCache.cpp Core/MIPS/ARM/ArmRegCacheFPU.cpp ) - target_link_libraries(unitTest ${COCOA_LIBRARY} ${LinkCommon} Common) + target_link_libraries(unitTest ${COCOA_LIBRARY} ${QUARTZ_CORE_LIBRARY} ${LinkCommon} Common) setup_target_project(unitTest unittest) endif() diff --git a/Common/Vulkan/VulkanContext.cpp b/Common/Vulkan/VulkanContext.cpp index be07dd66c6..cb4dc0b33a 100644 --- a/Common/Vulkan/VulkanContext.cpp +++ b/Common/Vulkan/VulkanContext.cpp @@ -125,6 +125,11 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) { instance_extensions_enabled_.push_back(VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); } #endif +#if defined(VK_USE_PLATFORM_METAL_EXT) + if (IsInstanceExtensionAvailable(VK_EXT_METAL_SURFACE_EXTENSION_NAME)) { + instance_extensions_enabled_.push_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME); + } +#endif #endif if (flags_ & VULKAN_FLAG_VALIDATE) { @@ -760,6 +765,16 @@ VkResult VulkanContext::ReinitSurface() { return vkCreateAndroidSurfaceKHR(instance_, &android, nullptr, &surface_); } #endif +#if defined(VK_USE_PLATFORM_METAL_EXT) + case WINDOWSYSTEM_METAL_EXT: + { + VkMetalSurfaceCreateInfoEXT metal{ VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT }; + metal.flags = 0; + metal.pLayer = winsysData1_; + metal.pNext = winsysData2_; + return vkCreateMetalSurfaceEXT(instance_, &metal, nullptr, &surface_); + } +#endif #if defined(VK_USE_PLATFORM_XLIB_KHR) case WINDOWSYSTEM_XLIB: { @@ -968,10 +983,10 @@ bool VulkanContext::InitSwapchain() { // Application must settle for fewer images than desired: desiredNumberOfSwapChainImages = surfCapabilities_.maxImageCount; } - + // We mostly follow the practices from // https://arm-software.github.io/vulkan_best_practice_for_mobile_developers/samples/surface_rotation/surface_rotation_tutorial.html - // + // VkSurfaceTransformFlagBitsKHR preTransform; std::string supportedTransforms = surface_transforms_to_string(surfCapabilities_.supportedTransforms); std::string currentTransform = surface_transforms_to_string(surfCapabilities_.currentTransform); diff --git a/Common/Vulkan/VulkanContext.h b/Common/Vulkan/VulkanContext.h index 63fa5108e7..fccc3dc98e 100644 --- a/Common/Vulkan/VulkanContext.h +++ b/Common/Vulkan/VulkanContext.h @@ -34,6 +34,9 @@ enum WindowSystem { #ifdef __ANDROID__ WINDOWSYSTEM_ANDROID, #endif +#ifdef VK_USE_PLATFORM_METAL_EXT + WINDOWSYSTEM_METAL_EXT, +#endif #ifdef VK_USE_PLATFORM_XLIB_KHR WINDOWSYSTEM_XLIB, #endif diff --git a/Common/Vulkan/VulkanLoader.cpp b/Common/Vulkan/VulkanLoader.cpp index 93aff18cec..a523ab4968 100644 --- a/Common/Vulkan/VulkanLoader.cpp +++ b/Common/Vulkan/VulkanLoader.cpp @@ -176,6 +176,9 @@ PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; #elif defined(_WIN32) PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; #endif +#if defined(VK_USE_PLATFORM_METAL_EXT) +PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; +#endif #if defined(VK_USE_PLATFORM_XLIB_KHR) PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; #endif @@ -236,10 +239,14 @@ static const char *device_name_blacklist[] = { }; static const char *so_names[] = { +#if defined(__APPLE__) + "libMoltenVK.dylib", +#else "libvulkan.so", #if !defined(__ANDROID__) "libvulkan.so.1", #endif +#endif }; void VulkanSetAvailable(bool available) { @@ -310,6 +317,8 @@ bool VulkanMayBeAvailable() { const char * const platformSurfaceExtension = VK_KHR_WIN32_SURFACE_EXTENSION_NAME; #elif defined(__ANDROID__) const char *platformSurfaceExtension = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME; +#elif defined(VK_USE_PLATFORM_METAL_EXT) + const char * const platformSurfaceExtension = VK_EXT_METAL_SURFACE_EXTENSION_NAME; #else const char *platformSurfaceExtension = 0; #endif @@ -515,6 +524,8 @@ void VulkanLoadInstanceFunctions(VkInstance instance, const VulkanDeviceExtensio LOAD_INSTANCE_FUNC(instance, vkCreateWin32SurfaceKHR); #elif defined(__ANDROID__) LOAD_INSTANCE_FUNC(instance, vkCreateAndroidSurfaceKHR); +#elif defined(VK_USE_PLATFORM_METAL_EXT) + LOAD_INSTANCE_FUNC(instance, vkCreateMetalSurfaceEXT); #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) LOAD_INSTANCE_FUNC(instance, vkCreateXlibSurfaceKHR); diff --git a/Common/Vulkan/VulkanLoader.h b/Common/Vulkan/VulkanLoader.h index 3d1ccae86b..99b560cfa6 100644 --- a/Common/Vulkan/VulkanLoader.h +++ b/Common/Vulkan/VulkanLoader.h @@ -25,6 +25,8 @@ #ifndef NOMINMAX #define NOMINMAX #endif +#elif defined(__APPLE__) +#define VK_USE_PLATFORM_METAL_EXT #endif #define VK_NO_PROTOTYPES @@ -173,6 +175,8 @@ extern PFN_vkCmdExecuteCommands vkCmdExecuteCommands; extern PFN_vkCreateAndroidSurfaceKHR vkCreateAndroidSurfaceKHR; #elif defined(_WIN32) extern PFN_vkCreateWin32SurfaceKHR vkCreateWin32SurfaceKHR; +#elif defined(VK_USE_PLATFORM_METAL_EXT) +extern PFN_vkCreateMetalSurfaceEXT vkCreateMetalSurfaceEXT; #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) extern PFN_vkCreateXlibSurfaceKHR vkCreateXlibSurfaceKHR; diff --git a/SDL/SDLCocoaMetalLayer.h b/SDL/SDLCocoaMetalLayer.h new file mode 100644 index 0000000000..28c7849e56 --- /dev/null +++ b/SDL/SDLCocoaMetalLayer.h @@ -0,0 +1,5 @@ +#pragma once + +extern "C" { +void *makeWindowMetalCompatible(void *window); +} diff --git a/SDL/SDLCocoaMetalLayer.mm b/SDL/SDLCocoaMetalLayer.mm new file mode 100644 index 0000000000..ce1b9cd206 --- /dev/null +++ b/SDL/SDLCocoaMetalLayer.mm @@ -0,0 +1,16 @@ +#import +#import + +#include "base/logging.h" +#include "SDLCocoaMetalLayer.h" + +void *makeWindowMetalCompatible(void *window) { + NSView *view = ((NSWindow *)window).contentView; + assert([view isKindOfClass:[NSView class]]); + + if (![view.layer isKindOfClass:[CAMetalLayer class]]) + { + [view setLayer:[CAMetalLayer layer]]; + } + return view.layer; +} diff --git a/SDL/SDLGLGraphicsContext.h b/SDL/SDLGLGraphicsContext.h index 651f7a534b..666aa72774 100644 --- a/SDL/SDLGLGraphicsContext.h +++ b/SDL/SDLGLGraphicsContext.h @@ -1,6 +1,4 @@ -#if !defined(__APPLE__) #include "SDL_syswm.h" -#endif #include "SDL.h" #include "thin3d/GLRenderManager.h" diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 90db5d4195..ee12c75442 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -35,9 +35,7 @@ SDLJoystick *joystick = NULL; #include "thread/threadutil.h" #include "math.h" -#if !defined(__APPLE__) #include "SDL_syswm.h" -#endif #if defined(VK_USE_PLATFORM_XLIB_KHR) #include @@ -66,6 +64,7 @@ static int g_QuitRequested = 0; static int g_DesktopWidth = 0; static int g_DesktopHeight = 0; +static int g_RefreshRate = 60000; int getDisplayNumber(void) { int displayNumber = 0; @@ -308,13 +307,15 @@ int System_GetPropertyInt(SystemProperty prop) { case SYSPROP_AUDIO_SAMPLE_RATE: return 44100; case SYSPROP_DISPLAY_REFRESH_RATE: - return 60000; + return g_RefreshRate; case SYSPROP_DEVICE_TYPE: #if defined(MOBILE_DEVICE) return DEVICE_TYPE_MOBILE; #else return DEVICE_TYPE_DESKTOP; #endif + case SYSPROP_DISPLAY_COUNT: + return SDL_GetNumVideoDisplays(); default: return -1; } @@ -509,6 +510,7 @@ int main(int argc, char *argv[]) { } g_DesktopWidth = displayMode.w; g_DesktopHeight = displayMode.h; + g_RefreshRate = (int)(displayMode.refresh_rate * 1000); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); diff --git a/SDL/SDLVulkanGraphicsContext.cpp b/SDL/SDLVulkanGraphicsContext.cpp index 3cf55a78c5..29d68ffc04 100644 --- a/SDL/SDLVulkanGraphicsContext.cpp +++ b/SDL/SDLVulkanGraphicsContext.cpp @@ -8,6 +8,9 @@ #include "Core/System.h" #include "SDLVulkanGraphicsContext.h" +#if defined(VK_USE_PLATFORM_METAL_EXT) +#include "SDLCocoaMetalLayer.h" +#endif 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); @@ -50,7 +53,6 @@ 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)) { @@ -71,13 +73,17 @@ bool SDLVulkanGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, case SDL_SYSWM_WAYLAND: vulkan_->InitSurface(WINDOWSYSTEM_WAYLAND, (void*)sys_info.info.wl.display, (void *)sys_info.info.wl.surface); break; +#endif +#if defined(VK_USE_PLATFORM_METAL_EXT) + case SDL_SYSWM_COCOA: + vulkan_->InitSurface(WINDOWSYSTEM_METAL_EXT, makeWindowMetalCompatible(sys_info.info.cocoa.window), nullptr); + break; #endif default: fprintf(stderr, "Vulkan subsystem %d not supported\n", sys_info.subsystem); exit(1); break; } -#endif if (!vulkan_->InitObjects()) { *error_message = vulkan_->InitError(); diff --git a/SDL/SDLVulkanGraphicsContext.h b/SDL/SDLVulkanGraphicsContext.h index 5a29e6c3df..6ecfecfe1e 100644 --- a/SDL/SDLVulkanGraphicsContext.h +++ b/SDL/SDLVulkanGraphicsContext.h @@ -1,7 +1,5 @@ #include "SDL.h" -#if !defined(__APPLE__) #include "SDL_syswm.h" -#endif #include "Common/GraphicsContext.h" #include "Common/Vulkan/VulkanContext.h"