mirror of
				https://github.com/hedge-dev/UnleashedRecomp.git
				synced 2025-10-30 07:11:05 +00:00 
			
		
		
		
	Compare commits
	
		
			1 commit
		
	
	
		
			d739f3b35d
			...
			5d3ab002ff
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
							 | 
						5d3ab002ff | 
					 47 changed files with 890 additions and 142 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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										10
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										10
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -1,12 +1,12 @@
 | 
				
			||||||
[submodule "tools/XenonRecomp"]
 | 
					[submodule "tools/XenonRecomp"]
 | 
				
			||||||
	path = tools/XenonRecomp
 | 
						path = tools/XenonRecomp
 | 
				
			||||||
	url = https://github.com/hedge-dev/XenonRecomp.git
 | 
						url = https://github.com/squidbus/XenonRecomp.git
 | 
				
			||||||
[submodule "thirdparty/ddspp"]
 | 
					[submodule "thirdparty/ddspp"]
 | 
				
			||||||
	path = thirdparty/ddspp
 | 
						path = thirdparty/ddspp
 | 
				
			||||||
	url = https://github.com/redorav/ddspp.git
 | 
						url = https://github.com/redorav/ddspp.git
 | 
				
			||||||
[submodule "tools/XenosRecomp"]
 | 
					[submodule "tools/XenosRecomp"]
 | 
				
			||||||
	path = tools/XenosRecomp
 | 
						path = tools/XenosRecomp
 | 
				
			||||||
	url = https://github.com/hedge-dev/XenosRecomp.git
 | 
						url = https://github.com/squidbus/XenosRecomp.git
 | 
				
			||||||
[submodule "UnleashedRecompResources"]
 | 
					[submodule "UnleashedRecompResources"]
 | 
				
			||||||
	path = UnleashedRecompResources
 | 
						path = UnleashedRecompResources
 | 
				
			||||||
	url = https://github.com/hedge-dev/UnleashedRecompResources.git
 | 
						url = https://github.com/hedge-dev/UnleashedRecompResources.git
 | 
				
			||||||
| 
						 | 
					@ -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>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
					    # Target Sandy Bridge for all projects
 | 
				
			||||||
    add_compile_options(
 | 
					    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
 | 
				
			||||||
| 
						 | 
					@ -410,11 +463,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);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
					    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())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,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 
 | 
				
			||||||
| 
						 | 
					@ -79,4 +80,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 8c6adcff4a5a74e7120cf1b3fc741ace84beb677
 | 
				
			||||||
| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
Subproject commit 56738e5893ed7c4dc108996590475c52726623e3
 | 
					Subproject commit c961d288f2c7f8b9925d1232671cf602c2230805
 | 
				
			||||||
| 
						 | 
					@ -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