From 7801e8368b92e89c7cbc24873b2650784eba681d Mon Sep 17 00:00:00 2001 From: nastys Date: Fri, 18 Feb 2022 00:19:11 +0100 Subject: [PATCH] Add MoltenVK Semaphore setting --- .ci/build-mac.sh | 2 +- rpcs3/Emu/RSX/VK/vkutils/device.cpp | 31 +++++++++++++++++++++++++++ rpcs3/Emu/RSX/VK/vkutils/instance.hpp | 8 +++++++ rpcs3/Emu/system_config.h | 1 + rpcs3/Emu/system_config_types.cpp | 17 +++++++++++++++ rpcs3/Emu/system_config_types.h | 8 +++++++ rpcs3/rpcs3qt/emu_settings.cpp | 9 ++++++++ rpcs3/rpcs3qt/emu_settings_type.h | 2 ++ rpcs3/rpcs3qt/settings_dialog.cpp | 7 ++++++ rpcs3/rpcs3qt/settings_dialog.ui | 18 ++++++++++++++++ rpcs3/rpcs3qt/tooltips.h | 1 + 11 files changed, 103 insertions(+), 1 deletion(-) diff --git a/.ci/build-mac.sh b/.ci/build-mac.sh index 74753ecc89..4ef387cc2f 100755 --- a/.ci/build-mac.sh +++ b/.ci/build-mac.sh @@ -9,7 +9,7 @@ export Qt5_DIR="/usr/local/Cellar/qt@5/5.15.2_1/lib/cmake/Qt5" export PATH="/usr/local/opt/llvm/bin:/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin" export LDFLAGS="-L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib" export CPPFLAGS="-I/usr/local/opt/llvm/include -msse -msse2 -mcx16 -no-pie" -export CXXFLAGS="-I/usr/local/opt/llvm/include -msse -msse2 -mcx16 -no-pie" +export CPLUS_INCLUDE_PATH="/usr/local/opt/molten-vk/include" export VULKAN_SDK="/usr/local/opt/molten-vk" export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json" diff --git a/rpcs3/Emu/RSX/VK/vkutils/device.cpp b/rpcs3/Emu/RSX/VK/vkutils/device.cpp index 8978293785..6794e713a2 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/device.cpp +++ b/rpcs3/Emu/RSX/VK/vkutils/device.cpp @@ -3,6 +3,10 @@ #include "util/logs.hpp" #include "Emu/system_config.h" +#ifdef __APPLE__ +#include +#endif + namespace vk { // Global shared render device @@ -121,6 +125,33 @@ namespace vk _vkGetPhysicalDeviceProperties2KHR(dev, &properties2); props = properties2.properties; +#ifdef __APPLE__ + if (instance_extensions.is_supported(VK_MVK_MOLTENVK_EXTENSION_NAME)) + { + MVKConfiguration mvk_config = {}; + size_t mvk_config_size = sizeof(MVKConfiguration); + + PFN_vkGetMoltenVKConfigurationMVK _vkGetMoltenVKConfigurationMVK = nullptr; + _vkGetMoltenVKConfigurationMVK = reinterpret_cast(vkGetInstanceProcAddr(parent, "vkGetMoltenVKConfigurationMVK")); + ensure(_vkGetMoltenVKConfigurationMVK); + + PFN_vkSetMoltenVKConfigurationMVK _vkSetMoltenVKConfigurationMVK = nullptr; + _vkSetMoltenVKConfigurationMVK = reinterpret_cast(vkGetInstanceProcAddr(parent, "vkSetMoltenVKConfigurationMVK")); + ensure(_vkSetMoltenVKConfigurationMVK); + + CHECK_RESULT_EX(_vkGetMoltenVKConfigurationMVK(VK_NULL_HANDLE, &mvk_config, &mvk_config_size), std::string("Could not get MoltenVK configuration.")); + + mvk_config.semaphoreUseMTLEvent = (g_cfg.video.vk.metal_semaphore == vk_metal_semaphore_mode::mtlevent_preferred || g_cfg.video.vk.metal_semaphore == vk_metal_semaphore_mode::mtlevent); + mvk_config.semaphoreUseMTLFence = (g_cfg.video.vk.metal_semaphore == vk_metal_semaphore_mode::mtlevent_preferred || g_cfg.video.vk.metal_semaphore == vk_metal_semaphore_mode::mtlfence); + + CHECK_RESULT_EX(_vkSetMoltenVKConfigurationMVK(VK_NULL_HANDLE, &mvk_config, &mvk_config_size), std::string("Could not set MoltenVK configuration.")); + } + else + { + rsx_log.error("Cannot set Metal Semaphore because VK_MVK_moltenvk is not supported.\nIf you're using MoltenVK through libvulkan, manually set the MVK_ALLOW_METAL_EVENTS and/or MVK_ALLOW_METAL_FENCES environment variables instead."); + } +#endif + if (descriptor_indexing_support) { if (descriptor_indexing_props.maxUpdateAfterBindDescriptorsInAllPools < 800'000) diff --git a/rpcs3/Emu/RSX/VK/vkutils/instance.hpp b/rpcs3/Emu/RSX/VK/vkutils/instance.hpp index 4bf3ecdcef..a263498da6 100644 --- a/rpcs3/Emu/RSX/VK/vkutils/instance.hpp +++ b/rpcs3/Emu/RSX/VK/vkutils/instance.hpp @@ -150,6 +150,14 @@ namespace vk extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); } +#ifdef __APPLE__ + #define VK_MVK_MOLTENVK_EXTENSION_NAME "VK_MVK_moltenvk" + if (support.is_supported(VK_MVK_MOLTENVK_EXTENSION_NAME)) + { + extensions.push_back(VK_MVK_MOLTENVK_EXTENSION_NAME); + } +#endif + if (support.is_supported(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME)) { extensions.push_back(VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME); diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index eae614f662..bbe288c565 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -169,6 +169,7 @@ struct cfg_root : cfg::node cfg::_bool fsr_upscaling{ this, "Enable FidelityFX Super Resolution Upscaling", false, true }; cfg::uint<0, 100> rcas_sharpening_intensity{ this, "FidelityFX CAS Sharpening Intensity", 50, true }; cfg::_enum asynchronous_scheduler{ this, "Asynchronous Queue Scheduler", vk_gpu_scheduler_mode::safe }; + cfg::_enum metal_semaphore{ this, "Metal Semaphore", vk_metal_semaphore_mode::mtlevent_preferred }; } vk{ this }; diff --git a/rpcs3/Emu/system_config_types.cpp b/rpcs3/Emu/system_config_types.cpp index 47696f721a..04bf5de235 100644 --- a/rpcs3/Emu/system_config_types.cpp +++ b/rpcs3/Emu/system_config_types.cpp @@ -529,6 +529,23 @@ void fmt_class_string::format(std::string& out, u64 arg) }); } +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + format_enum(out, arg, [](vk_metal_semaphore_mode value) + { + switch (value) + { + case vk_metal_semaphore_mode::software: return "Software emulation"; + case vk_metal_semaphore_mode::mtlevent_preferred: return "MTLEvent preferred"; + case vk_metal_semaphore_mode::mtlevent: return "MTLEvent"; + case vk_metal_semaphore_mode::mtlfence: return "MTLFence"; + } + + return unknown; + }); +} + template <> void fmt_class_string::format(std::string& out, u64 arg) { diff --git a/rpcs3/Emu/system_config_types.h b/rpcs3/Emu/system_config_types.h index 6b6e2a712f..6bd4db0316 100644 --- a/rpcs3/Emu/system_config_types.h +++ b/rpcs3/Emu/system_config_types.h @@ -232,6 +232,14 @@ enum class vk_gpu_scheduler_mode fast }; +enum class vk_metal_semaphore_mode +{ + software, + mtlevent_preferred, + mtlevent, + mtlfence +}; + enum class thread_scheduler_mode { os, diff --git a/rpcs3/rpcs3qt/emu_settings.cpp b/rpcs3/rpcs3qt/emu_settings.cpp index 9ee81ef409..abcb7e924e 100644 --- a/rpcs3/rpcs3qt/emu_settings.cpp +++ b/rpcs3/rpcs3qt/emu_settings.cpp @@ -1160,6 +1160,15 @@ QString emu_settings::GetLocalizedSetting(const QString& original, emu_settings_ case vk_gpu_scheduler_mode::fast: return tr("Fast"); } break; + case emu_settings_type::MetalSemaphore: + switch (static_cast(index)) + { + case vk_metal_semaphore_mode::software: return tr("Software emulation"); + case vk_metal_semaphore_mode::mtlevent_preferred: return tr("MTLEvent preferred"); + case vk_metal_semaphore_mode::mtlevent: return tr("MTLEvent"); + case vk_metal_semaphore_mode::mtlfence: return tr("MTLFence"); + } + break; default: break; } diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index eff3d29445..c3a34eca47 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -90,6 +90,7 @@ enum class emu_settings_type DriverWakeUpDelay, VulkanAsyncTextureUploads, VulkanAsyncSchedulerDriver, + MetalSemaphore, // Performance Overlay PerfOverlayEnabled, @@ -252,6 +253,7 @@ inline static const QMap settings_location = { emu_settings_type::VulkanAsyncSchedulerDriver, { "Video", "Vulkan", "Asynchronous Queue Scheduler"}}, { emu_settings_type::FsrUpscalingEnable, { "Video", "Vulkan", "Enable FidelityFX Super Resolution Upscaling"}}, { emu_settings_type::FsrSharpeningStrength, { "Video", "Vulkan", "FidelityFX CAS Sharpening Intensity"}}, + { emu_settings_type::MetalSemaphore, { "Video", "Vulkan", "Metal Semaphore"}}, // Performance Overlay { emu_settings_type::PerfOverlayEnabled, { "Video", "Performance Overlay", "Enabled" } }, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index f11f0c410d..6b8d8e1ee6 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -1232,6 +1232,13 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceComboBox(ui->vulkansched, emu_settings_type::VulkanAsyncSchedulerDriver); SubscribeTooltip(ui->gb_vulkansched, tooltips.settings.vulkan_async_scheduler); + m_emu_settings->EnhanceComboBox(ui->metalsemaphore, emu_settings_type::MetalSemaphore); +#ifdef __APPLE__ + SubscribeTooltip(ui->gb_metalsemaphore, tooltips.settings.metal_semaphore); +#else + ui->metalsemaphore->setVisible(false); +#endif + // Sliders EnhanceSlider(emu_settings_type::DriverWakeUpDelay, ui->wakeupDelay, ui->wakeupText, tr(reinterpret_cast(u8"%0 µs"), "Driver wake up delay")); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index da26fd8aae..29de35d860 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -3904,6 +3904,24 @@ + + + + + 0 + 0 + + + + Metal Semaphore + + + + + + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index ed162f75aa..cfe542b5eb 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -107,6 +107,7 @@ public: const QString accurate_ppu_128_loop = tr("When enabled, PPU atomic operations will operate on entire cache line data, as opposed to a single 64bit block of memory when disabled.\nNumerical values control whether or not to enable the accurate version based on the atomic operation's length."); const QString enable_performance_report = tr("Measure certain events and print a chart after the emulator is stopped. Don't enable if not asked to."); const QString num_ppu_threads = tr("Affects maximum amount of PPU threads running concurrently, the value of 1 has very low compatibility with games.\n2 is the default, if unsure do not modify this setting."); + const QString metal_semaphore = tr("Determines how MoltenVK will simulate vkSemaphore on the Metal API.\nSoftware emulation is the slowest, but most accurate option. However, it can cause tearing.\nMTLEvent is faster, but not available under Rosetta (if MTLEvent preferred is selected, MTLFence is used; otherwise, emulation is used).\nMTLFence is faster than emulation, but can randomly cause synchronization issues."); // emulator