mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2025-10-30 07:11:05 +00:00
Compare commits
2 commits
5d3ab002ff
...
d739f3b35d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d739f3b35d | ||
|
|
ada0db62dc |
47 changed files with 891 additions and 140 deletions
77
.github/workflows/validate.yml
vendored
77
.github/workflows/validate.yml
vendored
|
|
@ -210,3 +210,80 @@ jobs:
|
||||||
with:
|
with:
|
||||||
name: UnleashedRecomp-Flatpak
|
name: UnleashedRecomp-Flatpak
|
||||||
path: ./${{ env.FLATPAK_ID }}.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 latest Xcode
|
||||||
|
uses: maxim-lobanov/setup-xcode@v1
|
||||||
|
with:
|
||||||
|
xcode-version: latest-stable
|
||||||
|
|
||||||
|
- 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
6
.gitmodules
vendored
|
|
@ -61,3 +61,9 @@
|
||||||
[submodule "UnleashedRecomp/api"]
|
[submodule "UnleashedRecomp/api"]
|
||||||
path = UnleashedRecomp/api
|
path = UnleashedRecomp/api
|
||||||
url = https://github.com/hedge-dev/SWA.git
|
url = https://github.com/hedge-dev/SWA.git
|
||||||
|
[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
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ if(NOT DEFINED ENV{VCPKG_ROOT})
|
||||||
message(FATAL_ERROR "VCPKG_ROOT is not defined!")
|
message(FATAL_ERROR "VCPKG_ROOT is not defined!")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include($ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake)
|
|
||||||
set(UNLEASHED_RECOMP_THIRDPARTY_ROOT ${CMAKE_SOURCE_DIR}/thirdparty)
|
set(UNLEASHED_RECOMP_THIRDPARTY_ROOT ${CMAKE_SOURCE_DIR}/thirdparty)
|
||||||
set(UNLEASHED_RECOMP_TOOLS_ROOT ${CMAKE_SOURCE_DIR}/tools)
|
set(UNLEASHED_RECOMP_TOOLS_ROOT ${CMAKE_SOURCE_DIR}/tools)
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
@ -18,16 +17,28 @@ endif()
|
||||||
|
|
||||||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
||||||
|
|
||||||
# Target Sandy Bridge for all projects
|
project("UnleashedRecomp-ALL")
|
||||||
add_compile_options(
|
|
||||||
|
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
|
-march=sandybridge
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(${UNLEASHED_RECOMP_THIRDPARTY_ROOT})
|
add_subdirectory(${UNLEASHED_RECOMP_THIRDPARTY_ROOT})
|
||||||
add_subdirectory(${UNLEASHED_RECOMP_TOOLS_ROOT})
|
add_subdirectory(${UNLEASHED_RECOMP_TOOLS_ROOT})
|
||||||
|
|
||||||
project("UnleashedRecomp-ALL")
|
|
||||||
|
|
||||||
# Include sub-projects.
|
# Include sub-projects.
|
||||||
add_subdirectory("UnleashedRecompLib")
|
add_subdirectory("UnleashedRecompLib")
|
||||||
add_subdirectory("UnleashedRecomp")
|
add_subdirectory("UnleashedRecomp")
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,58 @@
|
||||||
"CMAKE_BUILD_TYPE": "Release",
|
"CMAKE_BUILD_TYPE": "Release",
|
||||||
"CMAKE_INTERPROCEDURAL_OPTIMIZATION": true
|
"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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,14 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
"os/linux/user_linux.cpp"
|
"os/linux/user_linux.cpp"
|
||||||
"os/linux/version_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()
|
endif()
|
||||||
|
|
||||||
set(UNLEASHED_RECOMP_CPU_CXX_SOURCES
|
set(UNLEASHED_RECOMP_CPU_CXX_SOURCES
|
||||||
|
|
@ -299,6 +307,55 @@ if (WIN32)
|
||||||
if (${CMAKE_BUILD_TYPE} MATCHES "Release")
|
if (${CMAKE_BUILD_TYPE} MATCHES "Release")
|
||||||
target_link_options(UnleashedRecomp PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
|
target_link_options(UnleashedRecomp PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup")
|
||||||
endif()
|
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_BUNDLED_PATH "Resources/vulkan/icd.d")
|
||||||
|
set(MVK_DST "${CMAKE_CURRENT_BINARY_DIR}/Unleashed Recompiled.app/Contents/${MVK_BUNDLED_PATH}")
|
||||||
|
set_property(TARGET UnleashedRecomp APPEND PROPERTY BUILD_RPATH "@executable_path/../${MVK_BUNDLED_PATH}")
|
||||||
|
|
||||||
|
set(MVK_ICD_SRC "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/MoltenVK/MoltenVK/MoltenVK/icd/MoltenVK_icd.json")
|
||||||
|
set(MVK_ICD_DST "${MVK_DST}/MoltenVK_icd.json")
|
||||||
|
set(MVK_DYLIB_SRC "${CMAKE_BINARY_DIR}/thirdparty/MoltenVK/libMoltenVK.dylib")
|
||||||
|
set(MVK_DYLIB_DST "${MVK_DST}/libMoltenVK.dylib")
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${MVK_DST}
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
|
||||||
|
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(UnleashedRecomp CopyMoltenVK)
|
||||||
else()
|
else()
|
||||||
add_executable(UnleashedRecomp ${UNLEASHED_RECOMP_CXX_SOURCES})
|
add_executable(UnleashedRecomp ${UNLEASHED_RECOMP_CXX_SOURCES})
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -324,20 +381,18 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||||
target_compile_definitions(UnleashedRecomp PRIVATE SDL_VULKAN_ENABLED)
|
target_compile_definitions(UnleashedRecomp PRIVATE SDL_VULKAN_ENABLED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(directx-dxc REQUIRED)
|
|
||||||
find_package(CURL REQUIRED)
|
find_package(CURL REQUIRED)
|
||||||
|
|
||||||
if (UNLEASHED_RECOMP_D3D12)
|
if (UNLEASHED_RECOMP_D3D12)
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/D3D12)
|
||||||
add_custom_command(TARGET UnleashedRecomp POST_BUILD
|
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-Core,IMPORTED_LOCATION_RELEASE> $<TARGET_FILE_DIR:UnleashedRecomp>/D3D12
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:Microsoft::DirectX12-Layers,IMPORTED_LOCATION_DEBUG> ${CMAKE_CURRENT_BINARY_DIR}/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
|
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
|
target_link_libraries(UnleashedRecomp PRIVATE
|
||||||
Microsoft::DirectX-Headers
|
Microsoft::DirectX-Headers
|
||||||
Microsoft::DirectX-Guids
|
Microsoft::DirectX-Guids
|
||||||
|
|
@ -348,8 +403,6 @@ if (UNLEASHED_RECOMP_D3D12)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
file(CHMOD ${DIRECTX_DXC_TOOL} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE)
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(UnleashedRecomp PRIVATE
|
target_link_libraries(UnleashedRecomp PRIVATE
|
||||||
comctl32
|
comctl32
|
||||||
|
|
@ -358,6 +411,7 @@ if (WIN32)
|
||||||
Shcore
|
Shcore
|
||||||
Synchronization
|
Synchronization
|
||||||
winmm
|
winmm
|
||||||
|
windowsapp
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -410,11 +464,11 @@ function(compile_shader FILE_PATH TARGET_NAME)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(compile_vertex_shader FILE_PATH)
|
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()
|
endfunction()
|
||||||
|
|
||||||
function(compile_pixel_shader FILE_PATH)
|
function(compile_pixel_shader FILE_PATH)
|
||||||
compile_shader(${FILE_PATH} ps_6_0)
|
compile_shader(${FILE_PATH} ps_6_0 -DUNLEASHED_RECOMP)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
compile_pixel_shader(blend_color_alpha_ps)
|
compile_pixel_shader(blend_color_alpha_ps)
|
||||||
|
|
|
||||||
|
|
@ -40,29 +40,101 @@ GuestThreadContext::~GuestThreadContext()
|
||||||
g_userHeap.Free(thread);
|
g_userHeap.Free(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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)
|
static void GuestThreadFunc(GuestThreadHandle* hThread)
|
||||||
{
|
{
|
||||||
|
#endif
|
||||||
hThread->suspended.wait(true);
|
hThread->suspended.wait(true);
|
||||||
GuestThread::Start(hThread->params);
|
GuestThread::Start(hThread->params);
|
||||||
|
#ifdef USE_PTHREAD
|
||||||
|
return nullptr;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
GuestThreadHandle::GuestThreadHandle(const GuestThreadParams& params)
|
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()
|
GuestThreadHandle::~GuestThreadHandle()
|
||||||
{
|
{
|
||||||
|
#ifdef USE_PTHREAD
|
||||||
|
pthread_join(thread, nullptr);
|
||||||
|
#else
|
||||||
if (thread.joinable())
|
if (thread.joinable())
|
||||||
thread.join();
|
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)
|
uint32_t GuestThreadHandle::Wait(uint32_t timeout)
|
||||||
{
|
{
|
||||||
assert(timeout == INFINITE);
|
assert(timeout == INFINITE);
|
||||||
|
|
||||||
|
#ifdef USE_PTHREAD
|
||||||
|
pthread_join(thread, nullptr);
|
||||||
|
#else
|
||||||
if (thread.joinable())
|
if (thread.joinable())
|
||||||
thread.join();
|
thread.join();
|
||||||
|
#endif
|
||||||
|
|
||||||
return STATUS_WAIT_0;
|
return STATUS_WAIT_0;
|
||||||
}
|
}
|
||||||
|
|
@ -80,27 +152,25 @@ uint32_t GuestThread::Start(const GuestThreadParams& params)
|
||||||
return ctx.ppcContext.r3.u32;
|
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)
|
GuestThreadHandle* GuestThread::Start(const GuestThreadParams& params, uint32_t* threadId)
|
||||||
{
|
{
|
||||||
auto hThread = CreateKernelObject<GuestThreadHandle>(params);
|
auto hThread = CreateKernelObject<GuestThreadHandle>(params);
|
||||||
|
|
||||||
if (threadId != nullptr)
|
if (threadId != nullptr)
|
||||||
*threadId = GetThreadId(hThread->thread.get_id());
|
{
|
||||||
|
*threadId = hThread->GetThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
return hThread;
|
return hThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t GuestThread::GetCurrentThreadId()
|
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)
|
void GuestThread::SetLastError(uint32_t error)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@
|
||||||
|
|
||||||
#include <kernel/xdm.h>
|
#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)
|
#define CURRENT_THREAD_HANDLE uint32_t(-2)
|
||||||
|
|
||||||
struct GuestThreadContext
|
struct GuestThreadContext
|
||||||
|
|
@ -24,11 +33,17 @@ struct GuestThreadHandle : KernelObject
|
||||||
{
|
{
|
||||||
GuestThreadParams params;
|
GuestThreadParams params;
|
||||||
std::atomic<bool> suspended;
|
std::atomic<bool> suspended;
|
||||||
|
#ifdef USE_PTHREAD
|
||||||
|
pthread_t thread;
|
||||||
|
#else
|
||||||
std::thread thread;
|
std::thread thread;
|
||||||
|
#endif
|
||||||
|
|
||||||
GuestThreadHandle(const GuestThreadParams& params);
|
GuestThreadHandle(const GuestThreadParams& params);
|
||||||
~GuestThreadHandle() override;
|
~GuestThreadHandle() override;
|
||||||
|
|
||||||
|
uint32_t GetThreadId() const;
|
||||||
|
|
||||||
uint32_t Wait(uint32_t timeout) override;
|
uint32_t Wait(uint32_t timeout) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3437,6 +3437,7 @@ namespace plume {
|
||||||
adapter = adapterOption;
|
adapter = adapterOption;
|
||||||
d3d = deviceOption;
|
d3d = deviceOption;
|
||||||
shaderModel = dataShaderModel.HighestShaderModel;
|
shaderModel = dataShaderModel.HighestShaderModel;
|
||||||
|
capabilities.geometryShader = true;
|
||||||
capabilities.raytracing = rtSupportOption;
|
capabilities.raytracing = rtSupportOption;
|
||||||
capabilities.raytracingStateUpdate = rtStateUpdateSupportOption;
|
capabilities.raytracingStateUpdate = rtStateUpdateSupportOption;
|
||||||
capabilities.sampleLocations = samplePositionsOption;
|
capabilities.sampleLocations = samplePositionsOption;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#undef ControlMask
|
#undef ControlMask
|
||||||
#undef Success
|
#undef Success
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
typedef struct _NSWindow NSWindow;
|
#include <SDL.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SDL_VULKAN_ENABLED
|
#ifdef SDL_VULKAN_ENABLED
|
||||||
|
|
@ -52,7 +52,9 @@ namespace plume {
|
||||||
};
|
};
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
struct RenderWindow {
|
struct RenderWindow {
|
||||||
NSWindow* window;
|
SDL_Window* window;
|
||||||
|
void* view;
|
||||||
|
|
||||||
bool operator==(const struct RenderWindow& rhs) const {
|
bool operator==(const struct RenderWindow& rhs) const {
|
||||||
return window == rhs.window;
|
return window == rhs.window;
|
||||||
}
|
}
|
||||||
|
|
@ -1784,6 +1786,9 @@ namespace plume {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderDeviceCapabilities {
|
struct RenderDeviceCapabilities {
|
||||||
|
// Geometry shaders.
|
||||||
|
bool geometryShader = false;
|
||||||
|
|
||||||
// Raytracing.
|
// Raytracing.
|
||||||
bool raytracing = false;
|
bool raytracing = false;
|
||||||
bool raytracingStateUpdate = false;
|
bool raytracingStateUpdate = false;
|
||||||
|
|
|
||||||
|
|
@ -51,11 +51,16 @@ namespace plume {
|
||||||
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
|
||||||
# elif defined(__linux__)
|
# elif defined(__linux__)
|
||||||
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
|
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
|
||||||
|
# elif defined(__APPLE__)
|
||||||
|
VK_EXT_METAL_SURFACE_EXTENSION_NAME,
|
||||||
# endif
|
# endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const std::unordered_set<std::string> OptionalInstanceExtensions = {
|
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 = {
|
static const std::unordered_set<std::string> RequiredDeviceExtensions = {
|
||||||
|
|
@ -79,6 +84,8 @@ namespace plume {
|
||||||
VK_KHR_PRESENT_ID_EXTENSION_NAME,
|
VK_KHR_PRESENT_ID_EXTENSION_NAME,
|
||||||
VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
|
VK_KHR_PRESENT_WAIT_EXTENSION_NAME,
|
||||||
VK_GOOGLE_DISPLAY_TIMING_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.
|
// 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;
|
VkPipelineStageFlags flags = 0;
|
||||||
|
|
||||||
if (stages & RenderBarrierStage::GRAPHICS) {
|
if (stages & RenderBarrierStage::GRAPHICS) {
|
||||||
flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
|
flags |= VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT;
|
||||||
flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
flags |= VK_PIPELINE_STAGE_VERTEX_INPUT_BIT;
|
||||||
flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
flags |= VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
|
||||||
|
if (geometrySupported) {
|
||||||
flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
|
flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
|
||||||
|
}
|
||||||
flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
flags |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||||
flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
flags |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||||
flags |= VK_PIPELINE_STAGE_LATE_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);
|
fprintf(stderr, "vkCreateXlibSurfaceKHR failed with error code 0x%X.\n", res);
|
||||||
return;
|
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
|
# endif
|
||||||
|
|
||||||
VkBool32 presentSupported = false;
|
VkBool32 presentSupported = false;
|
||||||
|
|
@ -2191,7 +2213,14 @@ namespace plume {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle the error silently.
|
// 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)) {
|
if ((res != VK_SUCCESS) && (res != VK_SUBOPTIMAL_KHR)) {
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2360,6 +2389,8 @@ namespace plume {
|
||||||
// The attributes width and height members do not include the border.
|
// The attributes width and height members do not include the border.
|
||||||
dstWidth = attributes.width;
|
dstWidth = attributes.width;
|
||||||
dstHeight = attributes.height;
|
dstHeight = attributes.height;
|
||||||
|
# elif defined(__APPLE__)
|
||||||
|
SDL_GetWindowSizeInPixels(renderWindow.window, (int *)(&dstWidth), (int *)(&dstHeight));
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2683,9 +2714,10 @@ namespace plume {
|
||||||
|
|
||||||
endActiveRenderPass();
|
endActiveRenderPass();
|
||||||
|
|
||||||
|
const bool geometryEnabled = device->capabilities.geometryShader;
|
||||||
const bool rtEnabled = device->capabilities.raytracing;
|
const bool rtEnabled = device->capabilities.raytracing;
|
||||||
VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
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<VkBufferMemoryBarrier> bufferMemoryBarriers;
|
||||||
thread_local std::vector<VkImageMemoryBarrier> imageMemoryBarriers;
|
thread_local std::vector<VkImageMemoryBarrier> imageMemoryBarriers;
|
||||||
bufferMemoryBarriers.clear();
|
bufferMemoryBarriers.clear();
|
||||||
|
|
@ -2704,7 +2736,7 @@ namespace plume {
|
||||||
bufferMemoryBarrier.offset = 0;
|
bufferMemoryBarrier.offset = 0;
|
||||||
bufferMemoryBarrier.size = interfaceBuffer->desc.size;
|
bufferMemoryBarrier.size = interfaceBuffer->desc.size;
|
||||||
bufferMemoryBarriers.emplace_back(bufferMemoryBarrier);
|
bufferMemoryBarriers.emplace_back(bufferMemoryBarrier);
|
||||||
srcStageMask |= toStageFlags(interfaceBuffer->barrierStages, rtEnabled);
|
srcStageMask |= toStageFlags(interfaceBuffer->barrierStages, geometryEnabled, rtEnabled);
|
||||||
interfaceBuffer->barrierStages = stages;
|
interfaceBuffer->barrierStages = stages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2724,7 +2756,7 @@ namespace plume {
|
||||||
imageMemoryBarrier.subresourceRange.layerCount = interfaceTexture->desc.arraySize;
|
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;
|
imageMemoryBarrier.subresourceRange.aspectMask = (interfaceTexture->desc.flags & RenderTextureFlag::DEPTH_TARGET) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
|
||||||
imageMemoryBarriers.emplace_back(imageMemoryBarrier);
|
imageMemoryBarriers.emplace_back(imageMemoryBarrier);
|
||||||
srcStageMask |= toStageFlags(interfaceTexture->barrierStages, rtEnabled);
|
srcStageMask |= toStageFlags(interfaceTexture->barrierStages, geometryEnabled, rtEnabled);
|
||||||
interfaceTexture->textureLayout = textureBarrier.layout;
|
interfaceTexture->textureLayout = textureBarrier.layout;
|
||||||
interfaceTexture->barrierStages = stages;
|
interfaceTexture->barrierStages = stages;
|
||||||
}
|
}
|
||||||
|
|
@ -2890,6 +2922,9 @@ namespace plume {
|
||||||
offsetVector.clear();
|
offsetVector.clear();
|
||||||
for (uint32_t i = 0; i < viewCount; i++) {
|
for (uint32_t i = 0; i < viewCount; i++) {
|
||||||
const VulkanBuffer *interfaceBuffer = static_cast<const VulkanBuffer *>(views[i].buffer.ref);
|
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);
|
bufferVector.emplace_back((interfaceBuffer != nullptr) ? interfaceBuffer->vk : VK_NULL_HANDLE);
|
||||||
offsetVector.emplace_back(views[i].buffer.offset);
|
offsetVector.emplace_back(views[i].buffer.offset);
|
||||||
}
|
}
|
||||||
|
|
@ -3696,6 +3731,11 @@ namespace plume {
|
||||||
bufferDeviceAddressFeatures.pNext = featuresChain;
|
bufferDeviceAddressFeatures.pNext = featuresChain;
|
||||||
featuresChain = &bufferDeviceAddressFeatures;
|
featuresChain = &bufferDeviceAddressFeatures;
|
||||||
|
|
||||||
|
VkPhysicalDevicePortabilitySubsetFeaturesKHR portabilityFeatures = {};
|
||||||
|
portabilityFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR;
|
||||||
|
portabilityFeatures.pNext = featuresChain;
|
||||||
|
featuresChain = &portabilityFeatures;
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures2 deviceFeatures = {};
|
VkPhysicalDeviceFeatures2 deviceFeatures = {};
|
||||||
deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
deviceFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||||
deviceFeatures.pNext = featuresChain;
|
deviceFeatures.pNext = featuresChain;
|
||||||
|
|
@ -3766,6 +3806,12 @@ namespace plume {
|
||||||
createDeviceChain = &bufferDeviceAddressFeatures;
|
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.
|
// Retrieve the information for the queue families.
|
||||||
uint32_t queueFamilyCount = 0;
|
uint32_t queueFamilyCount = 0;
|
||||||
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr);
|
||||||
|
|
@ -3778,6 +3824,7 @@ namespace plume {
|
||||||
uint32_t familyIndex = 0;
|
uint32_t familyIndex = 0;
|
||||||
uint32_t familySetBits = sizeof(uint32_t) * 8;
|
uint32_t familySetBits = sizeof(uint32_t) * 8;
|
||||||
uint32_t familyQueueCount = 0;
|
uint32_t familyQueueCount = 0;
|
||||||
|
bool familyUsed = false;
|
||||||
for (uint32_t i = 0; i < queueFamilyCount; i++) {
|
for (uint32_t i = 0; i < queueFamilyCount; i++) {
|
||||||
const VkQueueFamilyProperties &props = queueFamilyProperties[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.
|
// 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);
|
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;
|
familyIndex = i;
|
||||||
familySetBits = setBits;
|
familySetBits = setBits;
|
||||||
familyQueueCount = props.queueCount;
|
familyQueueCount = props.queueCount;
|
||||||
|
familyUsed = used;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3912,6 +3962,7 @@ namespace plume {
|
||||||
description.dedicatedVideoMemory = memoryHeapSize;
|
description.dedicatedVideoMemory = memoryHeapSize;
|
||||||
|
|
||||||
// Fill capabilities.
|
// Fill capabilities.
|
||||||
|
capabilities.geometryShader = deviceFeatures.features.geometryShader;
|
||||||
capabilities.raytracing = rtSupported;
|
capabilities.raytracing = rtSupported;
|
||||||
capabilities.raytracingStateUpdate = false;
|
capabilities.raytracingStateUpdate = false;
|
||||||
capabilities.sampleLocations = sampleLocationsSupported;
|
capabilities.sampleLocations = sampleLocationsSupported;
|
||||||
|
|
@ -3920,13 +3971,25 @@ namespace plume {
|
||||||
capabilities.presentWait = presentWait;
|
capabilities.presentWait = presentWait;
|
||||||
capabilities.displayTiming = supportedOptionalExtensions.find(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME) != supportedOptionalExtensions.end();
|
capabilities.displayTiming = supportedOptionalExtensions.find(VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME) != supportedOptionalExtensions.end();
|
||||||
capabilities.preferHDR = memoryHeapSize > (512 * 1024 * 1024);
|
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;
|
capabilities.triangleFan = true;
|
||||||
|
#endif
|
||||||
capabilities.dynamicDepthBias = true;
|
capabilities.dynamicDepthBias = true;
|
||||||
capabilities.uma = (description.type == RenderDeviceType::INTEGRATED) && hasHostVisibleDeviceLocalMemory;
|
capabilities.uma = (description.type == RenderDeviceType::INTEGRATED) && hasHostVisibleDeviceLocalMemory;
|
||||||
capabilities.gpuUploadHeap = capabilities.uma;
|
capabilities.gpuUploadHeap = capabilities.uma;
|
||||||
|
|
||||||
// Fill Vulkan-only capabilities.
|
// Fill Vulkan-only capabilities.
|
||||||
loadStoreOpNoneSupported = supportedOptionalExtensions.find(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME) != supportedOptionalExtensions.end();
|
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() {
|
VulkanDevice::~VulkanDevice() {
|
||||||
|
|
@ -4253,6 +4316,10 @@ namespace plume {
|
||||||
createInfo.ppEnabledLayerNames = nullptr;
|
createInfo.ppEnabledLayerNames = nullptr;
|
||||||
createInfo.enabledLayerCount = 0;
|
createInfo.enabledLayerCount = 0;
|
||||||
|
|
||||||
|
# ifdef __APPLE__
|
||||||
|
createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||||
|
# endif
|
||||||
|
|
||||||
// Check for extensions.
|
// Check for extensions.
|
||||||
uint32_t extensionCount;
|
uint32_t extensionCount;
|
||||||
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,13 @@
|
||||||
#define VK_USE_PLATFORM_ANDROID_KHR
|
#define VK_USE_PLATFORM_ANDROID_KHR
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#define VK_USE_PLATFORM_XLIB_KHR
|
#define VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#define VK_USE_PLATFORM_METAL_EXT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// For VK_KHR_portability_subset
|
||||||
|
#define VK_ENABLE_BETA_EXTENSIONS
|
||||||
|
|
||||||
#include <volk.h>
|
#include <volk.h>
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
|
|
@ -403,7 +408,9 @@ namespace plume {
|
||||||
RenderDeviceDescription description;
|
RenderDeviceDescription description;
|
||||||
VkPhysicalDeviceRayTracingPipelinePropertiesKHR rtPipelineProperties = {};
|
VkPhysicalDeviceRayTracingPipelinePropertiesKHR rtPipelineProperties = {};
|
||||||
VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationProperties = {};
|
VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationProperties = {};
|
||||||
|
std::unique_ptr<RenderBuffer> nullBuffer = nullptr;
|
||||||
bool loadStoreOpNoneSupported = false;
|
bool loadStoreOpNoneSupported = false;
|
||||||
|
bool nullDescriptorSupported = false;
|
||||||
|
|
||||||
VulkanDevice(VulkanInterface *renderInterface, const std::string &preferredDeviceName);
|
VulkanDevice(VulkanInterface *renderInterface, const std::string &preferredDeviceName);
|
||||||
~VulkanDevice() override;
|
~VulkanDevice() override;
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
#include <magic_enum/magic_enum.hpp>
|
#include <magic_enum/magic_enum.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define UNLEASHED_RECOMP
|
||||||
#include "../../tools/XenosRecomp/XenosRecomp/shader_common.h"
|
#include "../../tools/XenosRecomp/XenosRecomp/shader_common.h"
|
||||||
|
|
||||||
#ifdef UNLEASHED_RECOMP_D3D12
|
#ifdef UNLEASHED_RECOMP_D3D12
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,9 @@ void UpdateChecker::visitWebsite()
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
std::string command = "xdg-open " + std::string(VISIT_URL) + " &";
|
std::string command = "xdg-open " + std::string(VISIT_URL) + " &";
|
||||||
std::system(command.c_str());
|
std::system(command.c_str());
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
std::string command = "open " + std::string(VISIT_URL) + " &";
|
||||||
|
std::system(command.c_str());
|
||||||
#else
|
#else
|
||||||
static_assert(false, "Visit website not implemented for this platform.");
|
static_assert(false, "Visit website not implemented for this platform.");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -660,7 +660,7 @@ void KeQueryBasePriorityThread()
|
||||||
|
|
||||||
uint32_t NtSuspendThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
|
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 = true;
|
||||||
hThread->suspended.wait(true);
|
hThread->suspended.wait(true);
|
||||||
|
|
|
||||||
|
|
@ -306,26 +306,26 @@ uint32_t XamContentCreateEx(uint32_t dwUserIndex, const char* szRootName, const
|
||||||
|
|
||||||
if (!exists)
|
if (!exists)
|
||||||
{
|
{
|
||||||
std::string root = "";
|
std::filesystem::path rootPath;
|
||||||
|
|
||||||
if (pContentData->dwContentType == XCONTENTTYPE_SAVEDATA)
|
if (pContentData->dwContentType == XCONTENTTYPE_SAVEDATA)
|
||||||
{
|
{
|
||||||
std::u8string savePathU8 = GetSavePath(true).u8string();
|
rootPath = GetSavePath(true);
|
||||||
root = (const char *)(savePathU8.c_str());
|
|
||||||
}
|
}
|
||||||
else if (pContentData->dwContentType == XCONTENTTYPE_DLC)
|
else if (pContentData->dwContentType == XCONTENTTYPE_DLC)
|
||||||
{
|
{
|
||||||
root = GAME_INSTALL_DIRECTORY "/dlc";
|
rootPath = GetGamePath() / "dlc";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
root = GAME_INSTALL_DIRECTORY;
|
rootPath = GetGamePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string root = (const char*)rootPath.u8string().c_str();
|
||||||
XamRegisterContent(*pContentData, root);
|
XamRegisterContent(*pContentData, root);
|
||||||
|
|
||||||
std::error_code ec;
|
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);
|
XamRootCreate(szRootName, root);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include <stdafx.h>
|
#include <stdafx.h>
|
||||||
|
#ifdef __x86_64__
|
||||||
#include <cpuid.h>
|
#include <cpuid.h>
|
||||||
|
#endif
|
||||||
#include <cpu/guest_thread.h>
|
#include <cpu/guest_thread.h>
|
||||||
#include <gpu/video.h>
|
#include <gpu/video.h>
|
||||||
#include <kernel/function.h>
|
#include <kernel/function.h>
|
||||||
|
|
@ -69,8 +71,10 @@ void KiSystemStartup()
|
||||||
|
|
||||||
const auto gameContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Game");
|
const auto gameContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Game");
|
||||||
const auto updateContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Update");
|
const auto updateContent = XamMakeContent(XCONTENTTYPE_RESERVED, "Update");
|
||||||
XamRegisterContent(gameContent, GAME_INSTALL_DIRECTORY "/game");
|
const std::string gamePath = (const char*)(GetGamePath() / "game").u8string().c_str();
|
||||||
XamRegisterContent(updateContent, GAME_INSTALL_DIRECTORY "/update");
|
const std::string updatePath = (const char*)(GetGamePath() / "update").u8string().c_str();
|
||||||
|
XamRegisterContent(gameContent, gamePath);
|
||||||
|
XamRegisterContent(updateContent, updatePath);
|
||||||
|
|
||||||
const auto saveFilePath = GetSaveFilePath(true);
|
const auto saveFilePath = GetSaveFilePath(true);
|
||||||
bool saveFileExists = std::filesystem::exists(saveFilePath);
|
bool saveFileExists = std::filesystem::exists(saveFilePath);
|
||||||
|
|
@ -102,7 +106,7 @@ void KiSystemStartup()
|
||||||
XamContentCreateEx(0, "D", &gameContent, OPEN_EXISTING, nullptr, nullptr, 0, 0, nullptr);
|
XamContentCreateEx(0, "D", &gameContent, OPEN_EXISTING, nullptr, nullptr, 0, 0, nullptr);
|
||||||
|
|
||||||
std::error_code ec;
|
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())
|
if (file.is_directory())
|
||||||
{
|
{
|
||||||
|
|
@ -165,10 +169,10 @@ uint32_t LdrLoadModule(const std::filesystem::path &path)
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
__attribute__((constructor(101), target("no-avx,no-avx2"), noinline))
|
__attribute__((constructor(101), target("no-avx,no-avx2"), noinline))
|
||||||
void init()
|
void init()
|
||||||
{
|
{
|
||||||
#ifdef __x86_64__
|
|
||||||
uint32_t eax, ebx, ecx, edx;
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
|
||||||
// Execute CPUID for processor info and feature bits.
|
// Execute CPUID for processor info and feature bits.
|
||||||
|
|
@ -185,8 +189,8 @@ void init()
|
||||||
|
|
||||||
std::_Exit(1);
|
std::_Exit(1);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
@ -232,7 +236,7 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
// Set the current working directory to the executable's path.
|
// Set the current working directory to the executable's path.
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
std::filesystem::current_path(os::process::GetExecutablePath().parent_path(), ec);
|
std::filesystem::current_path(os::process::GetExecutableRoot(), ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::Load();
|
Config::Load();
|
||||||
|
|
@ -321,7 +325,7 @@ int main(int argc, char *argv[])
|
||||||
HostStartup();
|
HostStartup();
|
||||||
|
|
||||||
std::filesystem::path modulePath;
|
std::filesystem::path modulePath;
|
||||||
bool isGameInstalled = Installer::checkGameInstall(GAME_INSTALL_DIRECTORY, modulePath);
|
bool isGameInstalled = Installer::checkGameInstall(GetGamePath(), modulePath);
|
||||||
bool runInstallerWizard = forceInstaller || forceDLCInstaller || !isGameInstalled;
|
bool runInstallerWizard = forceInstaller || forceDLCInstaller || !isGameInstalled;
|
||||||
if (runInstallerWizard)
|
if (runInstallerWizard)
|
||||||
{
|
{
|
||||||
|
|
@ -331,7 +335,7 @@ int main(int argc, char *argv[])
|
||||||
std::_Exit(1);
|
std::_Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!InstallerWizard::Run(GAME_INSTALL_DIRECTORY, isGameInstalled && forceDLCInstaller))
|
if (!InstallerWizard::Run(GetGamePath(), isGameInstalled && forceDLCInstaller))
|
||||||
{
|
{
|
||||||
std::_Exit(0);
|
std::_Exit(0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ void ModLoader::Init()
|
||||||
{
|
{
|
||||||
configIni = {};
|
configIni = {};
|
||||||
|
|
||||||
if (!configIni.read(GAME_INSTALL_DIRECTORY "/cpkredir.ini"))
|
if (!configIni.read(GetGamePath() / "cpkredir.ini"))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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()
|
std::filesystem::path os::process::GetWorkingDirectory()
|
||||||
{
|
{
|
||||||
char cwd[PATH_MAX] = {};
|
char cwd[PATH_MAX] = {};
|
||||||
|
|
|
||||||
17
UnleashedRecomp/os/macos/logger_macos.cpp
Normal file
17
UnleashedRecomp/os/macos/logger_macos.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
7
UnleashedRecomp/os/macos/media_macos.cpp
Normal file
7
UnleashedRecomp/os/macos/media_macos.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <os/media.h>
|
||||||
|
|
||||||
|
bool os::media::IsExternalMediaPlaying()
|
||||||
|
{
|
||||||
|
// This functionality is not supported in macOS.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
97
UnleashedRecomp/os/macos/process_macos.cpp
Normal file
97
UnleashedRecomp/os/macos/process_macos.cpp
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::filesystem::path os::process::GetExecutableRoot()
|
||||||
|
{
|
||||||
|
std::filesystem::path resultPath = GetExecutablePath().remove_filename();
|
||||||
|
if (CFBundleRef bundleRef = CFBundleGetMainBundle())
|
||||||
|
{
|
||||||
|
if (CFURLRef bundleUrlRef = CFBundleCopyBundleURL(bundleRef))
|
||||||
|
{
|
||||||
|
char appBundlePath[MAXPATHLEN];
|
||||||
|
if (CFURLGetFileSystemRepresentation(bundleUrlRef, true, (uint8_t*)(appBundlePath), sizeof(appBundlePath)))
|
||||||
|
{
|
||||||
|
resultPath = std::filesystem::path(appBundlePath).parent_path();
|
||||||
|
}
|
||||||
|
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.
|
||||||
|
}
|
||||||
21
UnleashedRecomp/os/macos/registry_macos.inl
Normal file
21
UnleashedRecomp/os/macos/registry_macos.inl
Normal 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;
|
||||||
|
}
|
||||||
6
UnleashedRecomp/os/macos/user_macos.cpp
Normal file
6
UnleashedRecomp/os/macos/user_macos.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include <os/user.h>
|
||||||
|
|
||||||
|
bool os::user::IsDarkTheme()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
7
UnleashedRecomp/os/macos/version_macos.cpp
Normal file
7
UnleashedRecomp/os/macos/version_macos.cpp
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#include <os/version.h>
|
||||||
|
|
||||||
|
os::version::OSVersion os::version::GetOSVersion()
|
||||||
|
{
|
||||||
|
assert(false && "Unimplemented.");
|
||||||
|
return os::version::OSVersion();
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ namespace os::process
|
||||||
inline bool g_consoleVisible;
|
inline bool g_consoleVisible;
|
||||||
|
|
||||||
std::filesystem::path GetExecutablePath();
|
std::filesystem::path GetExecutablePath();
|
||||||
|
std::filesystem::path GetExecutableRoot();
|
||||||
std::filesystem::path GetWorkingDirectory();
|
std::filesystem::path GetWorkingDirectory();
|
||||||
bool SetWorkingDirectory(const std::filesystem::path& path);
|
bool SetWorkingDirectory(const std::filesystem::path& path);
|
||||||
bool StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work = {});
|
bool StartProcess(const std::filesystem::path& path, const std::vector<std::string>& args, std::filesystem::path work = {});
|
||||||
|
|
|
||||||
|
|
@ -15,4 +15,6 @@ namespace os::registry
|
||||||
#include <os/win32/registry_win32.inl>
|
#include <os/win32/registry_win32.inl>
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <os/linux/registry_linux.inl>
|
#include <os/linux/registry_linux.inl>
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
#include <os/macos/registry_macos.inl>
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,11 @@ std::filesystem::path os::process::GetExecutablePath()
|
||||||
return std::filesystem::path(exePath);
|
return std::filesystem::path(exePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::filesystem::path os::process::GetExecutableRoot()
|
||||||
|
{
|
||||||
|
return GetExecutablePath().remove_filename();
|
||||||
|
}
|
||||||
|
|
||||||
std::filesystem::path os::process::GetWorkingDirectory()
|
std::filesystem::path os::process::GetWorkingDirectory()
|
||||||
{
|
{
|
||||||
WCHAR workPath[MAX_PATH];
|
WCHAR workPath[MAX_PATH];
|
||||||
|
|
|
||||||
42
UnleashedRecomp/res/macos/MacOSXBundleInfo.plist.in
Normal file
42
UnleashedRecomp/res/macos/MacOSXBundleInfo.plist.in
Normal 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>
|
||||||
BIN
UnleashedRecomp/res/macos/game_icon.icns
Normal file
BIN
UnleashedRecomp/res/macos/game_icon.icns
Normal file
Binary file not shown.
|
|
@ -20,7 +20,7 @@ std::unique_ptr<GuestTexture> g_upKBMIcons;
|
||||||
|
|
||||||
float g_sideMargins = DEFAULT_SIDE_MARGINS;
|
float g_sideMargins = DEFAULT_SIDE_MARGINS;
|
||||||
|
|
||||||
std::vector<Button> g_buttons;
|
static std::vector<Button> g_buttons;
|
||||||
|
|
||||||
std::unordered_map<EButtonIcon, float> g_iconWidths =
|
std::unordered_map<EButtonIcon, float> g_iconWidths =
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,9 @@ void GameWindow::Init(const char* sdlVideoDriver)
|
||||||
s_renderWindow = s_pWindow;
|
s_renderWindow = s_pWindow;
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
s_renderWindow = { info.info.x11.display, info.info.x11.window };
|
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
|
#else
|
||||||
static_assert(false, "Unknown platform.");
|
static_assert(false, "Unknown platform.");
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1146,7 +1146,11 @@ static void PickerStart(bool folderMode) {
|
||||||
g_currentPickerVisible = true;
|
g_currentPickerVisible = true;
|
||||||
|
|
||||||
// Optional single thread mode for testing on systems that do not interact well with the separate thread being used for NFD.
|
// 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;
|
constexpr bool singleThreadMode = false;
|
||||||
|
#endif
|
||||||
if (singleThreadMode)
|
if (singleThreadMode)
|
||||||
PickerThreadProcess();
|
PickerThreadProcess();
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ static ImFont* g_fntSeurat;
|
||||||
|
|
||||||
std::string g_text;
|
std::string g_text;
|
||||||
int g_result;
|
int g_result;
|
||||||
std::vector<std::string> g_buttons;
|
static std::vector<std::string> g_buttons;
|
||||||
int g_defaultButtonIndex;
|
int g_defaultButtonIndex;
|
||||||
int g_cancelButtonIndex;
|
int g_cancelButtonIndex;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include "paths.h"
|
#include "paths.h"
|
||||||
#include <os/process.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();
|
std::filesystem::path g_userPath = BuildUserPath();
|
||||||
|
|
||||||
bool CheckPortable()
|
bool CheckPortable()
|
||||||
|
|
@ -22,18 +22,24 @@ std::filesystem::path BuildUserPath()
|
||||||
userPath = std::filesystem::path{ knownPath } / USER_DIRECTORY;
|
userPath = std::filesystem::path{ knownPath } / USER_DIRECTORY;
|
||||||
|
|
||||||
CoTaskMemFree(knownPath);
|
CoTaskMemFree(knownPath);
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__) || defined(__APPLE__)
|
||||||
const char* homeDir = getenv("HOME");
|
const char* homeDir = getenv("HOME");
|
||||||
|
#if defined(__linux__)
|
||||||
if (homeDir == nullptr)
|
if (homeDir == nullptr)
|
||||||
{
|
{
|
||||||
homeDir = getpwuid(getuid())->pw_dir;
|
homeDir = getpwuid(getuid())->pw_dir;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (homeDir != nullptr)
|
if (homeDir != nullptr)
|
||||||
{
|
{
|
||||||
// Prefer to store in the .config directory if it exists. Use the home directory otherwise.
|
// Prefer to store in the .config directory if it exists. Use the home directory otherwise.
|
||||||
std::filesystem::path homePath = homeDir;
|
std::filesystem::path homePath = homeDir;
|
||||||
|
#if defined(__linux__)
|
||||||
std::filesystem::path configPath = homePath / ".config";
|
std::filesystem::path configPath = homePath / ".config";
|
||||||
|
#else
|
||||||
|
std::filesystem::path configPath = homePath / "Library" / "Application Support";
|
||||||
|
#endif
|
||||||
if (std::filesystem::exists(configPath))
|
if (std::filesystem::exists(configPath))
|
||||||
userPath = configPath / USER_DIRECTORY;
|
userPath = configPath / USER_DIRECTORY;
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,22 @@
|
||||||
|
|
||||||
extern std::filesystem::path g_executableRoot;
|
extern std::filesystem::path g_executableRoot;
|
||||||
|
|
||||||
inline std::filesystem::path GetGamePath()
|
|
||||||
{
|
|
||||||
return GAME_INSTALL_DIRECTORY;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CheckPortable();
|
bool CheckPortable();
|
||||||
std::filesystem::path BuildUserPath();
|
std::filesystem::path BuildUserPath();
|
||||||
const std::filesystem::path& GetUserPath();
|
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)
|
inline std::filesystem::path GetSavePath(bool checkForMods)
|
||||||
{
|
{
|
||||||
if (checkForMods && !ModLoader::s_saveFilePath.empty())
|
if (checkForMods && !ModLoader::s_saveFilePath.empty())
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ add_custom_command(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex"
|
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xexp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/private/default.xexp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml"
|
"${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml"
|
||||||
|
USES_TERMINAL
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
|
|
@ -53,6 +54,7 @@ target_compile_definitions(XenosRecomp PRIVATE
|
||||||
XENOS_RECOMP_INPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/private\"
|
XENOS_RECOMP_INPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/private\"
|
||||||
XENOS_RECOMP_OUTPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/shader/shader_cache.cpp\"
|
XENOS_RECOMP_OUTPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/shader/shader_cache.cpp\"
|
||||||
XENOS_RECOMP_INCLUDE_INPUT=\"${XENOS_RECOMP_INCLUDE}\"
|
XENOS_RECOMP_INCLUDE_INPUT=\"${XENOS_RECOMP_INCLUDE}\"
|
||||||
|
UNLEASHED_RECOMP
|
||||||
)
|
)
|
||||||
|
|
||||||
file(GLOB XENOS_RECOMP_SOURCES
|
file(GLOB XENOS_RECOMP_SOURCES
|
||||||
|
|
@ -70,6 +72,7 @@ add_custom_command(
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/private/shader_decompressed.ar"
|
"${CMAKE_CURRENT_SOURCE_DIR}/private/shader_decompressed.ar"
|
||||||
${XENOS_RECOMP_SOURCES}
|
${XENOS_RECOMP_SOURCES}
|
||||||
${XENOS_RECOMP_INCLUDE}
|
${XENOS_RECOMP_INCLUDE}
|
||||||
|
USES_TERMINAL
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(UnleashedRecompLib
|
add_library(UnleashedRecompLib
|
||||||
|
|
@ -79,4 +82,5 @@ add_library(UnleashedRecompLib
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(UnleashedRecompLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
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")
|
target_precompile_headers(UnleashedRecompLib PUBLIC "ppc/ppc_recomp_shared.h")
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,21 @@ You can also find the equivalent packages for your preferred distro.
|
||||||
> [!NOTE]
|
> [!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.
|
> 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 Xcode 16.3+ or the equivalent 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
|
## 4. Build the Project
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
@ -81,3 +96,22 @@ cmake --build ./out/build/linux-release --target UnleashedRecomp
|
||||||
```bash
|
```bash
|
||||||
./UnleashedRecomp
|
./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
|
||||||
|
```
|
||||||
|
|
|
||||||
4
thirdparty/CMakeLists.txt
vendored
4
thirdparty/CMakeLists.txt
vendored
|
|
@ -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}/o1heap")
|
||||||
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL")
|
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL")
|
||||||
add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/SDL_mixer")
|
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
86
thirdparty/MoltenVK/CMakeLists.txt
vendored
Normal 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
1
thirdparty/MoltenVK/MoltenVK
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 3a0b07a24a4a681ffe70b461b1f4333b2729e2ef
|
||||||
1
thirdparty/MoltenVK/SPIRV-Cross
vendored
Submodule
1
thirdparty/MoltenVK/SPIRV-Cross
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 22b22f5685d868828be01c9ac00c31902e60afd9
|
||||||
2
thirdparty/Vulkan-Headers
vendored
2
thirdparty/Vulkan-Headers
vendored
|
|
@ -1 +1 @@
|
||||||
Subproject commit 14345dab231912ee9601136e96ca67a6e1f632e7
|
Subproject commit 75ad707a587e1469fb53a901b9b68fe9f6fbc11f
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit c017eb630ab917bffd3bc6a0a46995b49e7d8049
|
Subproject commit c5bfd90d87f2ed0db8cff5c19ea3aff0e161e527
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 56738e5893ed7c4dc108996590475c52726623e3
|
Subproject commit 990d03b28a27b50277ee5d8d942e1c5f873869d1
|
||||||
|
|
@ -9,8 +9,12 @@
|
||||||
"name": "directx12-agility",
|
"name": "directx12-agility",
|
||||||
"platform": "windows"
|
"platform": "windows"
|
||||||
},
|
},
|
||||||
"directx-dxc",
|
|
||||||
"freetype",
|
"freetype",
|
||||||
"curl"
|
"curl"
|
||||||
|
],
|
||||||
|
"vcpkg-configuration": {
|
||||||
|
"overlay-triplets": [
|
||||||
|
"vcpkg/triplets"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
7
vcpkg/triplets/arm64-osx.cmake
Normal file
7
vcpkg/triplets/arm64-osx.cmake
Normal 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")
|
||||||
7
vcpkg/triplets/x64-osx.cmake
Normal file
7
vcpkg/triplets/x64-osx.cmake
Normal 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")
|
||||||
Loading…
Add table
Reference in a new issue