Add support for macOS.

This commit is contained in:
squidbus 2025-03-02 23:49:48 -08:00 committed by Isaac Marovitz
parent 8370312454
commit 5a5672d84a
No known key found for this signature in database
GPG key ID: 97250B2B09A132E1
48 changed files with 961 additions and 133 deletions

View file

@ -210,3 +210,75 @@ jobs:
with:
name: UnleashedRecomp-Flatpak
path: ./${{ env.FLATPAK_ID }}.flatpak
build-macos:
name: Build macOS
runs-on: macos-15
strategy:
matrix:
arch: [ "arm64" ]
preset: ["macos-debug", "macos-release", "macos-relwithdebinfo"]
env:
CMAKE_PRESET: ${{ matrix.preset }}
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
submodules: recursive
- name: Checkout Private Repository
uses: actions/checkout@v4
with:
repository: ${{ secrets.ASSET_REPO }}
token: ${{ secrets.ASSET_REPO_TOKEN }}
path: ./private
- name: Setup ccache
uses: hendrikmuhs/ccache-action@v1.2
with:
key: ccache-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.preset }}
- name: Cache vcpkg
uses: actions/cache@v4
with:
path: |
./thirdparty/vcpkg/downloads
./thirdparty/vcpkg/packages
key: vcpkg-${{ runner.os }}-${{ matrix.arch }}-${{ hashFiles('vcpkg.json') }}
restore-keys: |
vcpkg-${{ runner.os }}-${{ matrix.arch }}-
- name: Install Dependencies (macOS)
run: |
brew install ninja
- name: Cache ccache Directory
uses: actions/cache@v4
with:
path: /tmp/ccache
key: ccache-${{ runner.os }}-${{ matrix.arch }}-${{ matrix.preset }}
- name: Prepare Project
run: |
cp ./private/* ./UnleashedRecompLib/private
- name: Configure Project
env:
CCACHE_DIR: /tmp/ccache
run: cmake . --preset ${{ env.CMAKE_PRESET }} -DCMAKE_OSX_ARCHITECTURES=${{ matrix.arch }} -DSDL2MIXER_VORBIS=VORBISFILE -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache
- name: Build Project
env:
CCACHE_DIR: /tmp/ccache
run: cmake --build ./out/build/${{ env.CMAKE_PRESET }} --target UnleashedRecomp
- name: Pack Release
run: |
codesign --deep -fs - "./out/build/${{ env.CMAKE_PRESET }}/UnleashedRecomp/Unleashed Recompiled.app"
tar -czf UnleashedRecomp-macOS-${{ matrix.arch }}-${{ env.CMAKE_PRESET }}.tar.gz -C ./out/build/${{ env.CMAKE_PRESET }}/UnleashedRecomp "Unleashed Recompiled.app"
- name: Upload Artifact
uses: actions/upload-artifact@v4
with:
name: UnleashedRecomp-macOS-${{ matrix.arch }}-${{ env.CMAKE_PRESET }}
path: UnleashedRecomp-macOS-${{ matrix.arch }}-${{ env.CMAKE_PRESET }}.tar.gz

6
.gitmodules vendored
View file

@ -58,6 +58,12 @@
[submodule "thirdparty/json"]
path = thirdparty/json
url = https://github.com/nlohmann/json
[submodule "thirdparty/MoltenVK/MoltenVK"]
path = thirdparty/MoltenVK/MoltenVK
url = https://github.com/KhronosGroup/MoltenVK.git
[submodule "thirdparty/MoltenVK/SPIRV-Cross"]
path = thirdparty/MoltenVK/SPIRV-Cross
url = https://github.com/KhronosGroup/SPIRV-Cross.git
[submodule "UnleashedRecomp/api"]
path = UnleashedRecomp/api
url = https://github.com/hedge-dev/SWA.git

View file

@ -4,7 +4,6 @@ if(NOT DEFINED ENV{VCPKG_ROOT})
message(FATAL_ERROR "VCPKG_ROOT is not defined!")
endif()
include($ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
set(UNLEASHED_RECOMP_THIRDPARTY_ROOT ${CMAKE_SOURCE_DIR}/thirdparty)
set(UNLEASHED_RECOMP_TOOLS_ROOT ${CMAKE_SOURCE_DIR}/tools)
set(CMAKE_CXX_STANDARD 20)
@ -18,16 +17,28 @@ endif()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# Target Sandy Bridge for all projects
add_compile_options(
-march=sandybridge
)
project("UnleashedRecomp-ALL")
if (CMAKE_OSX_ARCHITECTURES)
set(UNLEASHED_RECOMP_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES})
elseif(CMAKE_SYSTEM_PROCESSOR)
set(UNLEASHED_RECOMP_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR})
else()
set(UNLEASHED_RECOMP_ARCHITECTURE ${CMAKE_HOST_SYSTEM_PROCESSOR})
endif()
string(TOLOWER "${UNLEASHED_RECOMP_ARCHITECTURE}" UNLEASHED_RECOMP_ARCHITECTURE)
message(STATUS "Detected architecture: ${UNLEASHED_RECOMP_ARCHITECTURE}")
if (UNLEASHED_RECOMP_ARCHITECTURE STREQUAL "x86_64" OR UNLEASHED_RECOMP_ARCHITECTURE STREQUAL "amd64")
# Target Sandy Bridge for all projects
add_compile_options(
-march=sandybridge
)
endif()
add_subdirectory(${UNLEASHED_RECOMP_THIRDPARTY_ROOT})
add_subdirectory(${UNLEASHED_RECOMP_TOOLS_ROOT})
project("UnleashedRecomp-ALL")
# Include sub-projects.
add_subdirectory("UnleashedRecompLib")
add_subdirectory("UnleashedRecomp")

View file

@ -113,6 +113,58 @@
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INTERPROCEDURAL_OPTIMIZATION": true
}
},
{
"name": "macos-base",
"hidden": true,
"generator": "Ninja",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"installDir": "${sourceDir}/out/install/${presetName}",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": {
"value": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"type": "FILEPATH"
},
"CMAKE_OSX_DEPLOYMENT_TARGET": "13.0"
},
"environment": {
"VCPKG_ROOT": "${sourceDir}/thirdparty/vcpkg"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Darwin"
},
"vendor": {
"microsoft.com/VisualStudioRemoteSettings/CMake/2.0": {
"remoteSourceRootDir": "$env{HOME}/.vs/$ms{projectDirName}"
}
}
},
{
"name": "macos-debug",
"displayName": "macOS-Debug",
"inherits": "macos-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "macos-relwithdebinfo",
"displayName": "macOS-RelWithDebInfo",
"inherits": "macos-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
}
},
{
"name": "macos-release",
"displayName": "macOS-Release",
"inherits": "macos-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release",
"CMAKE_INTERPROCEDURAL_OPTIMIZATION": true
}
}
]
}

View file

@ -97,6 +97,14 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
"os/linux/user_linux.cpp"
"os/linux/version_linux.cpp"
)
elseif (APPLE)
set(UNLEASHED_RECOMP_OS_CXX_SOURCES
"os/macos/logger_macos.cpp"
"os/macos/media_macos.cpp"
"os/macos/process_macos.cpp"
"os/macos/user_macos.cpp"
"os/macos/version_macos.cpp"
)
endif()
set(UNLEASHED_RECOMP_CPU_CXX_SOURCES
@ -119,7 +127,7 @@ endif()
set(UNLEASHED_RECOMP_APU_CXX_SOURCES
"apu/audio.cpp"
"apu/embedded_player.cpp"
"apu/embedded_player.cpp"
"apu/driver/sdl2_driver.cpp"
)
@ -149,16 +157,16 @@ set(UNLEASHED_RECOMP_PATCHES_CXX_SOURCES
set(UNLEASHED_RECOMP_UI_CXX_SOURCES
"ui/achievement_menu.cpp"
"ui/achievement_overlay.cpp"
"ui/achievement_overlay.cpp"
"ui/black_bar.cpp"
"ui/button_guide.cpp"
"ui/fader.cpp"
"ui/game_window.cpp"
"ui/game_window.cpp"
"ui/imgui_utils.cpp"
"ui/installer_wizard.cpp"
"ui/message_window.cpp"
"ui/options_menu.cpp"
"ui/options_menu_thumbnails.cpp"
"ui/options_menu_thumbnails.cpp"
"ui/tv_static.cpp"
)
@ -180,7 +188,7 @@ set(UNLEASHED_RECOMP_INSTALL_CXX_SOURCES
set(UNLEASHED_RECOMP_USER_CXX_SOURCES
"user/achievement_data.cpp"
"user/achievement_manager.cpp"
"user/config.cpp"
"user/config.cpp"
"user/registry.cpp"
"user/paths.cpp"
"user/persistent_data.cpp"
@ -250,11 +258,11 @@ set(UNLEASHED_RECOMP_CXX_SOURCES
${UNLEASHED_RECOMP_USER_CXX_SOURCES}
${UNLEASHED_RECOMP_MOD_CXX_SOURCES}
${UNLEASHED_RECOMP_THIRDPARTY_SOURCES}
)
)
include("version.cmake")
set(VERSION_TXT "${PROJECT_SOURCE_DIR}/res/version.txt")
include("version.cmake")
set(VERSION_TXT "${PROJECT_SOURCE_DIR}/res/version.txt")
# Only show Git info and build type if not Release.
set(SHOW_GIT_INFO_AND_BUILD_TYPE 0)
@ -270,43 +278,85 @@ GenerateVersionSources(
BUILD_TYPE ${CMAKE_BUILD_TYPE}
SHOW_GIT_INFO ${SHOW_GIT_INFO_AND_BUILD_TYPE}
SHOW_BUILD_TYPE ${SHOW_GIT_INFO_AND_BUILD_TYPE}
)
)
if (WIN32)
# Create binary version number for Win32 integer attributes.
CreateVersionString(
VERSION_TXT ${VERSION_TXT}
OUTPUT_CSV 1
OUTPUT_VAR WIN32_VERSION_BINARY
)
# Create string version number for Win32 detailed attributes.
CreateVersionString(
VERSION_TXT ${VERSION_TXT}
BUILD_TYPE ${CMAKE_BUILD_TYPE}
SHOW_GIT_INFO ${SHOW_GIT_INFO_AND_BUILD_TYPE}
SHOW_BUILD_TYPE ${SHOW_GIT_INFO_AND_BUILD_TYPE}
OUTPUT_VAR WIN32_VERSION_STRING
)
# Create binary version number for Win32 integer attributes.
CreateVersionString(
VERSION_TXT ${VERSION_TXT}
OUTPUT_CSV 1
OUTPUT_VAR WIN32_VERSION_BINARY
)
# Create string version number for Win32 detailed attributes.
CreateVersionString(
VERSION_TXT ${VERSION_TXT}
BUILD_TYPE ${CMAKE_BUILD_TYPE}
SHOW_GIT_INFO ${SHOW_GIT_INFO_AND_BUILD_TYPE}
SHOW_BUILD_TYPE ${SHOW_GIT_INFO_AND_BUILD_TYPE}
OUTPUT_VAR WIN32_VERSION_STRING
)
# Set Win32 icon path.
set(WIN32_ICON_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources/images/game_icon.ico")
set(WIN32_ICON_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources/images/game_icon.ico")
configure_file("res/win32/res.rc.template" "${CMAKE_BINARY_DIR}/res.rc" @ONLY)
add_executable(UnleashedRecomp ${UNLEASHED_RECOMP_CXX_SOURCES} "${CMAKE_BINARY_DIR}/res.rc")
# Hide console for release configurations.
if (${CMAKE_BUILD_TYPE} MATCHES "Release")
target_link_options(UnleashedRecomp PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
add_executable(UnleashedRecomp ${UNLEASHED_RECOMP_CXX_SOURCES} "${CMAKE_BINARY_DIR}/res.rc")
# Hide console for release configurations.
if (${CMAKE_BUILD_TYPE} MATCHES "Release")
target_link_options(UnleashedRecomp PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
endif()
elseif (APPLE)
# Create version number for app bundle.
CreateVersionString(
VERSION_TXT ${VERSION_TXT}
OUTPUT_VAR MACOS_BUNDLE_VERSION
)
add_executable(UnleashedRecomp MACOSX_BUNDLE
${UNLEASHED_RECOMP_CXX_SOURCES}
res/macos/game_icon.icns
)
set_source_files_properties(res/macos/game_icon.icns PROPERTIES
MACOSX_PACKAGE_LOCATION Resources)
set_target_properties(UnleashedRecomp PROPERTIES
OUTPUT_NAME "Unleashed Recompiled"
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/res/macos/MacOSXBundleInfo.plist.in
MACOSX_BUNDLE_GUI_IDENTIFIER hedge-dev.UnleashedRecomp
MACOSX_BUNDLE_BUNDLE_NAME "Unleashed Recompiled"
MACOSX_BUNDLE_BUNDLE_VERSION ${MACOS_BUNDLE_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${MACOS_BUNDLE_VERSION}
MACOSX_BUNDLE_ICON_FILE "game_icon.icns"
)
# Linking with MoltenVK directly would prevent using the system Vulkan loader to load with debug layers.
# Instead, copy the MoltenVK dylib to the app bundle along with an ICD file for the loader to find it.
# In the event the loader is not installed, the MoltenVK dylib can still be picked up directly in the app bundle.
set(MVK_ICD "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/MoltenVK/MoltenVK_icd.json")
target_sources(UnleashedRecomp PRIVATE ${MVK_ICD})
set_source_files_properties(${MVK_ICD} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d)
# Unfortunately using the MoltenVK target output as a resource file does not quite create the correct
# dependency chain, so we need to resolve the paths manually and create a copy target dependency chain.
set(MVK_DYLIB_SRC "${CMAKE_BINARY_DIR}/thirdparty/MoltenVK/libMoltenVK.dylib")
set(MVK_DYLIB_DST "${CMAKE_CURRENT_BINARY_DIR}/Unleashed Recompiled.app/Contents/Frameworks/libMoltenVK.dylib")
add_custom_command(
OUTPUT ${MVK_DYLIB_DST}
DEPENDS ${MVK_DYLIB_SRC}
COMMAND cmake -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST})
add_custom_target(CopyMoltenVK DEPENDS ${MVK_DYLIB_DST})
add_dependencies(CopyMoltenVK MoltenVK)
add_dependencies(UnleashedRecomp CopyMoltenVK)
set_property(TARGET UnleashedRecomp APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks")
else()
add_executable(UnleashedRecomp ${UNLEASHED_RECOMP_CXX_SOURCES})
endif()
if (UNLEASHED_RECOMP_FLATPAK)
target_compile_definitions(UnleashedRecomp PRIVATE
"UNLEASHED_RECOMP_FLATPAK"
"GAME_INSTALL_DIRECTORY=\"/var/data\""
target_compile_definitions(UnleashedRecomp PRIVATE
"UNLEASHED_RECOMP_FLATPAK"
"GAME_INSTALL_DIRECTORY=\"/var/data\""
)
endif()
@ -324,19 +374,17 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
target_compile_definitions(UnleashedRecomp PRIVATE SDL_VULKAN_ENABLED)
endif()
find_package(directx-dxc REQUIRED)
find_package(CURL REQUIRED)
if (UNLEASHED_RECOMP_D3D12)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
add_custom_command(TARGET UnleashedRecomp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Core,IMPORTED_LOCATION_RELEASE> ${CMAKE_CURRENT_BINARY_DIR}/D3D12
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Layers,IMPORTED_LOCATION_DEBUG> ${CMAKE_CURRENT_BINARY_DIR}/D3D12
COMMAND_EXPAND_LISTS
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Core,IMPORTED_LOCATION_RELEASE> $<TARGET_FILE_DIR:UnleashedRecomp>/D3D12
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Layers,IMPORTED_LOCATION_DEBUG> $<TARGET_FILE_DIR:UnleashedRecomp>/D3D12
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectXShaderCompiler,IMPORTED_LOCATION> $<TARGET_FILE_DIR:UnleashedRecomp>
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DXIL,IMPORTED_LOCATION> $<TARGET_FILE_DIR:UnleashedRecomp>
COMMAND_EXPAND_LISTS
)
find_file(DIRECTX_DXIL_LIBRARY "dxil.dll")
file(COPY ${DIRECTX_DXIL_LIBRARY} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(UnleashedRecomp PRIVATE
Microsoft::DirectX-Headers
@ -348,18 +396,16 @@ if (UNLEASHED_RECOMP_D3D12)
)
endif()
file(CHMOD ${DIRECTX_DXC_TOOL} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
if (WIN32)
target_link_libraries(UnleashedRecomp PRIVATE
comctl32
comctl32
dwmapi
ntdll
ntdll
Shcore
Synchronization
winmm
)
endif()
endif()
target_link_libraries(UnleashedRecomp PRIVATE
fmt::fmt
@ -410,16 +456,16 @@ function(compile_shader FILE_PATH TARGET_NAME)
endfunction()
function(compile_vertex_shader FILE_PATH)
compile_shader(${FILE_PATH} vs_6_0 -fvk-invert-y)
compile_shader(${FILE_PATH} vs_6_0 -fvk-invert-y -DUNLEASHED_RECOMP)
endfunction()
function(compile_pixel_shader FILE_PATH)
compile_shader(${FILE_PATH} ps_6_0)
compile_shader(${FILE_PATH} ps_6_0 -DUNLEASHED_RECOMP)
endfunction()
compile_pixel_shader(blend_color_alpha_ps)
compile_vertex_shader(copy_vs)
compile_pixel_shader(copy_color_ps)
compile_pixel_shader(blend_color_alpha_ps)
compile_vertex_shader(copy_vs)
compile_pixel_shader(copy_color_ps)
compile_pixel_shader(copy_depth_ps)
compile_pixel_shader(csd_filter_ps)
compile_vertex_shader(csd_no_tex_vs)
@ -433,7 +479,7 @@ compile_pixel_shader(gamma_correction_ps)
compile_pixel_shader(imgui_ps)
compile_vertex_shader(imgui_vs)
compile_pixel_shader(movie_ps)
compile_vertex_shader(movie_vs)
compile_vertex_shader(movie_vs)
compile_pixel_shader(resolve_msaa_color_2x)
compile_pixel_shader(resolve_msaa_color_4x)
compile_pixel_shader(resolve_msaa_color_8x)
@ -443,7 +489,7 @@ compile_pixel_shader(resolve_msaa_depth_8x)
set(RESOURCES_SOURCE_PATH "${PROJECT_SOURCE_DIR}/../UnleashedRecompResources")
set(RESOURCES_OUTPUT_PATH "${PROJECT_SOURCE_DIR}/res")
## Miscellaneous ##
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/bc_diff/button_bc_diff.bin" DEST_FILE "${RESOURCES_OUTPUT_PATH}/bc_diff/button_bc_diff.bin" ARRAY_NAME "g_button_bc_diff" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/font/im_font_atlas.bin" DEST_FILE "${RESOURCES_OUTPUT_PATH}/font/im_font_atlas.bin" ARRAY_NAME "g_im_font_atlas" COMPRESSION_TYPE "zstd")
@ -455,7 +501,7 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/co
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/kbm.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/kbm.dds" ARRAY_NAME "g_kbm" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/select.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/select.dds" ARRAY_NAME "g_select" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/common/light.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/common/light.dds" ARRAY_NAME "g_light" COMPRESSION_TYPE "zstd")
## Installer ##
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/arrow_circle.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/arrow_circle.dds" ARRAY_NAME "g_arrow_circle" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_001.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_001.dds" ARRAY_NAME "g_install_001" COMPRESSION_TYPE "zstd")
@ -467,23 +513,23 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/in
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_007.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_007.dds" ARRAY_NAME "g_install_007" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/install_008.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/install_008.dds" ARRAY_NAME "g_install_008" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/miles_electric_icon.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/miles_electric_icon.dds" ARRAY_NAME "g_miles_electric_icon" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/pulse_install.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/pulse_install.dds" ARRAY_NAME "g_pulse_install" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/installer/pulse_install.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/installer/pulse_install.dds" ARRAY_NAME "g_pulse_install" COMPRESSION_TYPE "zstd")
## Options Menu ##
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/achievement_notifications.dds" ARRAY_NAME "g_achievement_notifications" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input_ps.dds" ARRAY_NAME "g_allow_background_input_ps" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/allow_background_input_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/allow_background_input_xb.dds" ARRAY_NAME "g_allow_background_input_xb" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_none.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_none.dds" ARRAY_NAME "g_antialiasing_none" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" ARRAY_NAME "g_antialiasing_2x" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" ARRAY_NAME "g_antialiasing_4x" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_none.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_none.dds" ARRAY_NAME "g_antialiasing_none" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_2x.dds" ARRAY_NAME "g_antialiasing_2x" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_4x.dds" ARRAY_NAME "g_antialiasing_4x" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/antialiasing_8x.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/antialiasing_8x.dds" ARRAY_NAME "g_antialiasing_8x" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/aspect_ratio.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/aspect_ratio.dds" ARRAY_NAME "g_aspect_ratio" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/battle_theme.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/battle_theme.dds" ARRAY_NAME "g_battle_theme" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/brightness.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/brightness.dds" ARRAY_NAME "g_brightness" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_stereo.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_stereo.dds" ARRAY_NAME "g_channel_stereo" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_surround.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_surround.dds" ARRAY_NAME "g_channel_surround" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/brightness.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/brightness.dds" ARRAY_NAME "g_brightness" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_stereo.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_stereo.dds" ARRAY_NAME "g_channel_stereo" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/channel_surround.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/channel_surround.dds" ARRAY_NAME "g_channel_surround" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_ps.dds" ARRAY_NAME "g_control_tutorial_ps" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" ARRAY_NAME "g_control_tutorial_xb" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/control_tutorial_xb.dds" ARRAY_NAME "g_control_tutorial_xb" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/controller_icons.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/controller_icons.dds" ARRAY_NAME "g_controller_icons" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/default.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/default.dds" ARRAY_NAME "g_default" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/effects_volume.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/effects_volume.dds" ARRAY_NAME "g_effects_volume" COMPRESSION_TYPE "zstd")
@ -499,7 +545,7 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/motion_blur_off.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/motion_blur_off.dds" ARRAY_NAME "g_motion_blur_off" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/motion_blur_original.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/motion_blur_original.dds" ARRAY_NAME "g_motion_blur_original" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/motion_blur_enhanced.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/motion_blur_enhanced.dds" ARRAY_NAME "g_motion_blur_enhanced" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/movie_scale_fit.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/movie_scale_fit.dds" ARRAY_NAME "g_movie_scale_fit" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/movie_scale_fit.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/movie_scale_fit.dds" ARRAY_NAME "g_movie_scale_fit" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/movie_scale_fill.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/movie_scale_fill.dds" ARRAY_NAME "g_movie_scale_fill" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/music_attenuation.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/music_attenuation.dds" ARRAY_NAME "g_music_attenuation" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/music_volume.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/music_volume.dds" ARRAY_NAME "g_music_volume" COMPRESSION_TYPE "zstd")
@ -508,34 +554,34 @@ BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/op
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x2048.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x2048.dds" ARRAY_NAME "g_shadow_resolution_x2048" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x4096.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x4096.dds" ARRAY_NAME "g_shadow_resolution_x4096" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/shadow_resolution_x8192.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/shadow_resolution_x8192.dds" ARRAY_NAME "g_shadow_resolution_x8192" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" ARRAY_NAME "g_time_of_day_transition_playstation" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_ps.dds" ARRAY_NAME "g_time_of_day_transition_playstation" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/time_transition_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/time_transition_xb.dds" ARRAY_NAME "g_time_of_day_transition_xbox" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_false.dds" ARRAY_NAME "g_transparency_antialiasing_false" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/transparency_antialiasing_true.dds" ARRAY_NAME "g_transparency_antialiasing_true" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" ARRAY_NAME "g_ui_alignment_centre" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_centre.dds" ARRAY_NAME "g_ui_alignment_centre" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/ui_alignment_edge.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/ui_alignment_edge.dds" ARRAY_NAME "g_ui_alignment_edge" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vertical_camera.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vertical_camera.dds" ARRAY_NAME "g_vertical_camera" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/voice_language.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/voice_language.dds" ARRAY_NAME "g_voice_language" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration_ps.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration_ps.dds" ARRAY_NAME "g_vibration_ps" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration_xb.dds" ARRAY_NAME "g_vibration_xb" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vsync_on.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync_on.dds" ARRAY_NAME "g_vsync_on" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vibration_xb.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vibration_xb.dds" ARRAY_NAME "g_vibration_xb" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vsync_on.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync_on.dds" ARRAY_NAME "g_vsync_on" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/vsync_off.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/vsync_off.dds" ARRAY_NAME "g_vsync_off" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/window_size.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/window_size.dds" ARRAY_NAME "g_window_size" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/thumbnails/xbox_color_correction.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/thumbnails/xbox_color_correction.dds" ARRAY_NAME "g_xbox_color_correction" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/miles_electric.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/miles_electric.dds" ARRAY_NAME "g_miles_electric" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/options_static.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/options_static.dds" ARRAY_NAME "g_options_static" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/miles_electric.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/miles_electric.dds" ARRAY_NAME "g_miles_electric" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/options_static.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/options_static.dds" ARRAY_NAME "g_options_static" COMPRESSION_TYPE "zstd")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/options_menu/options_static_flash.dds" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/options_menu/options_static_flash.dds" ARRAY_NAME "g_options_static_flash" COMPRESSION_TYPE "zstd")
## Game Icon ##
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon.bmp" ARRAY_NAME "g_game_icon")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon_night.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon_night.bmp" ARRAY_NAME "g_game_icon_night")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/images/game_icon_night.bmp" DEST_FILE "${RESOURCES_OUTPUT_PATH}/images/game_icon_night.bmp" ARRAY_NAME "g_game_icon_night")
## Audio ##
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/music/installer.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/music/installer.ogg" ARRAY_NAME "g_installer_music")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/music/installer.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/music/installer.ogg" ARRAY_NAME "g_installer_music")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_worldmap_cursor.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_worldmap_cursor.ogg" ARRAY_NAME "g_sys_worldmap_cursor")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_worldmap_finaldecide.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_worldmap_finaldecide.ogg" ARRAY_NAME "g_sys_worldmap_finaldecide")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausecansel.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausecansel.ogg" ARRAY_NAME "g_sys_actstg_pausecansel")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausecursor.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausecursor.ogg" ARRAY_NAME "g_sys_actstg_pausecursor")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausedecide.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausedecide.ogg" ARRAY_NAME "g_sys_actstg_pausedecide")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausewinclose.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausewinclose.ogg" ARRAY_NAME "g_sys_actstg_pausewinclose")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausewinopen.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausewinopen.ogg" ARRAY_NAME "g_sys_actstg_pausewinopen")
BIN2C(TARGET_OBJ UnleashedRecomp SOURCE_FILE "${RESOURCES_SOURCE_PATH}/sounds/sys_actstg_pausewinopen.ogg" DEST_FILE "${RESOURCES_OUTPUT_PATH}/sounds/sys_actstg_pausewinopen.ogg" ARRAY_NAME "g_sys_actstg_pausewinopen")

View file

@ -40,29 +40,101 @@ GuestThreadContext::~GuestThreadContext()
g_userHeap.Free(thread);
}
static void GuestThreadFunc(GuestThreadHandle* hThread)
#ifdef USE_PTHREAD
static size_t GetStackSize()
{
// Cache as this should not change.
static size_t stackSize = 0;
if (stackSize == 0)
{
// 8 MiB is a typical default.
constexpr auto defaultSize = 8 * 1024 * 1024;
struct rlimit lim;
const auto ret = getrlimit(RLIMIT_STACK, &lim);
if (ret == 0 && lim.rlim_cur < defaultSize)
{
// Use what the system allows.
stackSize = lim.rlim_cur;
}
else
{
stackSize = defaultSize;
}
}
return stackSize;
}
static void* GuestThreadFunc(void* arg)
{
GuestThreadHandle* hThread = (GuestThreadHandle*)arg;
#else
static void* GuestThreadFunc(GuestThreadHandle* hThread)
{
#endif
hThread->suspended.wait(true);
GuestThread::Start(hThread->params);
#ifdef USE_PTHREAD
return nullptr;
#endif
}
GuestThreadHandle::GuestThreadHandle(const GuestThreadParams& params)
: params(params), suspended((params.flags & 0x1) != 0), thread(GuestThreadFunc, this)
: params(params), suspended((params.flags & 0x1) != 0)
#ifdef USE_PTHREAD
{
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, GetStackSize());
const auto ret = pthread_create(&thread, &attr, GuestThreadFunc, this);
if (ret != 0) {
fprintf(stderr, "pthread_create failed with error code 0x%X.\n", ret);
return;
}
}
#else
, thread(GuestThreadFunc, this)
{
}
#endif
GuestThreadHandle::~GuestThreadHandle()
{
#ifdef USE_PTHREAD
pthread_join(thread, nullptr);
#else
if (thread.joinable())
thread.join();
#endif
}
template <typename ThreadType>
static uint32_t CalcThreadId(const ThreadType& id)
{
if constexpr (sizeof(id) == 4)
return *reinterpret_cast<const uint32_t*>(&id);
else
return XXH32(&id, sizeof(id), 0);
}
uint32_t GuestThreadHandle::GetThreadId() const
{
#ifdef USE_PTHREAD
return CalcThreadId(thread);
#else
return CalcThreadId(thread.get_id());
#endif
}
uint32_t GuestThreadHandle::Wait(uint32_t timeout)
{
assert(timeout == INFINITE);
#ifdef USE_PTHREAD
pthread_join(thread, nullptr);
#else
if (thread.joinable())
thread.join();
#endif
return STATUS_WAIT_0;
}
@ -80,27 +152,25 @@ uint32_t GuestThread::Start(const GuestThreadParams& params)
return ctx.ppcContext.r3.u32;
}
static uint32_t GetThreadId(const std::thread::id& id)
{
if constexpr (sizeof(id) == 4)
return *reinterpret_cast<const uint32_t*>(&id);
else
return XXH32(&id, sizeof(id), 0);
}
GuestThreadHandle* GuestThread::Start(const GuestThreadParams& params, uint32_t* threadId)
{
auto hThread = CreateKernelObject<GuestThreadHandle>(params);
if (threadId != nullptr)
*threadId = GetThreadId(hThread->thread.get_id());
{
*threadId = hThread->GetThreadId();
}
return hThread;
}
uint32_t GuestThread::GetCurrentThreadId()
{
return GetThreadId(std::this_thread::get_id());
#ifdef USE_PTHREAD
return CalcThreadId(pthread_self());
#else
return CalcThreadId(std::this_thread::get_id());
#endif
}
void GuestThread::SetLastError(uint32_t error)

View file

@ -2,6 +2,15 @@
#include <kernel/xdm.h>
// Use pthreads directly on macOS to be able to increase default stack size.
#ifdef __APPLE__
#define USE_PTHREAD 1
#endif
#ifdef USE_PTHREAD
#include <pthread.h>
#endif
#define CURRENT_THREAD_HANDLE uint32_t(-2)
struct GuestThreadContext
@ -24,11 +33,17 @@ struct GuestThreadHandle : KernelObject
{
GuestThreadParams params;
std::atomic<bool> suspended;
#ifdef USE_PTHREAD
pthread_t thread;
#else
std::thread thread;
#endif
GuestThreadHandle(const GuestThreadParams& params);
~GuestThreadHandle() override;
uint32_t GetThreadId() const;
uint32_t Wait(uint32_t timeout) override;
};

View file

@ -63,3 +63,47 @@ inline std::unique_ptr<uint8_t[]> ReadAllBytes(const char* filePath, size_t& fil
return data;
}
#ifndef __cpp_lib_atomic_ref
// Polyfill for std::atomic_ref
namespace std {
template <typename value_type>
class atomic_ref
{
public:
atomic_ref(value_type& ref)
{
ptr = reinterpret_cast<std::atomic<value_type>*>(&ref);
}
void store(value_type desired)
{
ptr->store(desired);
}
bool compare_exchange_weak(value_type& expected, value_type desired)
{
return ptr->compare_exchange_weak(expected, desired);
}
void wait(value_type old)
{
ptr->wait(old);
}
void notify_one()
{
ptr->notify_one();
}
bool operator=(const value_type& rhs)
{
store(rhs);
}
private:
std::atomic<value_type>* ptr;
};
}
#endif

View file

@ -3437,6 +3437,7 @@ namespace plume {
adapter = adapterOption;
d3d = deviceOption;
shaderModel = dataShaderModel.HighestShaderModel;
capabilities.geometryShader = true;
capabilities.raytracing = rtSupportOption;
capabilities.raytracingStateUpdate = rtStateUpdateSupportOption;
capabilities.sampleLocations = samplePositionsOption;

View file

@ -26,7 +26,7 @@
#undef ControlMask
#undef Success
#elif defined(__APPLE__)
typedef struct _NSWindow NSWindow;
#include <SDL.h>
#endif
#ifdef SDL_VULKAN_ENABLED
@ -52,7 +52,9 @@ namespace plume {
};
#elif defined(__APPLE__)
struct RenderWindow {
NSWindow* window;
SDL_Window* window;
void* view;
bool operator==(const struct RenderWindow& rhs) const {
return window == rhs.window;
}
@ -1784,6 +1786,9 @@ namespace plume {
};
struct RenderDeviceCapabilities {
// Geometry shaders.
bool geometryShader = false;
// Raytracing.
bool raytracing = false;
bool raytracingStateUpdate = false;

View file

@ -51,13 +51,18 @@ namespace plume {
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
# elif defined(__linux__)
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
# elif defined(__APPLE__)
VK_EXT_METAL_SURFACE_EXTENSION_NAME,
# endif
};
static const std::unordered_set<std::string> OptionalInstanceExtensions = {
// No optional instance extensions yet.
# if defined(__APPLE__)
// Tells the system Vulkan loader to enumerate portability drivers, if supported.
VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
# endif
};
static const std::unordered_set<std::string> RequiredDeviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME,
@ -79,6 +84,8 @@ namespace plume {
VK_KHR_PRESENT_ID_EXTENSION_NAME,
VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME,
// Vulkan spec requires this to be enabled if supported by the driver.
VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
};
// Common functions.
@ -567,14 +574,16 @@ namespace plume {
}
}
static VkPipelineStageFlags toStageFlags(RenderBarrierStages stages, bool rtSupported) {
static VkPipelineStageFlags toStageFlags(RenderBarrierStages stages, bool geometrySupported, bool rtSupported) {
VkPipelineStageFlags flags = 0;
if (stages & RenderBarrierStage::GRAPHICS) {
flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
if (geometrySupported) {
flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
}
flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
flags |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
@ -2051,6 +2060,19 @@ namespace plume {
fprintf(stderr, "vkCreateXlibSurfaceKHR failed with error code 0x%X.\n", res);
return;
}
# elif defined(__APPLE__)
assert(renderWindow.window != 0);
assert(renderWindow.view != 0);
VkMetalSurfaceCreateInfoEXT surfaceCreateInfo = {};
surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
surfaceCreateInfo.pLayer = renderWindow.view;
VulkanInterface *renderInterface = commandQueue->device->renderInterface;
res = vkCreateMetalSurfaceEXT(renderInterface->instance, &surfaceCreateInfo, nullptr, &surface);
if (res != VK_SUCCESS) {
fprintf(stderr, "vkCreateMetalSurfaceEXT failed with error code 0x%X.\n", res);
return;
}
# endif
VkBool32 presentSupported = false;
@ -2191,7 +2213,14 @@ namespace plume {
}
// Handle the error silently.
#if defined(__APPLE__)
// Under MoltenVK, VK_SUBOPTIMAL_KHR does not result in a valid state for rendering. We intentionally
// only check for this error during present to avoid having to synchronize manually against the semaphore
// signalled by vkAcquireNextImageKHR.
if (res != VK_SUCCESS) {
#else
if ((res != VK_SUCCESS) && (res != VK_SUBOPTIMAL_KHR)) {
#endif
return false;
}
@ -2360,6 +2389,8 @@ namespace plume {
// The attributes width and height members do not include the border.
dstWidth = attributes.width;
dstHeight = attributes.height;
# elif defined(__APPLE__)
SDL_GetWindowSizeInPixels(renderWindow.window, (int *)(&dstWidth), (int *)(&dstHeight));
# endif
}
@ -2683,9 +2714,10 @@ namespace plume {
endActiveRenderPass();
const bool geometryEnabled = device->capabilities.geometryShader;
const bool rtEnabled = device->capabilities.raytracing;
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT | toStageFlags(stages, rtEnabled);
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT | toStageFlags(stages, geometryEnabled, rtEnabled);
thread_local std::vector<VkBufferMemoryBarrier> bufferMemoryBarriers;
thread_local std::vector<VkImageMemoryBarrier> imageMemoryBarriers;
bufferMemoryBarriers.clear();
@ -2704,7 +2736,7 @@ namespace plume {
bufferMemoryBarrier.offset = 0;
bufferMemoryBarrier.size = interfaceBuffer->desc.size;
bufferMemoryBarriers.emplace_back(bufferMemoryBarrier);
srcStageMask |= toStageFlags(interfaceBuffer->barrierStages, rtEnabled);
srcStageMask |= toStageFlags(interfaceBuffer->barrierStages, geometryEnabled, rtEnabled);
interfaceBuffer->barrierStages = stages;
}
@ -2724,7 +2756,7 @@ namespace plume {
imageMemoryBarrier.subresourceRange.layerCount = interfaceTexture->desc.arraySize;
imageMemoryBarrier.subresourceRange.aspectMask = (interfaceTexture->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
imageMemoryBarriers.emplace_back(imageMemoryBarrier);
srcStageMask |= toStageFlags(interfaceTexture->barrierStages, rtEnabled);
srcStageMask |= toStageFlags(interfaceTexture->barrierStages, geometryEnabled, rtEnabled);
interfaceTexture->textureLayout = textureBarrier.layout;
interfaceTexture->barrierStages = stages;
}
@ -2890,6 +2922,9 @@ namespace plume {
offsetVector.clear();
for (uint32_t i = 0; i < viewCount; i++) {
const VulkanBuffer *interfaceBuffer = static_cast<const VulkanBuffer *>(views[i].buffer.ref);
if (interfaceBuffer == nullptr && !device->nullDescriptorSupported) {
interfaceBuffer = static_cast<const VulkanBuffer *>(device->nullBuffer.get());
}
bufferVector.emplace_back((interfaceBuffer != nullptr) ? interfaceBuffer->vk : VK_NULL_HANDLE);
offsetVector.emplace_back(views[i].buffer.offset);
}
@ -3696,6 +3731,11 @@ namespace plume {
bufferDeviceAddressFeatures.pNext = featuresChain;
featuresChain = &bufferDeviceAddressFeatures;
VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures = {};
portabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR;
portabilityFeatures.pNext = featuresChain;
featuresChain = &portabilityFeatures;
VkPhysicalDeviceFeatures2 deviceFeatures = {};
deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
deviceFeatures.pNext = featuresChain;
@ -3766,6 +3806,12 @@ namespace plume {
createDeviceChain = &bufferDeviceAddressFeatures;
}
const bool portabilitySubset = supportedOptionalExtensions.find(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) != supportedOptionalExtensions.end();
if (portabilitySubset) {
portabilityFeatures.pNext = createDeviceChain;
createDeviceChain = &portabilityFeatures;
}
// Retrieve the information for the queue families.
uint32_t queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
@ -3778,6 +3824,7 @@ namespace plume {
uint32_t familyIndex = 0;
uint32_t familySetBits = sizeof(uint32_t) * 8;
uint32_t familyQueueCount = 0;
bool familyUsed = false;
for (uint32_t i = 0; i < queueFamilyCount; i++) {
const VkQueueFamilyProperties &props = queueFamilyProperties[i];
@ -3787,11 +3834,14 @@ namespace plume {
}
// Prefer picking the queues with the least amount of bits set that match the mask we're looking for.
// If the queue families have matching capabilities but one is already used, prefer the unused one.
uint32_t setBits = numberOfSetBits(props.queueFlags);
if ((setBits < familySetBits) || ((setBits == familySetBits) && (props.queueCount > familyQueueCount))) {
bool used = queueFamilyUsed[i];
if ((setBits < familySetBits) || ((setBits == familySetBits) && ((props.queueCount > familyQueueCount) || (familyUsed && !used)))) {
familyIndex = i;
familySetBits = setBits;
familyQueueCount = props.queueCount;
familyUsed = used;
}
}
@ -3912,6 +3962,7 @@ namespace plume {
description.dedicatedVideoMemory = memoryHeapSize;
// Fill capabilities.
capabilities.geometryShader = deviceFeatures.features.geometryShader;
capabilities.raytracing = rtSupported;
capabilities.raytracingStateUpdate = false;
capabilities.sampleLocations = sampleLocationsSupported;
@ -3920,13 +3971,25 @@ namespace plume {
capabilities.presentWait = presentWait;
capabilities.displayTiming = supportedOptionalExtensions.find(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME) != supportedOptionalExtensions.end();
capabilities.preferHDR = memoryHeapSize > (512 * 1024 * 1024);
#if defined(__APPLE__)
// MoltenVK supports triangle fans but does so via compute shaders to translate to lists, since it has to
// support all cases including indirect draw. This results in renderpass restarts that can harm performance,
// so force disable native triangle fan support and rely on the game to emulate fans if needed.
capabilities.triangleFan = false;
#else
capabilities.triangleFan = true;
#endif
capabilities.dynamicDepthBias = true;
capabilities.uma = (description.type == RenderDeviceType::INTEGRATED) && hasHostVisibleDeviceLocalMemory;
capabilities.gpuUploadHeap = capabilities.uma;
// Fill Vulkan-only capabilities.
loadStoreOpNoneSupported = supportedOptionalExtensions.find(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME) != supportedOptionalExtensions.end();
nullDescriptorSupported = nullDescriptor;
if (!nullDescriptorSupported) {
nullBuffer = createBuffer(RenderBufferDesc::DefaultBuffer(16, RenderBufferFlag::VERTEX));
}
}
VulkanDevice::~VulkanDevice() {
@ -4253,6 +4316,10 @@ namespace plume {
createInfo.ppEnabledLayerNames = nullptr;
createInfo.enabledLayerCount = 0;
# ifdef __APPLE__
createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
# endif
// Check for extensions.
uint32_t extensionCount;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);

View file

@ -20,8 +20,13 @@
#define VK_USE_PLATFORM_ANDROID_KHR
#elif defined(__linux__)
#define VK_USE_PLATFORM_XLIB_KHR
#elif defined(__APPLE__)
#define VK_USE_PLATFORM_METAL_EXT
#endif
// For VK_KHR_portability_subset
#define VK_ENABLE_BETA_EXTENSIONS
#include <volk.h>
#ifdef __clang__
@ -403,7 +408,9 @@ namespace plume {
RenderDeviceDescription description;
VkPhysicalDeviceRayTracingPipelinePropertiesKHR rtPipelineProperties = {};
VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationProperties = {};
std::unique_ptr<RenderBuffer> nullBuffer = nullptr;
bool loadStoreOpNoneSupported = false;
bool nullDescriptorSupported = false;
VulkanDevice(VulkanInterface *renderInterface, const std::string &preferredDeviceName);
~VulkanDevice() override;

View file

@ -37,6 +37,7 @@
#include <magic_enum/magic_enum.hpp>
#endif
#define UNLEASHED_RECOMP
#include "../../tools/XenosRecomp/XenosRecomp/shader_common.h"
#ifdef UNLEASHED_RECOMP_D3D12

View file

@ -166,6 +166,9 @@ void UpdateChecker::visitWebsite()
#elif defined(__linux__)
std::string command = "xdg-open " + std::string(VISIT_URL) + " &";
std::system(command.c_str());
#elif defined(__APPLE__)
std::string command = "open " + std::string(VISIT_URL) + " &";
std::system(command.c_str());
#else
static_assert(false, "Visit website not implemented for this platform.");
#endif

View file

@ -660,7 +660,7 @@ void KeQueryBasePriorityThread()
uint32_t NtSuspendThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
{
assert(hThread != GetKernelObject(CURRENT_THREAD_HANDLE) && hThread->thread.get_id() == std::this_thread::get_id());
assert(hThread != GetKernelObject(CURRENT_THREAD_HANDLE) && hThread->GetThreadId() == GuestThread::GetCurrentThreadId());
hThread->suspended = true;
hThread->suspended.wait(true);

View file

@ -306,26 +306,26 @@ uint32_t XamContentCreateEx(uint32_t dwUserIndex, const char* szRootName, const
if (!exists)
{
std::string root = "";
std::filesystem::path rootPath;
if (pContentData->dwContentType == XCONTENTTYPE_SAVEDATA)
{
std::u8string savePathU8 = GetSavePath(true).u8string();
root = (const char *)(savePathU8.c_str());
rootPath = GetSavePath(true);
}
else if (pContentData->dwContentType == XCONTENTTYPE_DLC)
{
root = GAME_INSTALL_DIRECTORY "/dlc";
rootPath = GetGamePath() / "dlc";
}
else
{
root = GAME_INSTALL_DIRECTORY;
rootPath = GetGamePath();
}
const std::string root = (const char*)rootPath.u8string().c_str();
XamRegisterContent(*pContentData, root);
std::error_code ec;
std::filesystem::create_directory(std::u8string_view((const char8_t*)(root.c_str())), ec);
std::filesystem::create_directory(rootPath, ec);
XamRootCreate(szRootName, root);
}

View file

@ -1,5 +1,7 @@
#include <stdafx.h>
#ifdef __x86_64__
#include <cpuid.h>
#endif
#include <cpu/guest_thread.h>
#include <gpu/video.h>
#include <kernel/function.h>
@ -69,8 +71,10 @@ void KiSystemStartup()
const auto gameContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Game");
const auto updateContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Update");
XamRegisterContent(gameContent, GAME_INSTALL_DIRECTORY "/game");
XamRegisterContent(updateContent, GAME_INSTALL_DIRECTORY "/update");
const std::string gamePath = (const char*)(GetGamePath() / "game").u8string().c_str();
const std::string updatePath = (const char*)(GetGamePath() / "update").u8string().c_str();
XamRegisterContent(gameContent, gamePath);
XamRegisterContent(updateContent, updatePath);
const auto saveFilePath = GetSaveFilePath(true);
bool saveFileExists = std::filesystem::exists(saveFilePath);
@ -102,7 +106,7 @@ void KiSystemStartup()
XamContentCreateEx(0, "D", &gameContent, OPEN_EXISTING, nullptr, nullptr, 0, 0, nullptr);
std::error_code ec;
for (auto& file : std::filesystem::directory_iterator(GAME_INSTALL_DIRECTORY "/dlc", ec))
for (auto& file : std::filesystem::directory_iterator(GetGamePath() / "dlc", ec))
{
if (file.is_directory())
{
@ -165,10 +169,10 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
return entry;
}
#ifdef __x86_64__
__attribute__((constructor(101), target("no-avx,no-avx2"), noinline))
void init()
{
#ifdef __x86_64__
uint32_t eax, ebx, ecx, edx;
// Execute CPUID for processor info and feature bits.
@ -185,8 +189,8 @@ void init()
std::_Exit(1);
}
#endif
}
#endif
int main(int argc, char *argv[])
{
@ -324,7 +328,7 @@ int main(int argc, char *argv[])
HostStartup();
std::filesystem::path modulePath;
bool isGameInstalled = Installer::checkGameInstall(GAME_INSTALL_DIRECTORY, modulePath);
bool isGameInstalled = Installer::checkGameInstall(GetGamePath(), modulePath);
bool runInstallerWizard = forceInstaller || forceDLCInstaller || !isGameInstalled;
if (runInstallerWizard)
{
@ -334,7 +338,7 @@ int main(int argc, char *argv[])
std::_Exit(1);
}
if (!InstallerWizard::Run(GAME_INSTALL_DIRECTORY, isGameInstalled && forceDLCInstaller))
if (!InstallerWizard::Run(GetGamePath(), isGameInstalled && forceDLCInstaller))
{
std::_Exit(0);
}

View file

@ -100,7 +100,7 @@ void ModLoader::Init()
{
configIni = {};
if (!configIni.read(GAME_INSTALL_DIRECTORY "/cpkredir.ini"))
if (!configIni.read(GetGamePath() / "cpkredir.ini"))
return;
}

View file

@ -15,6 +15,11 @@ std::filesystem::path os::process::GetExecutablePath()
}
}
std::filesystem::path os::process::GetExecutableRoot()
{
return GetExecutablePath().remove_filename();
}
std::filesystem::path os::process::GetWorkingDirectory()
{
char cwd[PATH_MAX] = {};

View file

@ -0,0 +1,17 @@
#include <os/logger.h>
void os::logger::Init()
{
}
void os::logger::Log(const std::string_view str, ELogType type, const char* func)
{
if (func)
{
fmt::println("[{}] {}", func, str);
}
else
{
fmt::println("{}", str);
}
}

View file

@ -0,0 +1,7 @@
#include <os/media.h>
bool os::media::IsExternalMediaPlaying()
{
// This functionality is not supported in macOS.
return false;
}

View file

@ -0,0 +1,137 @@
#include <os/process.h>
#include <CoreFoundation/CFBundle.h>
#include <dlfcn.h>
#include <mach-o/dyld.h>
#include <signal.h>
#include <sys/param.h>
#include <unistd.h>
std::filesystem::path os::process::GetExecutablePath()
{
uint32_t exePathSize = PATH_MAX;
char exePath[PATH_MAX] = {};
if (_NSGetExecutablePath(exePath, &exePathSize) == 0)
{
return std::filesystem::path(std::u8string_view((const char8_t*)(exePath)));
}
else
{
return std::filesystem::path();
}
}
using IsTranslocatedURLFunc = Boolean (*)(CFURLRef path, bool* isTranslocated,
CFErrorRef* __nullable error);
using CreateOriginalPathForURLFunc = CFURLRef __nullable (*)(CFURLRef translocatedPath,
CFErrorRef* __nullable error);
static CFURLRef UntranslocateBundlePath(const CFURLRef bundlePath)
{
CFURLRef resultPath = nullptr;
if (void* securityHandle = dlopen("/System/Library/Frameworks/Security.framework/Security", RTLD_LAZY))
{
const auto IsTranslocatedURL = reinterpret_cast<IsTranslocatedURLFunc>(
dlsym(securityHandle, "SecTranslocateIsTranslocatedURL"));
const auto CreateOriginalPathForURL = reinterpret_cast<CreateOriginalPathForURLFunc>(
dlsym(securityHandle, "SecTranslocateCreateOriginalPathForURL"));
bool translocated = false;
if (IsTranslocatedURL && CreateOriginalPathForURL &&
IsTranslocatedURL(bundlePath, &translocated, nullptr) && translocated)
{
resultPath = CreateOriginalPathForURL(bundlePath, nullptr);
}
dlclose(securityHandle);
}
return resultPath;
}
std::filesystem::path os::process::GetExecutableRoot()
{
std::filesystem::path resultPath = GetExecutablePath().remove_filename();
if (CFBundleRef bundleRef = CFBundleGetMainBundle())
{
if (CFURLRef bundleUrlRef = CFBundleCopyBundleURL(bundleRef))
{
// The OS may relocate the app elsewhere for security reasons if,
// for example, it was downloaded and opened from the Downloads
// folder. In this case, we need to untranslocate the path to
// find out where the actual app bundle is.
CFURLRef untranslocatedUrlRef = UntranslocateBundlePath(bundleUrlRef);
char appBundlePath[MAXPATHLEN];
if (CFURLGetFileSystemRepresentation(
untranslocatedUrlRef ? untranslocatedUrlRef : bundleUrlRef, true,
reinterpret_cast<uint8_t*>(appBundlePath), sizeof(appBundlePath)))
{
resultPath = std::filesystem::path(appBundlePath).parent_path();
}
if (untranslocatedUrlRef)
{
CFRelease(untranslocatedUrlRef);
}
CFRelease(bundleUrlRef);
}
}
return resultPath;
}
std::filesystem::path os::process::GetWorkingDirectory()
{
char cwd[PATH_MAX] = {};
char *res = getcwd(cwd, sizeof(cwd));
if (res != nullptr)
{
return std::filesystem::path(std::u8string_view((const char8_t*)(cwd)));
}
else
{
return std::filesystem::path();
}
}
bool os::process::SetWorkingDirectory(const std::filesystem::path& path)
{
return chdir(path.c_str()) == 0;
}
bool os::process::StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work)
{
pid_t pid = fork();
if (pid < 0)
return false;
if (pid == 0)
{
setsid();
std::u8string workU8 = work.u8string();
chdir((const char*)(workU8.c_str()));
std::u8string pathU8 = path.u8string();
std::vector<char*> argStrs;
argStrs.push_back((char*)(pathU8.c_str()));
for (const std::string& arg : args)
argStrs.push_back((char *)(arg.c_str()));
argStrs.push_back(nullptr);
execvp((const char*)(pathU8.c_str()), argStrs.data());
raise(SIGKILL);
}
return true;
}
void os::process::CheckConsole()
{
// Always visible on macOS.
g_consoleVisible = true;
}
void os::process::ShowConsole()
{
// Unnecessary on macOS.
}

View file

@ -0,0 +1,21 @@
#include <os/registry.h>
// TODO: Implement
inline bool os::registry::Init()
{
return false;
}
// TODO: read from file?
template<typename T>
bool os::registry::ReadValue(const std::string_view& name, T& data)
{
return false;
}
// TODO: write to file?
template<typename T>
bool os::registry::WriteValue(const std::string_view& name, const T& data)
{
return false;
}

View file

@ -0,0 +1,6 @@
#include <os/user.h>
bool os::user::IsDarkTheme()
{
return false;
}

View file

@ -0,0 +1,7 @@
#include <os/version.h>
os::version::OSVersion os::version::GetOSVersion()
{
assert(false && "Unimplemented.");
return os::version::OSVersion();
}

View file

@ -5,6 +5,7 @@ namespace os::process
inline bool g_consoleVisible;
std::filesystem::path GetExecutablePath();
std::filesystem::path GetExecutableRoot();
std::filesystem::path GetWorkingDirectory();
bool SetWorkingDirectory(const std::filesystem::path& path);
bool StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work = {});

View file

@ -15,4 +15,6 @@ namespace os::registry
#include <os/win32/registry_win32.inl>
#elif defined(__linux__)
#include <os/linux/registry_linux.inl>
#elif defined(__APPLE__)
#include <os/macos/registry_macos.inl>
#endif

View file

@ -10,6 +10,11 @@ std::filesystem::path os::process::GetExecutablePath()
return std::filesystem::path(exePath);
}
std::filesystem::path os::process::GetExecutableRoot()
{
return GetExecutablePath().remove_filename();
}
std::filesystem::path os::process::GetWorkingDirectory()
{
WCHAR workPath[MAX_PATH];

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
<key>CFBundleGetInfoString</key>
<string>${MACOSX_BUNDLE_INFO_STRING}</string>
<key>CFBundleIconFile</key>
<string>${MACOSX_BUNDLE_ICON_FILE}</string>
<key>CFBundleIdentifier</key>
<string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string>
<key>CFBundleName</key>
<string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
<key>LSMinimumSystemVersion</key>
<string>13.0</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>GCSupportsGameMode</key>
<true/>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>

Binary file not shown.

View file

@ -20,7 +20,7 @@ std::unique_ptr<GuestTexture> g_upKBMIcons;
float g_sideMargins = DEFAULT_SIDE_MARGINS;
std::vector<Button> g_buttons;
static std::vector<Button> g_buttons;
std::unordered_map<EButtonIcon, float> g_iconWidths =
{

View file

@ -217,6 +217,9 @@ void GameWindow::Init(const char* sdlVideoDriver)
s_renderWindow = s_pWindow;
#elif defined(__linux__)
s_renderWindow = { info.info.x11.display, info.info.x11.window };
#elif defined(__APPLE__)
s_renderWindow.window = s_pWindow;
s_renderWindow.view = SDL_Metal_GetLayer(SDL_Metal_CreateView(s_pWindow));
#else
static_assert(false, "Unknown platform.");
#endif

View file

@ -1146,7 +1146,11 @@ static void PickerStart(bool folderMode) {
g_currentPickerVisible = true;
// Optional single thread mode for testing on systems that do not interact well with the separate thread being used for NFD.
#ifdef __APPLE__
constexpr bool singleThreadMode = true;
#else
constexpr bool singleThreadMode = false;
#endif
if (singleThreadMode)
PickerThreadProcess();
else

View file

@ -41,7 +41,7 @@ static ImFont* g_fntSeurat;
std::string g_text;
int g_result;
std::vector<std::string> g_buttons;
static std::vector<std::string> g_buttons;
int g_defaultButtonIndex;
int g_cancelButtonIndex;

View file

@ -1,7 +1,7 @@
#include "paths.h"
#include <os/process.h>
std::filesystem::path g_executableRoot = os::process::GetExecutablePath().remove_filename();
std::filesystem::path g_executableRoot = os::process::GetExecutableRoot();
std::filesystem::path g_userPath = BuildUserPath();
bool CheckPortable()
@ -22,18 +22,24 @@ std::filesystem::path BuildUserPath()
userPath = std::filesystem::path{ knownPath } / USER_DIRECTORY;
CoTaskMemFree(knownPath);
#elif defined(__linux__)
#elif defined(__linux__) || defined(__APPLE__)
const char* homeDir = getenv("HOME");
#if defined(__linux__)
if (homeDir == nullptr)
{
homeDir = getpwuid(getuid())->pw_dir;
}
#endif
if (homeDir != nullptr)
{
// Prefer to store in the .config directory if it exists. Use the home directory otherwise.
std::filesystem::path homePath = homeDir;
#if defined(__linux__)
std::filesystem::path configPath = homePath / ".config";
#else
std::filesystem::path configPath = homePath / "Library" / "Application Support";
#endif
if (std::filesystem::exists(configPath))
userPath = configPath / USER_DIRECTORY;
else

View file

@ -10,15 +10,22 @@
extern std::filesystem::path g_executableRoot;
inline std::filesystem::path GetGamePath()
{
return GAME_INSTALL_DIRECTORY;
}
bool CheckPortable();
std::filesystem::path BuildUserPath();
const std::filesystem::path& GetUserPath();
inline std::filesystem::path GetGamePath()
{
#ifdef __APPLE__
// On macOS, there is the expectation that the app may be installed to
// /Applications/, and the bundle should not be modified. Thus we need
// to install game files to the user directory instead of next to the app.
return GetUserPath();
#else
return GAME_INSTALL_DIRECTORY;
#endif
}
inline std::filesystem::path GetSavePath(bool checkForMods)
{
if (checkForMods && !ModLoader::s_saveFilePath.empty())

View file

@ -53,6 +53,7 @@ target_compile_definitions(XenosRecomp PRIVATE
XENOS_RECOMP_INPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/private\"
XENOS_RECOMP_OUTPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/shader/shader_cache.cpp\"
XENOS_RECOMP_INCLUDE_INPUT=\"${XENOS_RECOMP_INCLUDE}\"
UNLEASHED_RECOMP
)
file(GLOB XENOS_RECOMP_SOURCES
@ -79,4 +80,5 @@ add_library(UnleashedRecompLib
)
target_include_directories(UnleashedRecompLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_include_directories(UnleashedRecompLib PRIVATE "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenonRecomp/thirdparty/simde")
target_precompile_headers(UnleashedRecompLib PUBLIC "ppc/ppc_recomp_shared.h")

View file

@ -50,6 +50,21 @@ You can also find the equivalent packages for your preferred distro.
> [!NOTE]
> This list may not be comprehensive for your particular distro and you may be required to install additional packages, should an error occur during configuration.
### macOS
You will need to install the latest Xcode or Xcode Command Line Tools from Apple.
The following commands will install additional required dependencies, depending on which package manager you use.
If you use Homebrew:
```bash
brew install cmake ninja pkg-config
```
If you use MacPorts:
```bash
sudo port install cmake ninja pkg-config
```
## 4. Build the Project
### Windows
@ -81,3 +96,22 @@ cmake --build ./out/build/linux-release --target UnleashedRecomp
```bash
./UnleashedRecomp
```
### macOS
1. Configure the project using CMake by navigating to the repository and running the following command.
```bash
cmake . --preset macos-release
```
> [!NOTE]
> The available presets are `macos-debug`, `macos-relwithdebinfo` and `macos-release`.
2. Build the project using the selected configuration.
```bash
cmake --build ./out/build/macos-release --target UnleashedRecomp
```
3. Navigate to the directory that was specified as the output in the previous step and run the game.
```bash
open -a UnleashedRecomp.app
```

View file

@ -20,3 +20,7 @@ add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/nativefiledialog-extended"
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/o1heap")
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL")
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL_mixer")
if (APPLE)
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/MoltenVK")
endif()

86
thirdparty/MoltenVK/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,86 @@
# Simple CMake script to compile MoltenVK with SPIRV-Cross as a shared library target
# Prepare MoltenVK Git revision
find_package(Git)
if(GIT_FOUND)
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
OUTPUT_VARIABLE MVK_GIT_REV
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
set(MVK_GENERATED_INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/Generated)
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_library(APPKIT_LIBRARY AppKit REQUIRED)
find_library(FOUNDATION_LIBRARY Foundation REQUIRED)
find_library(IOKIT_LIBRARY IOKit REQUIRED)
find_library(IOSURFACE_LIBRARY IOSurface REQUIRED)
find_library(METAL_LIBRARY Metal REQUIRED)
find_library(QUARTZCORE_LIBRARY QuartzCore REQUIRED)
# SPIRV-Cross
option(SPIRV_CROSS_CLI "" OFF)
option(SPIRV_CROSS_ENABLE_TESTS "" OFF)
option(SPIRV_CROSS_ENABLE_HLSL "" OFF)
option(SPIRV_CROSS_ENABLE_CPP "" OFF)
option(SPIRV_CROSS_SKIP_INSTALL "" ON)
add_subdirectory(SPIRV-Cross)
# Common
set(MVK_COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/Common)
file(GLOB_RECURSE MVK_COMMON_SOURCES CONFIGURE_DEPENDS
${MVK_COMMON_DIR}/*.cpp
${MVK_COMMON_DIR}/*.m
${MVK_COMMON_DIR}/*.mm)
set(MVK_COMMON_INCLUDES ${MVK_COMMON_DIR})
add_library(MoltenVKCommon STATIC ${MVK_COMMON_SOURCES})
target_include_directories(MoltenVKCommon PUBLIC ${MVK_COMMON_INCLUDES})
target_compile_options(MoltenVKCommon PRIVATE -w)
# MoltenVKShaderConverter
set(MVK_SHADER_CONVERTER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVKShaderConverter)
file(GLOB_RECURSE MVK_SHADER_CONVERTER_SOURCES CONFIGURE_DEPENDS
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.cpp
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.m
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.mm)
set(MVK_SHADER_CONVERTER_INCLUDES ${MVK_SHADER_CONVERTER_DIR} ${MVK_SHADER_CONVERTER_DIR}/include)
add_library(MoltenVKShaderConverter STATIC ${MVK_SHADER_CONVERTER_SOURCES})
target_include_directories(MoltenVKShaderConverter PUBLIC ${MVK_SHADER_CONVERTER_INCLUDES})
target_compile_options(MoltenVKShaderConverter PRIVATE -w)
target_link_libraries(MoltenVKShaderConverter PRIVATE spirv-cross-msl spirv-cross-reflect MoltenVKCommon)
target_compile_definitions(MoltenVKShaderConverter PRIVATE MVK_EXCLUDE_SPIRV_TOOLS=1)
# MoltenVK
set(MVK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVK)
file(GLOB_RECURSE MVK_SOURCES CONFIGURE_DEPENDS
${MVK_DIR}/MoltenVK/*.cpp
${MVK_DIR}/MoltenVK/*.m
${MVK_DIR}/MoltenVK/*.mm)
file(GLOB MVK_SRC_INCLUDES LIST_DIRECTORIES ON ${MVK_DIR}/MoltenVK/*)
set(MVK_INCLUDES
${MVK_SRC_INCLUDES} ${MVK_GENERATED_INCLUDES} ${MVK_DIR}/include
${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include)
add_library(MoltenVK SHARED ${MVK_SOURCES})
target_include_directories(MoltenVK PRIVATE ${MVK_INCLUDES})
target_compile_options(MoltenVK PRIVATE -w)
target_link_libraries(MoltenVK PRIVATE
${APPKIT_LIBRARY} ${FOUNDATION_LIBRARY} ${IOKIT_LIBRARY} ${IOSURFACE_LIBRARY} ${METAL_LIBRARY} ${QUARTZCORE_LIBRARY}
spirv-cross-msl MoltenVKCommon MoltenVKShaderConverter)
target_compile_definitions(MoltenVK PRIVATE MVK_FRAMEWORK_VERSION=${MVK_VERSION} MVK_USE_CEREAL=0)

1
thirdparty/MoltenVK/MoltenVK vendored Submodule

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

8
thirdparty/MoltenVK/MoltenVK_icd.json vendored Normal file
View 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
}
}

1
thirdparty/MoltenVK/SPIRV-Cross vendored Submodule

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

@ -1 +1 @@
Subproject commit c017eb630ab917bffd3bc6a0a46995b49e7d8049
Subproject commit d3d59de8e0c165b8dcf883d47e1e5892942c8424

@ -1 +1 @@
Subproject commit 4897cf7ef2070120310c28a1a672b427d745dad8
Subproject commit 18145fa4c50128c8101e5605ba953ce5a653eca4

View file

@ -9,8 +9,12 @@
"name": "directx12-agility",
"platform": "windows"
},
"directx-dxc",
"freetype",
"curl"
]
],
"vcpkg-configuration": {
"overlay-triplets": [
"vcpkg/triplets"
]
}
}

View file

@ -0,0 +1,7 @@
set(VCPKG_TARGET_ARCHITECTURE arm64)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
set(VCPKG_OSX_ARCHITECTURES arm64)
set(VCPKG_OSX_DEPLOYMENT_TARGET "13.0")

View file

@ -0,0 +1,7 @@
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
set(VCPKG_OSX_ARCHITECTURES x86_64)
set(VCPKG_OSX_DEPLOYMENT_TARGET "13.0")