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

@ -6,7 +6,13 @@ endif()
file(GLOB_RECURSE CPP_FILES *.cpp)
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>")

View file

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

View file

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

View file

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

View file

@ -21,6 +21,7 @@ enum class GfxVendor
IntelNoLegacy,
Intel,
Nvidia,
Apple,
Mesa,
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,10 +65,14 @@ bool InitializeDeviceVulkan(VkDevice device)
void* dlopen_vulkan_loader()
{
void* vulkan_so = dlopen("libvulkan.so", RTLD_NOW);
if(!vulkan_so)
vulkan_so = dlopen("libvulkan.so.1", RTLD_NOW);
return vulkan_so;
#if BOOST_OS_LINUX
void* vulkan_so = dlopen("libvulkan.so", RTLD_NOW);
if(!vulkan_so)
vulkan_so = dlopen("libvulkan.so.1", RTLD_NOW);
#elif BOOST_OS_MACOS
void* vulkan_so = dlopen("libMoltenVK.dylib", RTLD_NOW);
#endif
return vulkan_so;
}
bool InitializeGlobalVulkan()

View file

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

View file

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