mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-24 18:16:55 +01:00
Initial implementation of macOS Vulkan renderer over MoltenVK (#124)
This commit is contained in:
parent
15b71c57dd
commit
527ee3aea5
@ -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()
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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>")
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ enum class GfxVendor
|
|||||||
IntelNoLegacy,
|
IntelNoLegacy,
|
||||||
Intel,
|
Intel,
|
||||||
Nvidia,
|
Nvidia,
|
||||||
|
Apple,
|
||||||
Mesa,
|
Mesa,
|
||||||
|
|
||||||
MAX
|
MAX
|
||||||
|
9
src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.h
Normal file
9
src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if BOOST_OS_MACOS
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
VkSurfaceKHR CreateCocoaSurface(VkInstance instance, void* handle);
|
||||||
|
|
||||||
|
#endif
|
45
src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm
Normal file
45
src/Cafe/HW/Latte/Renderer/Vulkan/CocoaSurface.mm
Normal 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;
|
||||||
|
}
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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{};
|
||||||
|
Loading…
Reference in New Issue
Block a user