Initial implementation of macOS Vulkan renderer over MoltenVK (#124)

This commit is contained in:
Marcin Chojnacki 2022-08-30 19:02:56 +02:00 committed by GitHub
parent 15b71c57dd
commit 527ee3aea5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 103 additions and 11 deletions

View File

@ -89,7 +89,7 @@ if (NOT TARGET glslang::SPIRV AND TARGET SPIRV)
add_library(glslang::SPIRV ALIAS SPIRV) add_library(glslang::SPIRV ALIAS SPIRV)
endif() endif()
if (UNIX) if (UNIX AND NOT APPLE)
find_package(X11 REQUIRED) find_package(X11 REQUIRED)
endif() endif()

View File

@ -20,7 +20,11 @@ if(MSVC)
# _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING # _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
# _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS # _SILENCE_ALL_CXX17_DEPRECATION_WARNINGS
elseif(UNIX) elseif(UNIX)
if(NOT APPLE) if(APPLE)
add_definitions(-D_XOPEN_SOURCE)
add_definitions(-DVK_USE_PLATFORM_MACOS_MVK)
add_definitions(-DVK_USE_PLATFORM_METAL_EXT)
else()
add_definitions(-DVK_USE_PLATFORM_XLIB_KHR) # legacy. Do we need to support XLIB surfaces? add_definitions(-DVK_USE_PLATFORM_XLIB_KHR) # legacy. Do we need to support XLIB surfaces?
add_definitions(-DVK_USE_PLATFORM_XCB_KHR) add_definitions(-DVK_USE_PLATFORM_XCB_KHR)
endif() endif()

View File

@ -6,7 +6,13 @@ endif()
file(GLOB_RECURSE CPP_FILES *.cpp) file(GLOB_RECURSE CPP_FILES *.cpp)
file(GLOB_RECURSE H_FILES *.h) file(GLOB_RECURSE H_FILES *.h)
add_library(CemuCafe ${CPP_FILES} ${H_FILES})
if(APPLE)
file(GLOB_RECURSE MM_FILES *.mm)
add_library(CemuCafe ${CPP_FILES} ${MM_FILES} ${H_FILES})
else()
add_library(CemuCafe ${CPP_FILES} ${H_FILES})
endif()
set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") set_property(TARGET CemuCafe PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

View File

@ -182,6 +182,8 @@ GraphicPack2::GraphicPack2(std::wstring filename, IniParser& rules)
m_gfx_vendor = GfxVendor::Mesa; m_gfx_vendor = GfxVendor::Mesa;
else if (boost::iequals(*option_vendorFilter, "nvidia")) else if (boost::iequals(*option_vendorFilter, "nvidia"))
m_gfx_vendor = GfxVendor::Nvidia; m_gfx_vendor = GfxVendor::Nvidia;
else if (boost::iequals(*option_vendorFilter, "apple"))
m_gfx_vendor = GfxVendor::Apple;
else else
cemuLog_force("Unknown value '{}' for vendorFilter", *option_vendorFilter); cemuLog_force("Unknown value '{}' for vendorFilter", *option_vendorFilter);
} }

View File

@ -79,6 +79,7 @@
#define GLVENDOR_INTEL_LEGACY (3) #define GLVENDOR_INTEL_LEGACY (3)
#define GLVENDOR_INTEL_NOLEGACY (4) #define GLVENDOR_INTEL_NOLEGACY (4)
#define GLVENDOR_INTEL (5) #define GLVENDOR_INTEL (5)
#define GLVENDOR_APPLE (6)
// decompiler // decompiler

View File

@ -161,6 +161,8 @@ int Latte_ThreadEntry()
case GfxVendor::Nvidia: case GfxVendor::Nvidia:
LatteGPUState.glVendor = GLVENDOR_NVIDIA; LatteGPUState.glVendor = GLVENDOR_NVIDIA;
break; break;
case GfxVendor::Apple:
LatteGPUState.glVendor = GLVENDOR_APPLE;
default: default:
break; break;
} }

View File

@ -21,6 +21,7 @@ enum class GfxVendor
IntelNoLegacy, IntelNoLegacy,
Intel, Intel,
Nvidia, Nvidia,
Apple,
Mesa, Mesa,
MAX MAX

View File

@ -0,0 +1,9 @@
#pragma once
#if BOOST_OS_MACOS
#include <vulkan/vulkan.h>
VkSurfaceKHR CreateCocoaSurface(VkInstance instance, void* handle);
#endif

View File

@ -0,0 +1,45 @@
#include "Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
#import <Cocoa/Cocoa.h>
#import <QuartzCore/CAMetalLayer.h>
@interface MetalView : NSView
@end
@implementation MetalView
-(BOOL) wantsUpdateLayer { return YES; }
+(Class) layerClass { return [CAMetalLayer class]; }
-(CALayer*) makeBackingLayer { return [self.class.layerClass layer]; }
@end
VkSurfaceKHR CreateCocoaSurface(VkInstance instance, void* handle)
{
NSView* view = (NSView*)handle;
MetalView* childView = [[MetalView alloc] initWithFrame:view.bounds];
childView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
childView.wantsLayer = YES;
[view addSubview:childView];
VkMetalSurfaceCreateInfoEXT surface;
surface.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
surface.pNext = NULL;
surface.flags = 0;
surface.pLayer = (CAMetalLayer*)childView.layer;
VkSurfaceKHR result;
VkResult err;
if ((err = vkCreateMetalSurfaceEXT(instance, &surface, nullptr, &result)) != VK_SUCCESS)
{
forceLog_printf("Cannot create a Metal Vulkan surface: %d", (sint32)err);
throw std::runtime_error(fmt::format("Cannot create a Metal Vulkan surface: {}", err));
}
return result;
}

View File

@ -65,9 +65,13 @@ bool InitializeDeviceVulkan(VkDevice device)
void* dlopen_vulkan_loader() void* dlopen_vulkan_loader()
{ {
#if BOOST_OS_LINUX
void* vulkan_so = dlopen("libvulkan.so", RTLD_NOW); void* vulkan_so = dlopen("libvulkan.so", RTLD_NOW);
if(!vulkan_so) if(!vulkan_so)
vulkan_so = dlopen("libvulkan.so.1", RTLD_NOW); vulkan_so = dlopen("libvulkan.so.1", RTLD_NOW);
#elif BOOST_OS_MACOS
void* vulkan_so = dlopen("libMoltenVK.dylib", RTLD_NOW);
#endif
return vulkan_so; return vulkan_so;
} }

View File

@ -135,6 +135,10 @@ VKFUNC_INSTANCE(vkCreateXcbSurfaceKHR);
VKFUNC_INSTANCE(vkCreateWin32SurfaceKHR); VKFUNC_INSTANCE(vkCreateWin32SurfaceKHR);
#endif #endif
#if BOOST_OS_MACOS
VKFUNC_INSTANCE(vkCreateMetalSurfaceEXT);
#endif
VKFUNC_INSTANCE(vkDestroySurfaceKHR); VKFUNC_INSTANCE(vkDestroySurfaceKHR);
VKFUNC_DEVICE(vkCreateSwapchainKHR); VKFUNC_DEVICE(vkCreateSwapchainKHR);
VKFUNC_DEVICE(vkDestroySwapchainKHR); VKFUNC_DEVICE(vkDestroySwapchainKHR);

View File

@ -3,6 +3,7 @@
#include "Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h" #include "Cafe/HW/Latte/Renderer/Vulkan/LatteTextureVk.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h" #include "Cafe/HW/Latte/Renderer/Vulkan/RendererShaderVk.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h" #include "Cafe/HW/Latte/Renderer/Vulkan/VulkanTextureReadback.h"
#include "Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.h"
#include "Cafe/HW/Latte/Core/LatteBufferCache.h" #include "Cafe/HW/Latte/Core/LatteBufferCache.h"
#include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h" #include "Cafe/HW/Latte/Core/LattePerformanceMonitor.h"
@ -107,6 +108,8 @@ std::vector<VulkanRenderer::DeviceInfo> VulkanRenderer::GetDevices()
requiredExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); requiredExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#elif BOOST_OS_LINUX #elif BOOST_OS_LINUX
requiredExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); requiredExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
#elif BOOST_OS_MACOS
requiredExtensions.emplace_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
#endif #endif
VkApplicationInfo app_info{}; VkApplicationInfo app_info{};
@ -189,6 +192,9 @@ void VulkanRenderer::DetermineVendor()
case 0x1002: case 0x1002:
m_vendor = GfxVendor::AMD; m_vendor = GfxVendor::AMD;
break; break;
case 0x106B:
m_vendor = GfxVendor::Apple;
break;
} }
if (IsRunningInWine()) if (IsRunningInWine())
@ -402,8 +408,10 @@ VulkanRenderer::VulkanRenderer()
deviceFeatures.independentBlend = VK_TRUE; deviceFeatures.independentBlend = VK_TRUE;
deviceFeatures.samplerAnisotropy = VK_TRUE; deviceFeatures.samplerAnisotropy = VK_TRUE;
deviceFeatures.imageCubeArray = VK_TRUE; deviceFeatures.imageCubeArray = VK_TRUE;
#if !BOOST_OS_MACOS
deviceFeatures.geometryShader = VK_TRUE; deviceFeatures.geometryShader = VK_TRUE;
deviceFeatures.logicOp = VK_TRUE; deviceFeatures.logicOp = VK_TRUE;
#endif
deviceFeatures.occlusionQueryPrecise = VK_TRUE; deviceFeatures.occlusionQueryPrecise = VK_TRUE;
deviceFeatures.depthClamp = VK_TRUE; deviceFeatures.depthClamp = VK_TRUE;
deviceFeatures.depthBiasClamp = VK_TRUE; deviceFeatures.depthBiasClamp = VK_TRUE;
@ -1165,6 +1173,8 @@ std::vector<const char*> VulkanRenderer::CheckInstanceExtensionSupport(FeatureCo
requiredInstanceExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); requiredInstanceExtensions.emplace_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
#elif BOOST_OS_LINUX #elif BOOST_OS_LINUX
requiredInstanceExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); requiredInstanceExtensions.emplace_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
#elif BOOST_OS_MACOS
requiredInstanceExtensions.emplace_back(VK_EXT_METAL_SURFACE_EXTENSION_NAME);
#endif #endif
if (cafeLog_isLoggingFlagEnabled(LOG_TYPE_VULKAN_VALIDATION)) if (cafeLog_isLoggingFlagEnabled(LOG_TYPE_VULKAN_VALIDATION))
requiredInstanceExtensions.emplace_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); requiredInstanceExtensions.emplace_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME);
@ -1342,8 +1352,7 @@ VkSurfaceKHR VulkanRenderer::CreateFramebufferSurface(VkInstance instance, struc
#elif BOOST_OS_LINUX #elif BOOST_OS_LINUX
return CreateXlibSurface(instance, windowInfo.xlib_display, windowInfo.xlib_window); return CreateXlibSurface(instance, windowInfo.xlib_display, windowInfo.xlib_window);
#elif BOOST_OS_MACOS #elif BOOST_OS_MACOS
cemu_assert_unimplemented(); return CreateCocoaSurface(instance, windowInfo.handle);
return nullptr;
#endif #endif
} }

View File

@ -38,7 +38,7 @@ target_link_libraries(CemuCommon PRIVATE
glm::glm glm::glm
) )
if (UNIX) if (UNIX AND NOT APPLE)
target_link_libraries(CemuCommon PRIVATE X11::X11 X11::Xrender X11::Xutil) target_link_libraries(CemuCommon PRIVATE X11::X11 X11::Xrender X11::Xutil)
endif() endif()

View File

@ -90,6 +90,8 @@ void gui_updateWindowTitles(bool isIdle, bool isLoading, double fps)
graphicMode = "[Intel GPU]"; graphicMode = "[Intel GPU]";
else if (LatteGPUState.glVendor == GLVENDOR_NVIDIA) else if (LatteGPUState.glVendor == GLVENDOR_NVIDIA)
graphicMode = "[NVIDIA GPU]"; graphicMode = "[NVIDIA GPU]";
else if (LatteGPUState.glVendor == GLVENDOR_APPLE)
graphicMode = "[Apple GPU]";
const uint64 titleId = CafeSystem::GetForegroundTitleId(); const uint64 titleId = CafeSystem::GetForegroundTitleId();
windowText.append(fmt::format(" - FPS: {:.2f} {} {} [TitleId: {:08x}-{:08x}]", (double)fps, renderer, graphicMode, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF))); windowText.append(fmt::format(" - FPS: {:.2f} {} {} [TitleId: {:08x}-{:08x}]", (double)fps, renderer, graphicMode, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF)));
@ -197,6 +199,8 @@ void gui_initHandleContextFromWxWidgetsWindow(WindowHandleInfo& handleInfoOut, c
{ {
cemuLog_log(LogType::Force, "Unable to get xlib display"); cemuLog_log(LogType::Force, "Unable to get xlib display");
} }
#else
handleInfoOut.handle = wxw->GetHandle();
#endif #endif
} }

View File

@ -20,6 +20,8 @@ struct WindowHandleInfo
//xcb_window_t xcb_window{}; //xcb_window_t xcb_window{};
// Wayland // Wayland
// todo // todo
#else
void* handle;
#endif #endif
}; };

View File

@ -1,6 +1,5 @@
#include "Fiber.h" #include "Fiber.h"
#if BOOST_OS_LINUX || BOOST_OS_MACOS #if BOOST_OS_LINUX || BOOST_OS_MACOS
#define _XOPEN_SOURCE
#include <ucontext.h> #include <ucontext.h>
thread_local Fiber* sCurrentFiber{}; thread_local Fiber* sCurrentFiber{};