mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2024-12-26 17:37:03 +00:00
mac: Choose whether system Vulkan is needed at runtime. (#1780)
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions
Some checks are pending
Build and Release / reuse (push) Waiting to run
Build and Release / clang-format (push) Waiting to run
Build and Release / get-info (push) Waiting to run
Build and Release / windows-sdl (push) Blocked by required conditions
Build and Release / windows-qt (push) Blocked by required conditions
Build and Release / macos-sdl (push) Blocked by required conditions
Build and Release / macos-qt (push) Blocked by required conditions
Build and Release / linux-sdl (push) Blocked by required conditions
Build and Release / linux-qt (push) Blocked by required conditions
Build and Release / pre-release (push) Blocked by required conditions
This commit is contained in:
parent
aa5c1c10df
commit
87773a417b
|
@ -892,11 +892,16 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
option(USE_SYSTEM_VULKAN_LOADER "Enables using the system Vulkan loader instead of directly linking with MoltenVK. Useful for loading validation layers." OFF)
|
if (ENABLE_QT_GUI)
|
||||||
if (USE_SYSTEM_VULKAN_LOADER)
|
# Include MoltenVK in the app bundle, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
|
||||||
target_compile_definitions(shadps4 PRIVATE USE_SYSTEM_VULKAN_LOADER=1)
|
target_sources(shadps4 PRIVATE externals/MoltenVK/MoltenVK_icd.json)
|
||||||
|
set_source_files_properties(externals/MoltenVK/MoltenVK_icd.json
|
||||||
|
PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d)
|
||||||
|
add_custom_command(TARGET shadps4 POST_BUILD
|
||||||
|
COMMAND cmake -E copy $<TARGET_LINKER_FILE:MoltenVK> $<TARGET_BUNDLE_DIR:shadps4>/Contents/Frameworks/libMoltenVK.dylib)
|
||||||
|
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks")
|
||||||
else()
|
else()
|
||||||
# Link MoltenVK for Vulkan support
|
# For non-bundled SDL build, just do a normal library link.
|
||||||
target_link_libraries(shadps4 PRIVATE MoltenVK)
|
target_link_libraries(shadps4 PRIVATE MoltenVK)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ path = [
|
||||||
"documents/changelog.md",
|
"documents/changelog.md",
|
||||||
"documents/Quickstart/2.png",
|
"documents/Quickstart/2.png",
|
||||||
"documents/Screenshots/*",
|
"documents/Screenshots/*",
|
||||||
|
"externals/MoltenVK/MoltenVK_icd.json",
|
||||||
"scripts/ps4_names.txt",
|
"scripts/ps4_names.txt",
|
||||||
"src/images/about_icon.png",
|
"src/images/about_icon.png",
|
||||||
"src/images/controller_icon.png",
|
"src/images/controller_icon.png",
|
||||||
|
|
16
externals/MoltenVK/CMakeLists.txt
vendored
16
externals/MoltenVK/CMakeLists.txt
vendored
|
@ -1,17 +1,29 @@
|
||||||
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
# Prepare version information
|
# Prepare MoltenVK Git revision
|
||||||
find_package(Git)
|
find_package(Git)
|
||||||
if(GIT_FOUND)
|
if(GIT_FOUND)
|
||||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
||||||
OUTPUT_VARIABLE MVK_GIT_REV
|
OUTPUT_VARIABLE MVK_GIT_REV
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
|
||||||
ERROR_QUIET
|
ERROR_QUIET
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
endif()
|
endif()
|
||||||
set(MVK_VERSION "1.2.12")
|
|
||||||
set(MVK_GENERATED_INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/Generated)
|
set(MVK_GENERATED_INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/Generated)
|
||||||
file(WRITE ${MVK_GENERATED_INCLUDES}/mvkGitRevDerived.h "static const char* mvkRevString = \"${MVK_GIT_REV}\";")
|
file(WRITE ${MVK_GENERATED_INCLUDES}/mvkGitRevDerived.h "static const char* mvkRevString = \"${MVK_GIT_REV}\";")
|
||||||
|
message(STATUS "MoltenVK revision: ${MVK_GIT_REV}")
|
||||||
|
|
||||||
|
# Prepare MoltenVK version
|
||||||
|
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVK/MoltenVK/API/mvk_private_api.h MVK_PRIVATE_API)
|
||||||
|
string(REGEX MATCH "#define MVK_VERSION_MAJOR [0-9]+" MVK_VERSION_MAJOR_LINE "${MVK_PRIVATE_API}")
|
||||||
|
string(REGEX MATCH "[0-9]+" MVK_VERSION_MAJOR "${MVK_VERSION_MAJOR_LINE}")
|
||||||
|
string(REGEX MATCH "#define MVK_VERSION_MINOR [0-9]+" MVK_VERSION_MINOR_LINE "${MVK_PRIVATE_API}")
|
||||||
|
string(REGEX MATCH "[0-9]+" MVK_VERSION_MINOR "${MVK_VERSION_MINOR_LINE}")
|
||||||
|
string(REGEX MATCH "#define MVK_VERSION_PATCH [0-9]+" MVK_VERSION_PATCH_LINE "${MVK_PRIVATE_API}")
|
||||||
|
string(REGEX MATCH "[0-9]+" MVK_VERSION_PATCH "${MVK_VERSION_PATCH_LINE}")
|
||||||
|
set(MVK_VERSION "${MVK_VERSION_MAJOR}.${MVK_VERSION_MINOR}.${MVK_VERSION_PATCH}")
|
||||||
|
message(STATUS "MoltenVK version: ${MVK_VERSION}")
|
||||||
|
|
||||||
# Find required system libraries
|
# Find required system libraries
|
||||||
find_library(APPKIT_LIBRARY AppKit REQUIRED)
|
find_library(APPKIT_LIBRARY AppKit REQUIRED)
|
||||||
|
|
8
externals/MoltenVK/MoltenVK_icd.json
vendored
Normal file
8
externals/MoltenVK/MoltenVK_icd.json
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"file_format_version": "1.0.0",
|
||||||
|
"ICD": {
|
||||||
|
"library_path": "../../../Frameworks/libMoltenVK.dylib",
|
||||||
|
"api_version": "1.2.0",
|
||||||
|
"is_portability_driver": true
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(__APPLE__) && !USE_SYSTEM_VULKAN_LOADER
|
|
||||||
#define VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Include vulkan-hpp header
|
// Include vulkan-hpp header
|
||||||
#define VK_ENABLE_BETA_EXTENSIONS
|
#define VK_ENABLE_BETA_EXTENSIONS
|
||||||
#define VK_NO_PROTOTYPES
|
#define VK_NO_PROTOTYPES
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <fmt/ranges.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
@ -21,15 +22,6 @@
|
||||||
#include "sdl_window.h"
|
#include "sdl_window.h"
|
||||||
#include "video_core/renderer_vulkan/vk_platform.h"
|
#include "video_core/renderer_vulkan/vk_platform.h"
|
||||||
|
|
||||||
#if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
|
|
||||||
static vk::detail::DynamicLoader dl;
|
|
||||||
#else
|
|
||||||
extern "C" {
|
|
||||||
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(VkInstance instance,
|
|
||||||
const char* pName);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation";
|
static const char* const VALIDATION_LAYER_NAME = "VK_LAYER_KHRONOS_validation";
|
||||||
|
@ -199,15 +191,57 @@ std::vector<const char*> GetInstanceExtensions(Frontend::WindowSystemType window
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> GetInstanceLayers(bool enable_validation, bool enable_crash_diagnostic) {
|
||||||
|
const auto [properties_result, properties] = vk::enumerateInstanceLayerProperties();
|
||||||
|
if (properties_result != vk::Result::eSuccess || properties.empty()) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Failed to query layer properties: {}",
|
||||||
|
vk::to_string(properties_result));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const char*> layers;
|
||||||
|
layers.reserve(2);
|
||||||
|
|
||||||
|
if (enable_validation) {
|
||||||
|
layers.push_back(VALIDATION_LAYER_NAME);
|
||||||
|
}
|
||||||
|
if (enable_crash_diagnostic) {
|
||||||
|
layers.push_back(CRASH_DIAGNOSTIC_LAYER_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize layer list
|
||||||
|
std::erase_if(layers, [&](const char* layer) -> bool {
|
||||||
|
const auto it = std::ranges::find_if(properties, [layer](const auto& prop) {
|
||||||
|
return std::strcmp(layer, prop.layerName) == 0;
|
||||||
|
});
|
||||||
|
if (it == properties.end()) {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Requested layer {} is not available", layer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool enable_validation,
|
vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool enable_validation,
|
||||||
bool enable_crash_diagnostic) {
|
bool enable_crash_diagnostic) {
|
||||||
LOG_INFO(Render_Vulkan, "Creating vulkan instance");
|
LOG_INFO(Render_Vulkan, "Creating vulkan instance");
|
||||||
|
|
||||||
#if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
|
#ifdef __APPLE__
|
||||||
auto vkGetInstanceProcAddr =
|
// If the Vulkan loader exists in /usr/local/lib, give it priority. The Vulkan SDK
|
||||||
dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
|
// installs it here by default but it is not in the default library search path.
|
||||||
|
// The loader has a clause to check for it, but at a lower priority than the bundled
|
||||||
|
// libMoltenVK.dylib, so we need to handle it ourselves to give it priority.
|
||||||
|
static const std::string usr_local_path = "/usr/local/lib/libvulkan.dylib";
|
||||||
|
static vk::detail::DynamicLoader dl = std::filesystem::exists(usr_local_path)
|
||||||
|
? vk::detail::DynamicLoader(usr_local_path)
|
||||||
|
: vk::detail::DynamicLoader();
|
||||||
|
#else
|
||||||
|
static vk::detail::DynamicLoader dl;
|
||||||
#endif
|
#endif
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);
|
VULKAN_HPP_DEFAULT_DISPATCHER.init(
|
||||||
|
dl.getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"));
|
||||||
|
|
||||||
const auto [available_version_result, available_version] =
|
const auto [available_version_result, available_version] =
|
||||||
VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceVersion
|
VULKAN_HPP_DEFAULT_DISPATCHER.vkEnumerateInstanceVersion
|
||||||
|
@ -230,38 +264,25 @@ vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool e
|
||||||
.apiVersion = available_version,
|
.apiVersion = available_version,
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 num_layers = 0;
|
const auto layers = GetInstanceLayers(enable_validation, enable_crash_diagnostic);
|
||||||
std::array<const char*, 2> layers;
|
|
||||||
|
|
||||||
vk::Bool32 enable_force_barriers = vk::False;
|
const std::string extensions_string = fmt::format("{}", fmt::join(extensions, ", "));
|
||||||
const char* log_path{};
|
const std::string layers_string = fmt::format("{}", fmt::join(layers, ", "));
|
||||||
|
LOG_INFO(Render_Vulkan, "Enabled instance extensions: {}", extensions_string);
|
||||||
|
LOG_INFO(Render_Vulkan, "Enabled instance layers: {}", layers_string);
|
||||||
|
|
||||||
#if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
|
// Validation settings
|
||||||
if (enable_validation) {
|
vk::Bool32 enable_sync = Config::vkValidationSyncEnabled() ? vk::True : vk::False;
|
||||||
layers[num_layers++] = VALIDATION_LAYER_NAME;
|
vk::Bool32 enable_gpuav = Config::vkValidationSyncEnabled() ? vk::True : vk::False;
|
||||||
}
|
const char* gpuav_mode =
|
||||||
|
Config::vkValidationGpuEnabled() ? "GPU_BASED_GPU_ASSISTED" : "GPU_BASED_NONE";
|
||||||
|
|
||||||
if (enable_crash_diagnostic) {
|
// Crash diagnostics settings
|
||||||
layers[num_layers++] = CRASH_DIAGNOSTIC_LAYER_NAME;
|
static const auto crash_diagnostic_path =
|
||||||
static const auto crash_diagnostic_path =
|
Common::FS::GetUserPathString(Common::FS::PathType::LogDir);
|
||||||
Common::FS::GetUserPathString(Common::FS::PathType::LogDir);
|
const char* log_path = crash_diagnostic_path.c_str();
|
||||||
log_path = crash_diagnostic_path.c_str();
|
vk::Bool32 enable_force_barriers = vk::True;
|
||||||
enable_force_barriers = vk::True;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (enable_validation || enable_crash_diagnostic) {
|
|
||||||
LOG_WARNING(Render_Vulkan,
|
|
||||||
"Skipping loading Vulkan layers as dynamic loading is not enabled.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
vk::Bool32 enable_sync =
|
|
||||||
enable_validation && Config::vkValidationSyncEnabled() ? vk::True : vk::False;
|
|
||||||
vk::Bool32 enable_gpuav =
|
|
||||||
enable_validation && Config::vkValidationSyncEnabled() ? vk::True : vk::False;
|
|
||||||
const char* gpuav_mode = enable_validation && Config::vkValidationGpuEnabled()
|
|
||||||
? "GPU_BASED_GPU_ASSISTED"
|
|
||||||
: "GPU_BASED_NONE";
|
|
||||||
const std::array layer_setings = {
|
const std::array layer_setings = {
|
||||||
vk::LayerSettingEXT{
|
vk::LayerSettingEXT{
|
||||||
.pLayerName = VALIDATION_LAYER_NAME,
|
.pLayerName = VALIDATION_LAYER_NAME,
|
||||||
|
@ -331,7 +352,7 @@ vk::UniqueInstance CreateInstance(Frontend::WindowSystemType window_type, bool e
|
||||||
vk::StructureChain<vk::InstanceCreateInfo, vk::LayerSettingsCreateInfoEXT> instance_ci_chain = {
|
vk::StructureChain<vk::InstanceCreateInfo, vk::LayerSettingsCreateInfoEXT> instance_ci_chain = {
|
||||||
vk::InstanceCreateInfo{
|
vk::InstanceCreateInfo{
|
||||||
.pApplicationInfo = &application_info,
|
.pApplicationInfo = &application_info,
|
||||||
.enabledLayerCount = num_layers,
|
.enabledLayerCount = static_cast<u32>(layers.size()),
|
||||||
.ppEnabledLayerNames = layers.data(),
|
.ppEnabledLayerNames = layers.data(),
|
||||||
.enabledExtensionCount = static_cast<u32>(extensions.size()),
|
.enabledExtensionCount = static_cast<u32>(extensions.size()),
|
||||||
.ppEnabledExtensionNames = extensions.data(),
|
.ppEnabledExtensionNames = extensions.data(),
|
||||||
|
|
Loading…
Reference in a new issue