From c452b43ebccfcab3f59fcc7afd2bd9f7a0c31084 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 17 Aug 2018 21:13:25 -0400 Subject: [PATCH] Basic support for Vulkan Portability on OSX --- Utilities/types.h | 4 ++ rpcs3/CMakeLists.txt | 7 +-- rpcs3/Emu/RSX/GSRender.h | 4 ++ rpcs3/Emu/RSX/VK/VKGSRender.cpp | 6 +-- rpcs3/Emu/RSX/VK/VKGSRender.h | 2 +- rpcs3/Emu/RSX/VK/VKHelpers.h | 84 +++++++++++++++++++++++++-------- rpcs3/Emu/RSX/VK/VulkanAPI.h | 4 +- rpcs3/rpcs3qt/gs_frame.cpp | 8 +++- 8 files changed, 90 insertions(+), 29 deletions(-) diff --git a/Utilities/types.h b/Utilities/types.h index 65be18d813..436b1d2ff1 100644 --- a/Utilities/types.h +++ b/Utilities/types.h @@ -73,7 +73,11 @@ using ulong = unsigned long; using ullong = unsigned long long; using llong = long long; +#if __APPLE__ +using uptr = std::uint64_t; +#else using uptr = std::uintptr_t; +#endif using u8 = std::uint8_t; using u16 = std::uint16_t; diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index 893bcbf5f7..ebf885d2d7 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -256,10 +256,11 @@ if(USE_LIBEVDEV) endif() endif() option(USE_VULKAN "Vulkan render backend" ON) -if(NOT APPLE AND USE_VULKAN) +if(USE_VULKAN) find_package(Vulkan) if(VULKAN_FOUND) add_definitions(-DHAVE_VULKAN) + include_directories("${Vulkan_INCLUDE_DIRS}") else() message("WARNING! USE_VULKAN was enabled, but libvulkan was not found. RPCS3 will be compiled without Vulkan support.") endif() @@ -388,7 +389,7 @@ if(NOT MSVC) target_link_libraries(rpcs3 Threads::Threads) endif() -if(UNIX) +if(NOT APPLE AND UNIX) find_package(X11 REQUIRED) target_include_directories(rpcs3 PUBLIC ${X11_INCLUDE_DIR}) target_link_libraries(rpcs3 ${X11_LIBRARIES}) @@ -438,7 +439,7 @@ else() if(CMAKE_SYSTEM MATCHES "Linux") target_link_libraries(rpcs3 "${RPCS3_SRC_DIR}/../3rdparty/discord-rpc/lib/libdiscord-rpc-linux.a") elseif(APPLE) - target_link_libraries(rpcs3 "${RPCS3_SRC_DIR}/../3rdparty/discord-rpc/lib/libdiscord-rpc-mac.a") + target_link_libraries(rpcs3 "${RPCS3_SRC_DIR}/../3rdparty/discord-rpc/lib/libdiscord-rpc-mac.a" objc "-framework Foundation" "-framework CoreServices") endif() endif() diff --git a/rpcs3/Emu/RSX/GSRender.h b/rpcs3/Emu/RSX/GSRender.h index bc26d61072..1a0653a1da 100644 --- a/rpcs3/Emu/RSX/GSRender.h +++ b/rpcs3/Emu/RSX/GSRender.h @@ -5,6 +5,8 @@ #ifdef _WIN32 #include +#elif defined(__APPLE__) +// nothing #else // Cannot include Xlib.h before Qt5 // and we don't need all of Xlib anyway @@ -49,6 +51,8 @@ using draw_context_t = void*; #ifdef _WIN32 using display_handle_t = HWND; +#elif defined(__APPLE__) + using display_handle_t = void*; // NSView #else using display_handle_t = std::variant< std::pair diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.cpp b/rpcs3/Emu/RSX/VK/VKGSRender.cpp index 7ad70d64e0..18bcc2eaef 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.cpp +++ b/rpcs3/Emu/RSX/VK/VKGSRender.cpp @@ -516,7 +516,7 @@ VKGSRender::VKGSRender() : GSRender() display_handle_t display = m_frame->handle(); -#ifndef _WIN32 +#if !defined(_WIN32) && !defined(__APPLE__) display.match([this](std::pair p) { m_display_handle = p.first; XFlush(m_display_handle); }, [](auto _) {}); #endif @@ -776,7 +776,7 @@ VKGSRender::~VKGSRender() m_swapchain->destroy(); m_thread_context.close(); -#if !defined(_WIN32) && defined(HAVE_VULKAN) +#if !defined(_WIN32) && !defined(__APPLE__) && defined(HAVE_VULKAN) if (m_display_handle) XCloseDisplay(m_display_handle); #endif @@ -3265,4 +3265,4 @@ void VKGSRender::discard_occlusion_query(rsx::reports::occlusion_query_info* que bool VKGSRender::on_decompiler_task() { return m_prog_buffer->async_update(8, *m_device, pipeline_layout).first; -} \ No newline at end of file +} diff --git a/rpcs3/Emu/RSX/VK/VKGSRender.h b/rpcs3/Emu/RSX/VK/VKGSRender.h index 4635a301a2..9e7a14cab5 100644 --- a/rpcs3/Emu/RSX/VK/VKGSRender.h +++ b/rpcs3/Emu/RSX/VK/VKGSRender.h @@ -375,7 +375,7 @@ private: //Vertex layout rsx::vertex_input_layout m_vertex_layout; -#if !defined(_WIN32) && defined(HAVE_VULKAN) +#if !defined(_WIN32) && !defined(__APPLE__) && defined(HAVE_VULKAN) Display *m_display_handle = nullptr; #endif diff --git a/rpcs3/Emu/RSX/VK/VKHelpers.h b/rpcs3/Emu/RSX/VK/VKHelpers.h index 0e5a55e91c..3704f2c8e0 100644 --- a/rpcs3/Emu/RSX/VK/VKHelpers.h +++ b/rpcs3/Emu/RSX/VK/VKHelpers.h @@ -9,6 +9,10 @@ #include #include +#if !defined(_WIN32) && !defined(__APPLE__) +#include +#endif + #include "Utilities/variant.hpp" #include "Emu/RSX/GSRender.h" #include "Emu/System.h" @@ -21,10 +25,6 @@ #include "3rdparty/GPUOpen/include/vk_mem_alloc.h" -#ifndef _WIN32 -#include -#endif - #ifdef __APPLE__ #define VK_DISABLE_COMPONENT_SWIZZLE 1 #else @@ -1502,6 +1502,52 @@ public: src.first = false; return VK_SUCCESS; } +#elif defined(__APPLE__) + + class swapchain_MacOS : public native_swapchain_base + { + void* nsView = NULL; + + public: + swapchain_MacOS(physical_device &gpu, uint32_t _present_queue, uint32_t _graphics_queue, VkFormat format = VK_FORMAT_B8G8R8A8_UNORM) + : native_swapchain_base(gpu, _present_queue, _graphics_queue, format) + {} + + ~swapchain_MacOS(){} + + bool init() override + { + //TODO: get from `nsView` + m_width = 0; + m_height = 0; + + if (m_width == 0 || m_height == 0) + { + LOG_ERROR(RSX, "Invalid window dimensions %d x %d", m_width, m_height); + return false; + } + + init_swapchain_images(dev, 3); + return true; + } + + void create(display_handle_t& window_handle) override + { + nsView = window_handle; + } + + void destroy(bool full=true) override + { + swapchain_images.clear(); + + if (full) + dev.destroy(); + } + + VkResult present(u32 index) override + { + fmt::throw_exception("Native macOS swapchain is not implemented yet!"); + } #else class swapchain_X11 : public native_swapchain_base @@ -1991,15 +2037,20 @@ public: std::vector extensions; std::vector layers; -#ifndef __APPLE__ if (!fast) { + supported_extensions support; + extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); - extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + if (support.is_supported(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)) + { + extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); + } #ifdef _WIN32 extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); +#elif defined(__APPLE__) + extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); #else - supported_extensions support; bool found_surface_ext = false; if (support.is_supported(VK_KHR_XLIB_SURFACE_EXTENSION_NAME)) { @@ -2018,11 +2069,10 @@ public: LOG_ERROR(RSX, "Could not find a supported Vulkan surface extension"); return 0; } -#endif //(WIN32) +#endif //(WIN32, __APPLE__) if (g_cfg.video.debug_output) layers.push_back("VK_LAYER_LUNARG_standard_validation"); } -#endif //(!APPLE) VkInstanceCreateInfo instance_info = {}; instance_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; @@ -2095,6 +2145,7 @@ public: swapchain_base* createSwapChain(display_handle_t window_handle, vk::physical_device &dev) { + VkSurfaceKHR surface; #ifdef _WIN32 using swapchain_NATIVE = swapchain_WIN32; HINSTANCE hInstance = NULL; @@ -2104,16 +2155,17 @@ public: createInfo.hinstance = hInstance; createInfo.hwnd = window_handle; - VkSurfaceKHR surface; CHECK_RESULT(vkCreateWin32SurfaceKHR(m_instance, &createInfo, NULL, &surface)); #elif defined(__APPLE__) - using swapchain_NATIVE = swapchain_X11; - VkSurfaceKHR surface; + using swapchain_NATIVE = swapchain_MacOS; + VkMacOSSurfaceCreateInfoMVK createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK; + createInfo.pView = window_handle; + CHECK_RESULT(vkCreateMacOSSurfaceMVK(m_instance, &createInfo, NULL, &surface)); #else using swapchain_NATIVE = swapchain_X11; - VkSurfaceKHR surface; window_handle.match( [&](std::pair p) @@ -2141,7 +2193,6 @@ public: std::vector supportsPresent(device_queues, VK_FALSE); bool present_possible = false; -#ifndef __APPLE__ for (u32 index = 0; index < device_queues; index++) { vkGetPhysicalDeviceSurfaceSupportKHR(dev, index, surface, &supportsPresent[index]); @@ -2160,7 +2211,6 @@ public: { LOG_ERROR(RSX, "It is not possible for the currently selected GPU to present to the window (Likely caused by NVIDIA driver running the current display)"); } -#endif // Search for a graphics and a present queue in the array of queue // families, try to find one that supports both @@ -2219,10 +2269,6 @@ public: return swapchain; } -#ifdef __APPLE__ - fmt::throw_exception("Unreachable" HERE); -#endif - // Get the list of VkFormat's that are supported: uint32_t formatCount; CHECK_RESULT(vkGetPhysicalDeviceSurfaceFormatsKHR(dev, surface, &formatCount, nullptr)); diff --git a/rpcs3/Emu/RSX/VK/VulkanAPI.h b/rpcs3/Emu/RSX/VK/VulkanAPI.h index 2b3b03a9eb..235f5061e3 100644 --- a/rpcs3/Emu/RSX/VK/VulkanAPI.h +++ b/rpcs3/Emu/RSX/VK/VulkanAPI.h @@ -2,7 +2,9 @@ #ifdef _WIN32 #define VK_USE_PLATFORM_WIN32_KHR -#elif !defined __APPLE__ +#elif defined(__APPLE__) +#define VK_USE_PLATFORM_MACOS_MVK +#else #define VK_USE_PLATFORM_XLIB_KHR #endif diff --git a/rpcs3/rpcs3qt/gs_frame.cpp b/rpcs3/rpcs3qt/gs_frame.cpp index b422dfa9ae..7d2f48c823 100644 --- a/rpcs3/rpcs3qt/gs_frame.cpp +++ b/rpcs3/rpcs3qt/gs_frame.cpp @@ -13,6 +13,8 @@ #ifdef _WIN32 #include +#elif defined(__APPLE__) +//nothing #else #ifdef VK_USE_PLATFORM_WAYLAND_KHR #include @@ -200,6 +202,8 @@ display_handle_t gs_frame::handle() const { #ifdef _WIN32 return (HWND) this->winId(); +#elif defined(__APPLE__) + return (void*) this->winId(); //NSView #else #ifdef VK_USE_PLATFORM_WAYLAND_KHR QPlatformNativeInterface *native = QGuiApplication::platformNativeInterface(); @@ -238,7 +242,7 @@ void gs_frame::delete_context(draw_context_t ctx) int gs_frame::client_width() { -#ifdef _WIN32 +#if defined(_WIN32) || defined(__APPLE__) return size().width(); #else return size().width() * devicePixelRatio(); @@ -247,7 +251,7 @@ int gs_frame::client_width() int gs_frame::client_height() { -#ifdef _WIN32 +#if defined(_WIN32) || defined(__APPLE__) return size().height(); #else return size().height() * devicePixelRatio();