mac: Migrate to KosmicKrisp (#4566)

This commit is contained in:
squidbus 2026-06-13 04:22:09 -07:00 committed by GitHub
parent 8c4e3926bb
commit 3590426ab8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 44 additions and 129 deletions

View File

@ -233,8 +233,9 @@ jobs:
run: |
mkdir upload
mv ${{github.workspace}}/build/shadps4 upload
mv ${{github.workspace}}/build/MoltenVK_icd.json upload
mv ${{github.workspace}}/build/libMoltenVK.dylib upload
mv ${{github.workspace}}/build/libvulkan.dylib upload
mv ${{github.workspace}}/build/libvulkan_kosmickrisp.dylib upload
mv ${{github.workspace}}/build/kosmickrisp_mesa_icd.json upload
- uses: actions/upload-artifact@v7
with:
name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}

7
.gitmodules vendored
View File

@ -99,10 +99,6 @@
url = https://github.com/shadps4-emu/ext-wepoll.git
shallow = true
branch = dist
[submodule "externals/MoltenVK"]
path = externals/MoltenVK
url = https://github.com/shadPS4-emu/ext-MoltenVK.git
shallow = true
[submodule "externals/json"]
path = externals/json
url = https://github.com/nlohmann/json.git
@ -151,3 +147,6 @@
[submodule "externals/miniupnp"]
path = externals/miniupnp
url = https://github.com/miniupnp/miniupnp.git
[submodule "externals/mesa-kosmickrisp"]
path = externals/mesa-kosmickrisp
url = https://github.com/shadexternals/mesa-kosmickrisp

View File

@ -9,8 +9,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
if(APPLE)
list(APPEND ADDITIONAL_LANGUAGES OBJC)
# Starting with 15.4, Rosetta 2 has support for all the necessary instruction sets.
set(CMAKE_OSX_DEPLOYMENT_TARGET 15.4 CACHE STRING "")
# Minimum OS version for KosmicKrisp
set(CMAKE_OSX_DEPLOYMENT_TARGET 26.0 CACHE STRING "")
endif()
if (NOT CMAKE_BUILD_TYPE)
@ -246,7 +246,7 @@ find_package(SDL3 3.1.2 CONFIG)
find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG)
find_package(VulkanHeaders 1.4.329 CONFIG)
find_package(VulkanHeaders 1.4.330 CONFIG)
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
find_package(xbyak 7.07 CONFIG)
find_package(xxHash 0.8.2 MODULE)
@ -1216,25 +1216,10 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
endif()
if (APPLE)
# Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
# Bundle Vulkan loader and KosmicKrisp driver with the emulator.
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path")
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/MoltenVK/libMoltenVK.dylib)
set(MVK_DYLIB_DST ${MVK_DST}/libMoltenVK.dylib)
set(MVK_ICD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK/icd/MoltenVK_icd.json)
set(MVK_ICD_DST ${MVK_DST}/MoltenVK_icd.json)
add_custom_command(
OUTPUT ${MVK_ICD_DST}
DEPENDS ${MVK_ICD_SRC} ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E copy ${MVK_ICD_SRC} ${MVK_ICD_DST})
add_custom_command(
OUTPUT ${MVK_DYLIB_DST}
DEPENDS ${MVK_DYLIB_SRC} ${MVK_DST}
COMMAND ${CMAKE_COMMAND} -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST})
add_custom_target(CopyMoltenVK DEPENDS ${MVK_ICD_DST} ${MVK_DYLIB_DST})
add_dependencies(CopyMoltenVK MoltenVK)
add_dependencies(shadps4 CopyMoltenVK)
add_subdirectory(externals/mesa-kosmickrisp)
AddCopyKosmicKrisp(shadps4 ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR})
if (ARCHITECTURE STREQUAL "x86_64")
# Reserve system-managed memory space.

View File

@ -76,7 +76,7 @@ Check the build instructions for [**Linux**](https://github.com/shadps4-emu/shad
Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-macos.md).
> [!IMPORTANT]
> macOS users need at least macOS 15.4 to run shadPS4. Due to GPU issues there are currently heavy bugs on Intel Macs.
> macOS users need at least macOS 26.0 to run shadPS4. Intel Macs are not supported.
# Usage examples

View File

@ -21,7 +21,6 @@ path = [
"documents/Screenshots/*",
"documents/Screenshots/Linux/*",
"documents/Screenshots/Windows/*",
"externals/MoltenVK/MoltenVK_icd.json",
"flake.lock",
"scripts/ps4_names.txt",
"src/images/bronze.png",

View File

@ -7,7 +7,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
### Install the necessary tools to build shadPS4:
First, make sure you have **Xcode 16.0 or newer** installed.
First, make sure you have **Xcode 26.0 or newer** installed.
For installing other tools and library dependencies we will be using [Homebrew](https://brew.sh/).

View File

@ -260,16 +260,6 @@ if (APPLE OR ${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
endif()
endif()
# Apple-only dependencies
if (APPLE)
# MoltenVK
if (NOT TARGET MoltenVK)
set(MVK_EXCLUDE_SPIRV_TOOLS ON)
set(MVK_USE_METAL_PRIVATE_API ON)
add_subdirectory(MoltenVK)
endif()
endif()
#windows only
if (WIN32)
add_subdirectory(ext-wepoll)

1
externals/MoltenVK vendored

@ -1 +0,0 @@
Subproject commit a14cbf433414aa95da7046694b069f0f3f9263a5

1
externals/mesa-kosmickrisp vendored Submodule

@ -0,0 +1 @@
Subproject commit 801e2de8ef2e3e89fd7ee1da52d67a1294ad6135

@ -1 +1 @@
Subproject commit 33d7f512583b8de44d1b6384aa1cf482f92e53e9
Subproject commit ee3b5caaa7e372715873c7b9c390ee1c3ca5db25

View File

@ -9,28 +9,44 @@
#include <CLI/CLI.hpp>
#include <SDL3/SDL_messagebox.h>
#include <core/emulator_settings.h>
#include <core/emulator_state.h>
#include "common/arch.h"
#include "common/key_manager.h"
#include "common/logging/log.h"
#include "common/memory_patcher.h"
#include "common/path_util.h"
#include "core/debugger.h"
#include "core/emulator_settings.h"
#include "core/emulator_state.h"
#include "core/file_sys/fs.h"
#include "core/ipc/ipc.h"
#include "core/user_settings.h"
#include "emulator.h"
#include "imgui/big_picture/big_picture.h"
#ifdef _WIN32
#include <windows.h>
#elif defined(__APPLE__)
#include <sys/sysctl.h>
#endif
#include <core/user_settings.h>
int main(int argc, char* argv[]) {
#ifdef _WIN32
SetConsoleOutputCP(CP_UTF8);
#endif
#if defined(__APPLE__) && defined(ARCH_X86_64)
// KosmicKrisp only supports Apple Silicon. Check that we are not running on an Intel Mac.
int sysctl_ret = 0;
size_t sysctl_size = sizeof(sysctl_ret);
sysctlbyname("sysctl.proc_translated", &sysctl_ret, &sysctl_size, nullptr, 0);
if (sysctl_ret != 1) {
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "shadPS4",
"shadPS4 only supports Apple Silicon Macs.", nullptr);
std::cout << "shadPS4 only supports Apple Silicon Macs." << std::endl;
return -1;
}
#endif
CLI::App app{"shadPS4 Emulator CLI"};
// ---- CLI state ----

View File

@ -100,8 +100,7 @@ void Translator::V_INTERP_MOV_F32(const GcnInst& inst) {
auto& interp = info.fs_interpolation[attr_index];
ASSERT(attr.is_flat || inst.src[0].code == 2);
if (profile.supports_amd_shader_explicit_vertex_parameter ||
(profile.supports_fragment_shader_barycentric &&
!profile.has_incomplete_fragment_shader_barycentric)) {
profile.supports_fragment_shader_barycentric) {
// VSRC 0=P10, 1=P20, 2=P0
interp.primary = Qualifier::PerVertex;
SetDst(inst.dst[0],

View File

@ -44,7 +44,6 @@ struct Profile {
bool supports_workgroup_explicit_memory_layout{};
bool supports_amd_shader_explicit_vertex_parameter{};
bool supports_fragment_shader_barycentric{};
bool has_incomplete_fragment_shader_barycentric{};
bool has_broken_spirv_clamp{};
bool lower_left_origin_mode{};
bool needs_manual_interpolation{};

View File

@ -201,7 +201,6 @@ bool Instance::CreateDevice() {
vk::PhysicalDeviceRobustness2FeaturesEXT,
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT,
vk::PhysicalDevicePrimitiveTopologyListRestartFeaturesEXT,
vk::PhysicalDevicePortabilitySubsetFeaturesKHR,
vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT,
vk::PhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR,
vk::PhysicalDeviceImage2DViewOf3DFeaturesEXT>();
@ -335,21 +334,10 @@ bool Instance::CreateDevice() {
LOG_INFO(Render_Vulkan, "- sampler2DViewOf3D: {}",
image_2d_view_of_3d_features.sampler2DViewOf3D);
}
supports_memory_budget = add_extension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
const bool calibrated_timestamps =
TRACY_GPU_ENABLED ? add_extension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME) : false;
#ifdef __APPLE__
if (driver_id == vk::DriverId::eMoltenvk) {
portability_subset = add_extension(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME);
if (portability_subset) {
portability_features =
feature_chain.get<vk::PhysicalDevicePortabilitySubsetFeaturesKHR>();
}
}
#endif
supports_memory_budget = add_extension(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME);
const auto family_properties = physical_device.getQueueFamilyProperties();
if (family_properties.empty()) {
LOG_CRITICAL(Render_Vulkan, "Physical device reported no queues.");
@ -514,27 +502,6 @@ bool Instance::CreateDevice() {
.image2DViewOf3D = image_2d_view_of_3d_features.image2DViewOf3D,
.sampler2DViewOf3D = image_2d_view_of_3d_features.sampler2DViewOf3D,
},
#ifdef __APPLE__
vk::PhysicalDevicePortabilitySubsetFeaturesKHR{
.constantAlphaColorBlendFactors = portability_features.constantAlphaColorBlendFactors,
.events = portability_features.events,
.imageViewFormatReinterpretation = portability_features.imageViewFormatReinterpretation,
.imageViewFormatSwizzle = portability_features.imageViewFormatSwizzle,
.imageView2DOn3DImage = portability_features.imageView2DOn3DImage,
.multisampleArrayImage = portability_features.multisampleArrayImage,
.mutableComparisonSamplers = portability_features.mutableComparisonSamplers,
.pointPolygons = portability_features.pointPolygons,
.samplerMipLodBias = portability_features.samplerMipLodBias,
.separateStencilMaskRef = portability_features.separateStencilMaskRef,
.shaderSampleRateInterpolationFunctions =
portability_features.shaderSampleRateInterpolationFunctions,
.tessellationIsolines = portability_features.tessellationIsolines,
.tessellationPointMode = portability_features.tessellationPointMode,
.triangleFans = portability_features.triangleFans,
.vertexAttributeAccessBeyondStride =
portability_features.vertexAttributeAccessBeyondStride,
},
#endif
};
if (!custom_border_color) {

View File

@ -270,16 +270,6 @@ public:
return features.tessellationShader;
}
/// Returns true when tessellation isolines are supported by the device
bool IsTessellationIsolinesSupported() const {
return !portability_subset || portability_features.tessellationIsolines;
}
/// Returns true when tessellation point mode is supported by the device
bool IsTessellationPointModeSupported() const {
return !portability_subset || portability_features.tessellationPointMode;
}
/// Returns the vendor ID of the physical device
u32 GetVendorID() const {
return properties.vendorID;
@ -483,7 +473,6 @@ private:
vk::PhysicalDeviceFeatures features;
vk::PhysicalDeviceVulkan12Features vk12_features;
vk::PhysicalDeviceVulkan13Features vk13_features;
vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features;
vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT dynamic_state_3_features;
vk::PhysicalDeviceRobustness2FeaturesEXT robustness2_features;
vk::PhysicalDeviceShaderAtomicFloat2FeaturesEXT shader_atomic_float2_features;
@ -523,7 +512,6 @@ private:
bool shader_atomic_float{};
bool shader_atomic_float2{};
bool workgroup_memory_explicit_layout{};
bool portability_subset{};
bool maintenance_8{};
bool attachment_feedback_loop{};
bool image_2d_view_of_3d{};

View File

@ -298,15 +298,12 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
.supports_amd_shader_explicit_vertex_parameter =
instance_.IsAmdShaderExplicitVertexParameterSupported(),
.supports_fragment_shader_barycentric = instance_.IsFragmentShaderBarycentricSupported(),
.has_incomplete_fragment_shader_barycentric =
instance_.IsFragmentShaderBarycentricSupported() &&
instance.GetDriverID() == vk::DriverId::eMoltenvk,
.needs_manual_interpolation = instance.IsFragmentShaderBarycentricSupported() &&
instance.GetDriverID() == vk::DriverId::eNvidiaProprietary,
.needs_lds_barriers = instance.GetDriverID() == vk::DriverId::eNvidiaProprietary ||
instance.GetDriverID() == vk::DriverId::eMoltenvk,
instance.GetDriverID() == vk::DriverId::eMesaKosmickrisp,
.needs_buffer_offsets = instance.StorageMinAlignment() > 4,
.needs_unorm_fixup = instance.GetDriverID() == vk::DriverId::eMoltenvk,
.needs_unorm_fixup = instance.GetDriverID() == vk::DriverId::eMesaKosmickrisp,
.needs_clip_distance_emulation = instance.GetDriverID() == vk::DriverId::eNvidiaProprietary,
.supports_shader_stencil_export = instance_.IsShaderStencilExportSupported(),
};
@ -532,9 +529,7 @@ bool PipelineCache::RefreshGraphicsStages() {
}
break;
case AmdGpu::ShaderStageEnable::VgtStages::LsHs:
if (!instance.IsTessellationSupported() ||
(regs.tess_config.type == AmdGpu::TessellationType::Isoline &&
!instance.IsTessellationIsolinesSupported())) {
if (!instance.IsTessellationSupported()) {
return false;
}
if (!bind_stage(Stage::Hull, LogicalStage::TessellationControl)) {
@ -548,9 +543,7 @@ bool PipelineCache::RefreshGraphicsStages() {
}
break;
case AmdGpu::ShaderStageEnable::VgtStages::LsHsEsGs:
if (!instance.IsTessellationSupported() ||
(regs.tess_config.type == AmdGpu::TessellationType::Isoline &&
!instance.IsTessellationIsolinesSupported())) {
if (!instance.IsTessellationSupported()) {
return false;
}
if (!instance.IsGeometryStageSupported()) {

View File

@ -192,10 +192,6 @@ std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window
break;
}
#ifdef __APPLE__
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
#endif
if (window_type != Frontend::WindowSystemType::Headless) {
extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME);
}
@ -262,14 +258,14 @@ vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool e
bool enable_crash_diagnostic) {
LOG_INFO(Render_Vulkan, "Creating vulkan instance");
#if defined(__APPLE__) && !defined(ENABLE_QT_GUI)
// Initialize the environment with the path to the MoltenVK ICD, so that the loader will
#if defined(__APPLE__)
// Initialize the environment with the path to the included ICD, so that the loader will
// find it.
static const auto icd_path = [] {
char path[PATH_MAX];
u32 length = PATH_MAX;
_NSGetExecutablePath(path, &length);
return std::filesystem::path(path).parent_path() / "MoltenVK_icd.json";
return std::filesystem::path(path).parent_path();
}();
setenv("VK_DRIVER_FILES", icd_path.c_str(), true);
#endif
@ -315,9 +311,6 @@ vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool e
Common::FS::GetUserPathString(Common::FS::PathType::LogDir);
const char* log_path = crash_diagnostic_path.c_str();
vk::Bool32 enable_force_barriers = vk::True;
#ifdef __APPLE__
const vk::Bool32 mvk_debug_mode = enable_crash_diagnostic ? vk::True : vk::False;
#endif
const std::array layer_setings = {
vk::LayerSettingEXT{
@ -404,24 +397,10 @@ vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool e
.valueCount = 1,
.pValues = &enable_force_barriers,
},
#ifdef __APPLE__
// MoltenVK debug mode turns on additional device loss error details, so
// use the crash diagnostic setting as an indicator of whether to turn it on.
vk::LayerSettingEXT{
.pLayerName = "MoltenVK",
.pSettingName = "MVK_CONFIG_DEBUG",
.type = vk::LayerSettingTypeEXT::eBool32,
.valueCount = 1,
.pValues = &mvk_debug_mode,
},
#endif
};
vk::StructureChain<vk::InstanceCreateInfo, vk::LayerSettingsCreateInfoEXT> instance_ci_chain = {
vk::InstanceCreateInfo{
#ifdef __APPLE__
.flags = vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR,
#endif
.pApplicationInfo = &application_info,
.enabledLayerCount = static_cast<u32>(layers.size()),
.ppEnabledLayerNames = layers.data(),