mirror of
				https://github.com/hedge-dev/UnleashedRecomp.git
				synced 2025-10-30 07:11:05 +00:00 
			
		
		
		
	Compare commits
	
		
			4 commits
		
	
	
		
			d5de86d53b
			...
			901654fed1
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 901654fed1 | ||
|   | 9ace79a4d2 | ||
|   | 80e779afd9 | ||
|   | 7740f6587d | 
					 59 changed files with 876 additions and 11828 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 | ||||||
|  |  | ||||||
							
								
								
									
										21
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								.gitmodules
									
										
									
									
										vendored
									
									
								
							|  | @ -16,21 +16,9 @@ | ||||||
| [submodule "thirdparty/vcpkg"] | [submodule "thirdparty/vcpkg"] | ||||||
| 	path = thirdparty/vcpkg | 	path = thirdparty/vcpkg | ||||||
| 	url = https://github.com/microsoft/vcpkg | 	url = https://github.com/microsoft/vcpkg | ||||||
| [submodule "thirdparty/volk"] |  | ||||||
| 	path = thirdparty/volk |  | ||||||
| 	url = https://github.com/zeux/volk |  | ||||||
| [submodule "thirdparty/SDL"] | [submodule "thirdparty/SDL"] | ||||||
| 	path = thirdparty/SDL | 	path = thirdparty/SDL | ||||||
| 	url = https://github.com/libsdl-org/SDL.git | 	url = https://github.com/libsdl-org/SDL.git | ||||||
| [submodule "thirdparty/Vulkan-Headers"] |  | ||||||
| 	path = thirdparty/Vulkan-Headers |  | ||||||
| 	url = https://github.com/KhronosGroup/Vulkan-Headers.git |  | ||||||
| [submodule "thirdparty/VulkanMemoryAllocator"] |  | ||||||
| 	path = thirdparty/VulkanMemoryAllocator |  | ||||||
| 	url = https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator.git |  | ||||||
| [submodule "thirdparty/D3D12MemoryAllocator"] |  | ||||||
| 	path = thirdparty/D3D12MemoryAllocator |  | ||||||
| 	url = https://github.com/GPUOpen-LibrariesAndSDKs/D3D12MemoryAllocator.git |  | ||||||
| [submodule "thirdparty/stb"] | [submodule "thirdparty/stb"] | ||||||
| 	path = thirdparty/stb | 	path = thirdparty/stb | ||||||
| 	url = https://github.com/nothings/stb.git | 	url = https://github.com/nothings/stb.git | ||||||
|  | @ -61,3 +49,12 @@ | ||||||
| [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 | ||||||
|  | [submodule "thirdparty/plume"] | ||||||
|  | 	path = thirdparty/plume | ||||||
|  | 	url = https://github.com/renderbag/plume.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,36 @@ endif() | ||||||
| 
 | 
 | ||||||
| set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") | set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") | ||||||
| 
 | 
 | ||||||
|  | project("UnleashedRecomp-ALL") | ||||||
|  | 
 | ||||||
|  | if (APPLE) | ||||||
|  |     enable_language(OBJC OBJCXX) | ||||||
|  | endif() | ||||||
|  | 
 | ||||||
|  | if (CMAKE_SYSTEM_NAME MATCHES "Linux") | ||||||
|  |     set(SDL_VULKAN_ENABLED ON CACHE BOOL "") | ||||||
|  | endif() | ||||||
|  | 
 | ||||||
|  | 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 | ||||||
|  | @ -108,15 +116,8 @@ set(UNLEASHED_RECOMP_GPU_CXX_SOURCES | ||||||
|     "gpu/imgui/imgui_common.cpp" |     "gpu/imgui/imgui_common.cpp" | ||||||
|     "gpu/imgui/imgui_font_builder.cpp" |     "gpu/imgui/imgui_font_builder.cpp" | ||||||
|     "gpu/imgui/imgui_snapshot.cpp" |     "gpu/imgui/imgui_snapshot.cpp" | ||||||
|     "gpu/rhi/plume_vulkan.cpp" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| if (UNLEASHED_RECOMP_D3D12) |  | ||||||
|     list(APPEND UNLEASHED_RECOMP_GPU_CXX_SOURCES |  | ||||||
|         "gpu/rhi/plume_d3d12.cpp" |  | ||||||
|     ) |  | ||||||
| endif() |  | ||||||
| 
 |  | ||||||
| set(UNLEASHED_RECOMP_APU_CXX_SOURCES | set(UNLEASHED_RECOMP_APU_CXX_SOURCES | ||||||
|     "apu/audio.cpp" |     "apu/audio.cpp" | ||||||
|     "apu/embedded_player.cpp" |     "apu/embedded_player.cpp" | ||||||
|  | @ -213,18 +214,10 @@ set(UNLEASHED_RECOMP_THIRDPARTY_INCLUDES | ||||||
|     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include" |     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/magic_enum/include" | ||||||
|     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb" |     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/stb" | ||||||
|     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/unordered_dense/include" |     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/unordered_dense/include" | ||||||
|     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/volk" |  | ||||||
|     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/Vulkan-Headers/include" |  | ||||||
|     "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/VulkanMemoryAllocator/include" |  | ||||||
|     "${UNLEASHED_RECOMP_TOOLS_ROOT}/bc_diff" |     "${UNLEASHED_RECOMP_TOOLS_ROOT}/bc_diff" | ||||||
|     "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/thirdparty/smol-v/source" |     "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenosRecomp/thirdparty/smol-v/source" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| if (UNLEASHED_RECOMP_D3D12) |  | ||||||
|     list(APPEND UNLEASHED_RECOMP_THIRDPARTY_INCLUDES "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/D3D12MemoryAllocator/include") |  | ||||||
|     list(APPEND UNLEASHED_RECOMP_THIRDPARTY_SOURCES "${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/D3D12MemoryAllocator/src/D3D12MemAlloc.cpp") |  | ||||||
| endif() |  | ||||||
| 
 |  | ||||||
| set_source_files_properties(${UNLEASHED_RECOMP_THIRDPARTY_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) | set_source_files_properties(${UNLEASHED_RECOMP_THIRDPARTY_SOURCES} PROPERTIES SKIP_PRECOMPILE_HEADERS ON) | ||||||
| 
 | 
 | ||||||
| set(UNLEASHED_RECOMP_CXX_SOURCES | set(UNLEASHED_RECOMP_CXX_SOURCES | ||||||
|  | @ -299,6 +292,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() | ||||||
|  | @ -320,24 +362,22 @@ if (UNLEASHED_RECOMP_D3D12) | ||||||
|     ) |     ) | ||||||
| endif() | endif() | ||||||
| 
 | 
 | ||||||
| if (CMAKE_SYSTEM_NAME MATCHES "Linux") | if (SDL_VULKAN_ENABLED) | ||||||
|     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 +388,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 | ||||||
|  | @ -375,6 +413,7 @@ target_link_libraries(UnleashedRecomp PRIVATE | ||||||
|     UnleashedRecompLib |     UnleashedRecompLib | ||||||
|     xxHash::xxhash |     xxHash::xxhash | ||||||
|     CURL::libcurl |     CURL::libcurl | ||||||
|  |     plume | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| target_include_directories(UnleashedRecomp PRIVATE | target_include_directories(UnleashedRecomp PRIVATE | ||||||
|  | @ -411,11 +450,11 @@ function(compile_shader FILE_PATH TARGET_NAME) | ||||||
| endfunction() | endfunction() | ||||||
| 
 | 
 | ||||||
| function(compile_vertex_shader FILE_PATH) | function(compile_vertex_shader FILE_PATH) | ||||||
|     compile_shader(${FILE_PATH} vs_6_0 -fvk-invert-y) |     compile_shader(${FILE_PATH} vs_6_0 -fvk-invert-y -DUNLEASHED_RECOMP) | ||||||
| endfunction() | endfunction() | ||||||
| 
 | 
 | ||||||
| function(compile_pixel_shader FILE_PATH) | function(compile_pixel_shader FILE_PATH) | ||||||
|     compile_shader(${FILE_PATH} ps_6_0) |     compile_shader(${FILE_PATH} ps_6_0 -DUNLEASHED_RECOMP) | ||||||
| endfunction() | endfunction() | ||||||
| 
 | 
 | ||||||
| compile_pixel_shader(blend_color_alpha_ps) | compile_pixel_shader(blend_color_alpha_ps) | ||||||
|  |  | ||||||
|  | @ -40,29 +40,101 @@ GuestThreadContext::~GuestThreadContext() | ||||||
|     g_userHeap.Free(thread); |     g_userHeap.Free(thread); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef USE_PTHREAD | ||||||
|  | static size_t GetStackSize() | ||||||
|  | { | ||||||
|  |     // Cache as this should not change.
 | ||||||
|  |     static size_t stackSize = 0; | ||||||
|  |     if (stackSize == 0) | ||||||
|  |     { | ||||||
|  |         // 8 MiB is a typical default.
 | ||||||
|  |         constexpr auto defaultSize = 8 * 1024 * 1024; | ||||||
|  |         struct rlimit lim; | ||||||
|  |         const auto ret = getrlimit(RLIMIT_STACK, &lim); | ||||||
|  |         if (ret == 0 && lim.rlim_cur < defaultSize) | ||||||
|  |         { | ||||||
|  |             // Use what the system allows.
 | ||||||
|  |             stackSize = lim.rlim_cur; | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |         { | ||||||
|  |             stackSize = defaultSize; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return stackSize; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void* GuestThreadFunc(void* arg) | ||||||
|  | { | ||||||
|  |     GuestThreadHandle* hThread = (GuestThreadHandle*)arg; | ||||||
|  | #else | ||||||
| static void GuestThreadFunc(GuestThreadHandle* hThread) | static void GuestThreadFunc(GuestThreadHandle* hThread) | ||||||
| { | { | ||||||
|  | #endif | ||||||
|     hThread->suspended.wait(true); |     hThread->suspended.wait(true); | ||||||
|     GuestThread::Start(hThread->params); |     GuestThread::Start(hThread->params); | ||||||
|  | #ifdef USE_PTHREAD | ||||||
|  |     return nullptr; | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| GuestThreadHandle::GuestThreadHandle(const GuestThreadParams& params) | GuestThreadHandle::GuestThreadHandle(const GuestThreadParams& params) | ||||||
|     : params(params), suspended((params.flags & 0x1) != 0), thread(GuestThreadFunc, this) |     : params(params), suspended((params.flags & 0x1) != 0) | ||||||
|  | #ifdef USE_PTHREAD | ||||||
|  | { | ||||||
|  |     pthread_attr_t attr; | ||||||
|  |     pthread_attr_init(&attr); | ||||||
|  |     pthread_attr_setstacksize(&attr, GetStackSize()); | ||||||
|  |     const auto ret = pthread_create(&thread, &attr, GuestThreadFunc, this); | ||||||
|  |     if (ret != 0) { | ||||||
|  |         fprintf(stderr, "pthread_create failed with error code 0x%X.\n", ret); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | #else | ||||||
|  |       , thread(GuestThreadFunc, this) | ||||||
| { | { | ||||||
| } | } | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| GuestThreadHandle::~GuestThreadHandle() | GuestThreadHandle::~GuestThreadHandle() | ||||||
| { | { | ||||||
|  | #ifdef USE_PTHREAD | ||||||
|  |     pthread_join(thread, nullptr); | ||||||
|  | #else | ||||||
|     if (thread.joinable()) |     if (thread.joinable()) | ||||||
|         thread.join(); |         thread.join(); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template <typename ThreadType> | ||||||
|  | static uint32_t CalcThreadId(const ThreadType& id) | ||||||
|  | { | ||||||
|  |     if constexpr (sizeof(id) == 4) | ||||||
|  |         return *reinterpret_cast<const uint32_t*>(&id); | ||||||
|  |     else | ||||||
|  |         return XXH32(&id, sizeof(id), 0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | uint32_t GuestThreadHandle::GetThreadId() const | ||||||
|  | { | ||||||
|  | #ifdef USE_PTHREAD | ||||||
|  |     return CalcThreadId(thread); | ||||||
|  | #else | ||||||
|  |     return CalcThreadId(thread.get_id()); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint32_t GuestThreadHandle::Wait(uint32_t timeout) | uint32_t GuestThreadHandle::Wait(uint32_t timeout) | ||||||
| { | { | ||||||
|     assert(timeout == INFINITE); |     assert(timeout == INFINITE); | ||||||
| 
 | 
 | ||||||
|  | #ifdef USE_PTHREAD | ||||||
|  |     pthread_join(thread, nullptr); | ||||||
|  | #else | ||||||
|     if (thread.joinable()) |     if (thread.joinable()) | ||||||
|         thread.join(); |         thread.join(); | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     return STATUS_WAIT_0; |     return STATUS_WAIT_0; | ||||||
| } | } | ||||||
|  | @ -80,27 +152,25 @@ uint32_t GuestThread::Start(const GuestThreadParams& params) | ||||||
|     return ctx.ppcContext.r3.u32; |     return ctx.ppcContext.r3.u32; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static uint32_t GetThreadId(const std::thread::id& id) |  | ||||||
| { |  | ||||||
|     if constexpr (sizeof(id) == 4) |  | ||||||
|         return *reinterpret_cast<const uint32_t*>(&id); |  | ||||||
|     else |  | ||||||
|         return XXH32(&id, sizeof(id), 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| GuestThreadHandle* GuestThread::Start(const GuestThreadParams& params, uint32_t* threadId) | GuestThreadHandle* GuestThread::Start(const GuestThreadParams& params, uint32_t* threadId) | ||||||
| { | { | ||||||
|     auto hThread = CreateKernelObject<GuestThreadHandle>(params); |     auto hThread = CreateKernelObject<GuestThreadHandle>(params); | ||||||
| 
 | 
 | ||||||
|     if (threadId != nullptr) |     if (threadId != nullptr) | ||||||
|         *threadId = GetThreadId(hThread->thread.get_id()); |     { | ||||||
|  |         *threadId = hThread->GetThreadId(); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     return hThread; |     return hThread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint32_t GuestThread::GetCurrentThreadId() | uint32_t GuestThread::GetCurrentThreadId() | ||||||
| { | { | ||||||
|     return GetThreadId(std::this_thread::get_id()); | #ifdef USE_PTHREAD | ||||||
|  |     return CalcThreadId(pthread_self()); | ||||||
|  | #else | ||||||
|  |     return CalcThreadId(std::this_thread::get_id()); | ||||||
|  | #endif | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GuestThread::SetLastError(uint32_t error) | void GuestThread::SetLastError(uint32_t error) | ||||||
|  |  | ||||||
|  | @ -2,6 +2,15 @@ | ||||||
| 
 | 
 | ||||||
| #include <kernel/xdm.h> | #include <kernel/xdm.h> | ||||||
| 
 | 
 | ||||||
|  | // Use pthreads directly on macOS to be able to increase default stack size.
 | ||||||
|  | #ifdef __APPLE__ | ||||||
|  | #define USE_PTHREAD 1 | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifdef USE_PTHREAD | ||||||
|  | #include <pthread.h> | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #define CURRENT_THREAD_HANDLE uint32_t(-2) | #define CURRENT_THREAD_HANDLE uint32_t(-2) | ||||||
| 
 | 
 | ||||||
| struct GuestThreadContext | struct GuestThreadContext | ||||||
|  | @ -24,11 +33,17 @@ struct GuestThreadHandle : KernelObject | ||||||
| { | { | ||||||
|     GuestThreadParams params; |     GuestThreadParams params; | ||||||
|     std::atomic<bool> suspended; |     std::atomic<bool> suspended; | ||||||
|  | #ifdef USE_PTHREAD | ||||||
|  |     pthread_t thread; | ||||||
|  | #else | ||||||
|     std::thread thread; |     std::thread thread; | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     GuestThreadHandle(const GuestThreadParams& params); |     GuestThreadHandle(const GuestThreadParams& params); | ||||||
|     ~GuestThreadHandle() override; |     ~GuestThreadHandle() override; | ||||||
| 
 | 
 | ||||||
|  |     uint32_t GetThreadId() const; | ||||||
|  | 
 | ||||||
|     uint32_t Wait(uint32_t timeout) override; |     uint32_t Wait(uint32_t timeout) override; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,21 +0,0 @@ | ||||||
| MIT License |  | ||||||
| 
 |  | ||||||
| Copyright (c) 2024 renderbag and contributors |  | ||||||
| 
 |  | ||||||
| Permission is hereby granted, free of charge, to any person obtaining a copy |  | ||||||
| of this software and associated documentation files (the "Software"), to deal |  | ||||||
| in the Software without restriction, including without limitation the rights |  | ||||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |  | ||||||
| copies of the Software, and to permit persons to whom the Software is |  | ||||||
| furnished to do so, subject to the following conditions: |  | ||||||
| 
 |  | ||||||
| The above copyright notice and this permission notice shall be included in all |  | ||||||
| copies or substantial portions of the Software. |  | ||||||
| 
 |  | ||||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |  | ||||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |  | ||||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |  | ||||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |  | ||||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |  | ||||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |  | ||||||
| SOFTWARE. |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,481 +0,0 @@ | ||||||
| //
 |  | ||||||
| // plume
 |  | ||||||
| //
 |  | ||||||
| // Copyright (c) 2024 renderbag and contributors. All rights reserved.
 |  | ||||||
| // Licensed under the MIT license. See LICENSE file for details.
 |  | ||||||
| //
 |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "plume_render_interface.h" |  | ||||||
| 
 |  | ||||||
| #include <map> |  | ||||||
| #include <mutex> |  | ||||||
| #include <unordered_map> |  | ||||||
| 
 |  | ||||||
| #include <directx/d3d12.h> |  | ||||||
| #include <dxgi1_4.h> |  | ||||||
| 
 |  | ||||||
| #include "D3D12MemAlloc.h" |  | ||||||
| 
 |  | ||||||
| namespace plume { |  | ||||||
|     struct D3D12Buffer; |  | ||||||
|     struct D3D12CommandQueue; |  | ||||||
|     struct D3D12Device; |  | ||||||
|     struct D3D12GraphicsPipeline; |  | ||||||
|     struct D3D12Interface; |  | ||||||
|     struct D3D12Pipeline; |  | ||||||
|     struct D3D12Pool; |  | ||||||
|     struct D3D12PipelineLayout; |  | ||||||
|     struct D3D12Texture; |  | ||||||
| 
 |  | ||||||
|     struct D3D12DescriptorHeapAllocator { |  | ||||||
|         enum : uint32_t { |  | ||||||
|             INVALID_OFFSET = 0xFFFFFFFFU |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         // Reference implementation http://diligentgraphics.com/diligent-engine/architecture/d3d12/variable-size-memory-allocations-manager/
 |  | ||||||
|         struct FreeBlock; |  | ||||||
| 
 |  | ||||||
|         typedef std::map<uint32_t, FreeBlock> OffsetFreeBlockMap; |  | ||||||
|         typedef std::multimap<uint32_t, OffsetFreeBlockMap::iterator> SizeFreeBlockMap; |  | ||||||
| 
 |  | ||||||
|         struct FreeBlock { |  | ||||||
|             uint32_t size; |  | ||||||
|             SizeFreeBlockMap::iterator sizeMapIterator; |  | ||||||
| 
 |  | ||||||
|             FreeBlock(uint32_t size) { |  | ||||||
|                 this->size = size; |  | ||||||
|             } |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         ID3D12DescriptorHeap *heap = nullptr; |  | ||||||
|         uint32_t heapSize = 0; |  | ||||||
|         uint32_t freeSize = 0; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         D3D12_CPU_DESCRIPTOR_HANDLE cpuDescriptorHandle = {}; |  | ||||||
|         D3D12_GPU_DESCRIPTOR_HANDLE gpuDescriptorHandle = {}; |  | ||||||
|         UINT descriptorHandleIncrement = 0; |  | ||||||
|         OffsetFreeBlockMap offsetFreeBlockMap; |  | ||||||
|         SizeFreeBlockMap sizeFreeBlockMap; |  | ||||||
|         std::mutex allocationMutex; |  | ||||||
| 
 |  | ||||||
|         D3D12DescriptorHeapAllocator(D3D12Device *device, uint32_t heapSize, D3D12_DESCRIPTOR_HEAP_TYPE heapType); |  | ||||||
|         ~D3D12DescriptorHeapAllocator(); |  | ||||||
|         void addFreeBlock(uint32_t offset, uint32_t size); |  | ||||||
|         uint32_t allocate(uint32_t size); |  | ||||||
|         void free(uint32_t offset, uint32_t size); |  | ||||||
|         D3D12_CPU_DESCRIPTOR_HANDLE getCPUHandleAt(uint32_t index) const; |  | ||||||
|         D3D12_GPU_DESCRIPTOR_HANDLE getGPUHandleAt(uint32_t index) const; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12DescriptorSet : RenderDescriptorSet { |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
| 
 |  | ||||||
|         struct HeapAllocation { |  | ||||||
|             uint32_t offset = 0; |  | ||||||
|             uint32_t count = 0; |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         HeapAllocation viewAllocation; |  | ||||||
|         HeapAllocation samplerAllocation; |  | ||||||
|         std::vector<RenderDescriptorRangeType> descriptorTypes; |  | ||||||
|         std::vector<uint32_t> descriptorHeapIndices; |  | ||||||
|         uint32_t descriptorTypeMaxIndex = 0; |  | ||||||
| 
 |  | ||||||
|         D3D12DescriptorSet(D3D12Device *device, const RenderDescriptorSetDesc &desc); |  | ||||||
|         ~D3D12DescriptorSet() override; |  | ||||||
|         void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView *bufferStructuredView, const RenderBufferFormattedView *bufferFormattedView) override; |  | ||||||
|         void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, RenderTextureLayout textureLayout, const RenderTextureView *textureView) override; |  | ||||||
|         void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) override; |  | ||||||
|         void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) override; |  | ||||||
|         void setSRV(uint32_t descriptorIndex, ID3D12Resource *resource, const D3D12_SHADER_RESOURCE_VIEW_DESC *viewDesc); |  | ||||||
|         void setUAV(uint32_t descriptorIndex, ID3D12Resource *resource, const D3D12_UNORDERED_ACCESS_VIEW_DESC *viewDesc); |  | ||||||
|         void setCBV(uint32_t descriptorIndex, ID3D12Resource *resource, uint64_t bufferSize); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12SwapChain : RenderSwapChain { |  | ||||||
|         IDXGISwapChain3 *d3d = nullptr; |  | ||||||
|         HANDLE waitableObject = 0; |  | ||||||
|         D3D12CommandQueue *commandQueue = nullptr; |  | ||||||
|         RenderWindow renderWindow = {}; |  | ||||||
|         std::vector<D3D12Texture> textures; |  | ||||||
|         uint32_t textureCount = 0; |  | ||||||
|         RenderFormat format = RenderFormat::UNKNOWN; |  | ||||||
|         DXGI_FORMAT nativeFormat = DXGI_FORMAT_UNKNOWN; |  | ||||||
|         uint32_t width = 0; |  | ||||||
|         uint32_t height = 0; |  | ||||||
|         uint32_t refreshRate = 0; |  | ||||||
|         bool vsyncEnabled = true; |  | ||||||
|         uint32_t maxFrameLatency = 0; |  | ||||||
| 
 |  | ||||||
|         D3D12SwapChain(D3D12CommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency); |  | ||||||
|         ~D3D12SwapChain() override; |  | ||||||
|         bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override; |  | ||||||
|         void wait() override; |  | ||||||
|         bool resize() override; |  | ||||||
|         bool needsResize() const override; |  | ||||||
|         void setVsyncEnabled(bool vsyncEnabled) override; |  | ||||||
|         bool isVsyncEnabled() const override; |  | ||||||
|         uint32_t getWidth() const override; |  | ||||||
|         uint32_t getHeight() const override; |  | ||||||
|         RenderTexture *getTexture(uint32_t textureIndex) override; |  | ||||||
|         uint32_t getTextureCount() const override; |  | ||||||
|         bool acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) override; |  | ||||||
|         RenderWindow getWindow() const override; |  | ||||||
|         bool isEmpty() const override; |  | ||||||
|         uint32_t getRefreshRate() const override; |  | ||||||
|         void getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const; |  | ||||||
|         void setTextures(); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Framebuffer : RenderFramebuffer { |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         uint32_t width = 0; |  | ||||||
|         uint32_t height = 0; |  | ||||||
|         std::vector<const D3D12Texture *> colorTargets; |  | ||||||
|         const D3D12Texture *depthTarget = nullptr; |  | ||||||
|         std::vector<D3D12_CPU_DESCRIPTOR_HANDLE> colorHandles; |  | ||||||
|         D3D12_CPU_DESCRIPTOR_HANDLE depthHandle = {}; |  | ||||||
| 
 |  | ||||||
|         D3D12Framebuffer(D3D12Device *device, const RenderFramebufferDesc &desc); |  | ||||||
|         ~D3D12Framebuffer() override; |  | ||||||
|         uint32_t getWidth() const override; |  | ||||||
|         uint32_t getHeight() const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12QueryPool : RenderQueryPool { |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         ID3D12QueryHeap *d3d = nullptr; |  | ||||||
|         std::vector<uint64_t> results; |  | ||||||
|         std::unique_ptr<RenderBuffer> readbackBuffer; |  | ||||||
| 
 |  | ||||||
|         D3D12QueryPool(D3D12Device *device, uint32_t queryCount); |  | ||||||
|         virtual ~D3D12QueryPool() override; |  | ||||||
|         virtual void queryResults() override; |  | ||||||
|         virtual const uint64_t *getResults() const override; |  | ||||||
|         virtual uint32_t getCount() const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12CommandList : RenderCommandList { |  | ||||||
|         ID3D12GraphicsCommandList9 *d3d = nullptr; |  | ||||||
|         ID3D12CommandAllocator *commandAllocator = nullptr; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         RenderCommandListType type = RenderCommandListType::UNKNOWN; |  | ||||||
|         const D3D12Framebuffer *targetFramebuffer = nullptr; |  | ||||||
|         bool targetFramebufferSamplePositionsSet = false; |  | ||||||
|         bool open = false; |  | ||||||
|         const D3D12PipelineLayout *activeComputePipelineLayout = nullptr; |  | ||||||
|         const D3D12PipelineLayout *activeGraphicsPipelineLayout = nullptr; |  | ||||||
|         const D3D12GraphicsPipeline *activeGraphicsPipeline = nullptr; |  | ||||||
|         bool descriptorHeapsSet = false; |  | ||||||
|         D3D12_PRIMITIVE_TOPOLOGY activeTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; |  | ||||||
|         bool activeSamplePositions = false; |  | ||||||
| 
 |  | ||||||
|         D3D12CommandList(D3D12Device *device, RenderCommandListType type); |  | ||||||
|         ~D3D12CommandList() override; |  | ||||||
|         void begin() override; |  | ||||||
|         void end() override; |  | ||||||
|         void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) override; |  | ||||||
|         void dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) override; |  | ||||||
|         void traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) override; |  | ||||||
|         void drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) override; |  | ||||||
|         void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) override; |  | ||||||
|         void setPipeline(const RenderPipeline *pipeline) override; |  | ||||||
|         void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) override; |  | ||||||
|         void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; |  | ||||||
|         void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; |  | ||||||
|         void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; |  | ||||||
|         void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; |  | ||||||
|         void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; |  | ||||||
|         void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) override; |  | ||||||
|         void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; |  | ||||||
|         void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; |  | ||||||
|         void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; |  | ||||||
|         void setIndexBuffer(const RenderIndexBufferView *view) override; |  | ||||||
|         void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) override; |  | ||||||
|         void setViewports(const RenderViewport *viewports, uint32_t count) override; |  | ||||||
|         void setScissors(const RenderRect *scissorRects, uint32_t count) override; |  | ||||||
|         void setFramebuffer(const RenderFramebuffer *framebuffer) override; |  | ||||||
|         void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) override; |  | ||||||
|         void clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) override; |  | ||||||
|         void clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) override; |  | ||||||
|         void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) override; |  | ||||||
|         void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX, uint32_t dstY, uint32_t dstZ, const RenderBox *srcBox) override; |  | ||||||
|         void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override; |  | ||||||
|         void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override; |  | ||||||
|         void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override; |  | ||||||
|         void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) override; |  | ||||||
|         void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override; |  | ||||||
|         void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override; |  | ||||||
|         void discardTexture(const RenderTexture* texture) override; |  | ||||||
|         void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) override; |  | ||||||
|         void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) override; |  | ||||||
|         void checkDescriptorHeaps(); |  | ||||||
|         void notifyDescriptorHeapWasChangedExternally(); |  | ||||||
|         void checkTopology(); |  | ||||||
|         void checkFramebufferSamplePositions(); |  | ||||||
|         void setSamplePositions(const RenderTexture *texture); |  | ||||||
|         void resetSamplePositions(); |  | ||||||
|         void setDescriptorSet(const D3D12PipelineLayout *activePipelineLayout, RenderDescriptorSet *descriptorSet, uint32_t setIndex, bool setCompute); |  | ||||||
|         void setRootDescriptorTable(D3D12DescriptorHeapAllocator *heapAllocator, D3D12DescriptorSet::HeapAllocation &heapAllocation, uint32_t rootIndex, bool setCompute); |  | ||||||
|         void setRootDescriptor(const D3D12PipelineLayout *activePipelineLayout, RenderBufferReference bufferReference, uint32_t setIndex, bool setCompute); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12CommandFence : RenderCommandFence { |  | ||||||
|         ID3D12Fence *d3d = nullptr; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         HANDLE fenceEvent = 0; |  | ||||||
|         UINT64 fenceValue = 0; |  | ||||||
| 
 |  | ||||||
|         D3D12CommandFence(D3D12Device *device); |  | ||||||
|         ~D3D12CommandFence() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12CommandSemaphore : RenderCommandSemaphore { |  | ||||||
|         ID3D12Fence *d3d = nullptr; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         UINT64 semaphoreValue = 0; |  | ||||||
| 
 |  | ||||||
|         D3D12CommandSemaphore(D3D12Device *device); |  | ||||||
|         ~D3D12CommandSemaphore() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12CommandQueue : RenderCommandQueue { |  | ||||||
|         ID3D12CommandQueue *d3d = nullptr; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         RenderCommandListType type = RenderCommandListType::UNKNOWN; |  | ||||||
| 
 |  | ||||||
|         D3D12CommandQueue(D3D12Device *device, RenderCommandListType type); |  | ||||||
|         ~D3D12CommandQueue() override; |  | ||||||
|         std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t newFrameLatency) override; |  | ||||||
|         void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override; |  | ||||||
|         void waitForCommandFence(RenderCommandFence *fence) override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Buffer : RenderBuffer { |  | ||||||
|         ID3D12Resource *d3d = nullptr; |  | ||||||
|         D3D12_RESOURCE_STATES resourceStates = D3D12_RESOURCE_STATE_COMMON; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         D3D12MA::Allocation *allocation = nullptr; |  | ||||||
|         D3D12Pool *pool = nullptr; |  | ||||||
|         RenderBufferDesc desc; |  | ||||||
| 
 |  | ||||||
|         D3D12Buffer() = default; |  | ||||||
|         D3D12Buffer(D3D12Device *device, D3D12Pool *pool, const RenderBufferDesc &desc); |  | ||||||
|         ~D3D12Buffer() override; |  | ||||||
|         void *map(uint32_t subresource, const RenderRange *readRange) override; |  | ||||||
|         void unmap(uint32_t subresource, const RenderRange *writtenRange) override; |  | ||||||
|         std::unique_ptr<RenderBufferFormattedView> createBufferFormattedView(RenderFormat format) override; |  | ||||||
|         void setName(const std::string &name) override; |  | ||||||
|         uint64_t getDeviceAddress() const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12BufferFormattedView : RenderBufferFormattedView { |  | ||||||
|         RenderFormat format = RenderFormat::UNKNOWN; |  | ||||||
|         D3D12Buffer *buffer = nullptr; |  | ||||||
| 
 |  | ||||||
|         D3D12BufferFormattedView(D3D12Buffer *buffer, RenderFormat format); |  | ||||||
|         ~D3D12BufferFormattedView() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Texture : RenderTexture { |  | ||||||
|         ID3D12Resource *d3d = nullptr; |  | ||||||
|         D3D12_RESOURCE_STATES resourceStates = D3D12_RESOURCE_STATE_COMMON; |  | ||||||
|         RenderTextureLayout layout = RenderTextureLayout::UNKNOWN; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         D3D12MA::Allocation *allocation = nullptr; |  | ||||||
|         D3D12Pool *pool = nullptr; |  | ||||||
|         RenderTextureDesc desc; |  | ||||||
|         uint32_t targetAllocatorOffset = 0; |  | ||||||
|         uint32_t targetEntryCount = 0; |  | ||||||
|         bool targetHeapDepth = false; |  | ||||||
| 
 |  | ||||||
|         D3D12Texture() = default; |  | ||||||
|         D3D12Texture(D3D12Device *device, D3D12Pool *pool, const RenderTextureDesc &desc); |  | ||||||
|         ~D3D12Texture() override; |  | ||||||
|         std::unique_ptr<RenderTextureView> createTextureView(const RenderTextureViewDesc &desc) override; |  | ||||||
|         void setName(const std::string &name) override; |  | ||||||
|         void createRenderTargetHeap(); |  | ||||||
|         void createDepthStencilHeap(); |  | ||||||
|         void releaseTargetHeap(); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12TextureView : RenderTextureView { |  | ||||||
|         DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN; |  | ||||||
|         D3D12Texture *texture = nullptr; |  | ||||||
|         RenderTextureViewDimension dimension = RenderTextureViewDimension::UNKNOWN; |  | ||||||
|         uint32_t mipLevels = 0; |  | ||||||
|         uint32_t mipSlice = 0; |  | ||||||
|         uint32_t shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING; |  | ||||||
| 
 |  | ||||||
|         D3D12TextureView(D3D12Texture *texture, const RenderTextureViewDesc &desc); |  | ||||||
|         ~D3D12TextureView() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12AccelerationStructure :RenderAccelerationStructure { |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         const D3D12Buffer *buffer = nullptr; |  | ||||||
|         uint64_t offset = 0; |  | ||||||
|         uint64_t size = 0; |  | ||||||
|         RenderAccelerationStructureType type = RenderAccelerationStructureType::UNKNOWN; |  | ||||||
| 
 |  | ||||||
|         D3D12AccelerationStructure(D3D12Device *device, const RenderAccelerationStructureDesc &desc); |  | ||||||
|         ~D3D12AccelerationStructure() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Pool : RenderPool { |  | ||||||
|         D3D12MA::Pool *d3d = nullptr; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         RenderPoolDesc desc; |  | ||||||
| 
 |  | ||||||
|         D3D12Pool(D3D12Device *device, const RenderPoolDesc &desc, bool gpuUploadHeapFallback); |  | ||||||
|         ~D3D12Pool() override; |  | ||||||
|         std::unique_ptr<RenderBuffer> createBuffer(const RenderBufferDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Shader : RenderShader { |  | ||||||
|         const void* data = nullptr; |  | ||||||
|         uint64_t size = 0; |  | ||||||
|         std::string entryPointName; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         RenderShaderFormat format = RenderShaderFormat::UNKNOWN; |  | ||||||
| 
 |  | ||||||
|         D3D12Shader(D3D12Device *device, const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format); |  | ||||||
|         ~D3D12Shader() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Sampler : RenderSampler { |  | ||||||
|         D3D12_SAMPLER_DESC samplerDesc = {}; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         RenderBorderColor borderColor = RenderBorderColor::UNKNOWN; |  | ||||||
|         RenderShaderVisibility shaderVisibility = RenderShaderVisibility::UNKNOWN; |  | ||||||
| 
 |  | ||||||
|         D3D12Sampler(D3D12Device *device, const RenderSamplerDesc &desc); |  | ||||||
|         ~D3D12Sampler() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Pipeline : RenderPipeline { |  | ||||||
|         enum class Type { |  | ||||||
|             Unknown, |  | ||||||
|             Compute, |  | ||||||
|             Graphics, |  | ||||||
|             Raytracing |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         Type type = Type::Unknown; |  | ||||||
| 
 |  | ||||||
|         D3D12Pipeline(D3D12Device *device, Type type); |  | ||||||
|         virtual ~D3D12Pipeline() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12ComputePipeline : D3D12Pipeline { |  | ||||||
|         ID3D12PipelineState *d3d = nullptr; |  | ||||||
| 
 |  | ||||||
|         D3D12ComputePipeline(D3D12Device *device, const RenderComputePipelineDesc &desc); |  | ||||||
|         ~D3D12ComputePipeline() override; |  | ||||||
|         virtual void setName(const std::string& name) const override; |  | ||||||
|         virtual RenderPipelineProgram getProgram(const std::string &name) const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12GraphicsPipeline : D3D12Pipeline { |  | ||||||
|         ID3D12PipelineState *d3d = nullptr; |  | ||||||
|         std::vector<RenderInputSlot> inputSlots; |  | ||||||
|         D3D12_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED; |  | ||||||
| 
 |  | ||||||
|         D3D12GraphicsPipeline(D3D12Device *device, const RenderGraphicsPipelineDesc &desc); |  | ||||||
|         ~D3D12GraphicsPipeline() override; |  | ||||||
|         virtual void setName(const std::string& name) const override; |  | ||||||
|         virtual RenderPipelineProgram getProgram(const std::string &name) const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12RaytracingPipeline : D3D12Pipeline { |  | ||||||
|         ID3D12StateObject *stateObject = nullptr; |  | ||||||
|         ID3D12StateObjectProperties *stateObjectProperties = nullptr; |  | ||||||
|         std::vector<void *> programShaderIdentifiers; |  | ||||||
|         std::unordered_map<std::string, RenderPipelineProgram> nameProgramMap; |  | ||||||
|         const D3D12PipelineLayout *pipelineLayout = nullptr; |  | ||||||
| 
 |  | ||||||
|         D3D12RaytracingPipeline(D3D12Device *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline); |  | ||||||
|         ~D3D12RaytracingPipeline() override; |  | ||||||
|         virtual void setName(const std::string& name) const override; |  | ||||||
|         virtual RenderPipelineProgram getProgram(const std::string &name) const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12PipelineLayout : RenderPipelineLayout { |  | ||||||
|         ID3D12RootSignature *rootSignature = nullptr; |  | ||||||
|         D3D12Device *device = nullptr; |  | ||||||
|         std::vector<RenderPushConstantRange> pushConstantRanges; |  | ||||||
|         std::vector<uint32_t> setViewRootIndices; |  | ||||||
|         std::vector<uint32_t> setSamplerRootIndices; |  | ||||||
|         std::vector<std::pair<uint32_t, RenderRootDescriptorType>> rootDescriptorRootIndicesAndTypes; |  | ||||||
|         uint32_t setCount = 0; |  | ||||||
|         uint32_t rootCount = 0; |  | ||||||
| 
 |  | ||||||
|         D3D12PipelineLayout(D3D12Device *device, const RenderPipelineLayoutDesc &desc); |  | ||||||
|         ~D3D12PipelineLayout() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Device : RenderDevice { |  | ||||||
|         ID3D12Device8 *d3d = nullptr; |  | ||||||
|         D3D12Interface *renderInterface = nullptr; |  | ||||||
|         IDXGIAdapter1 *adapter = nullptr; |  | ||||||
|         D3D12MA::Allocator *allocator = nullptr; |  | ||||||
|         D3D_SHADER_MODEL shaderModel = D3D_SHADER_MODEL(0); |  | ||||||
|         std::unique_ptr<RenderPipelineLayout> rtDummyGlobalPipelineLayout; |  | ||||||
|         std::unique_ptr<RenderPipelineLayout> rtDummyLocalPipelineLayout; |  | ||||||
|         std::unique_ptr<D3D12DescriptorHeapAllocator> viewHeapAllocator; |  | ||||||
|         std::unique_ptr<D3D12DescriptorHeapAllocator> samplerHeapAllocator; |  | ||||||
|         std::unique_ptr<D3D12DescriptorHeapAllocator> colorTargetHeapAllocator; |  | ||||||
|         std::unique_ptr<D3D12DescriptorHeapAllocator> depthTargetHeapAllocator; |  | ||||||
|         std::unique_ptr<D3D12Pool> customUploadPool; |  | ||||||
|         RenderDeviceCapabilities capabilities; |  | ||||||
|         RenderDeviceDescription description; |  | ||||||
|         uint64_t timestampFrequency = 1; |  | ||||||
|         bool gpuUploadHeapFallback = false; |  | ||||||
| 
 |  | ||||||
|         D3D12Device(D3D12Interface *renderInterface, const std::string &preferredDeviceName); |  | ||||||
|         ~D3D12Device() override; |  | ||||||
|         std::unique_ptr<RenderCommandList> createCommandList(RenderCommandListType type) override; |  | ||||||
|         std::unique_ptr<RenderDescriptorSet> createDescriptorSet(const RenderDescriptorSetDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderShader> createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) override; |  | ||||||
|         std::unique_ptr<RenderSampler> createSampler(const RenderSamplerDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPipeline> createComputePipeline(const RenderComputePipelineDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPipeline> createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPipeline> createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) override; |  | ||||||
|         std::unique_ptr<RenderCommandQueue> createCommandQueue(RenderCommandListType type) override; |  | ||||||
|         std::unique_ptr<RenderBuffer> createBuffer(const RenderBufferDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderAccelerationStructure> createAccelerationStructure(const RenderAccelerationStructureDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPool> createPool(const RenderPoolDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPipelineLayout> createPipelineLayout(const RenderPipelineLayoutDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderCommandFence> createCommandFence() override; |  | ||||||
|         std::unique_ptr<RenderCommandSemaphore> createCommandSemaphore() override; |  | ||||||
|         std::unique_ptr<RenderFramebuffer> createFramebuffer(const RenderFramebufferDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderQueryPool> createQueryPool(uint32_t queryCount) override; |  | ||||||
|         void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) override; |  | ||||||
|         void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) override; |  | ||||||
|         void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) override; |  | ||||||
|         const RenderDeviceCapabilities &getCapabilities() const override; |  | ||||||
|         const RenderDeviceDescription &getDescription() const override; |  | ||||||
|         RenderSampleCounts getSampleCountsSupported(RenderFormat format) const override; |  | ||||||
|         void waitIdle() const override; |  | ||||||
|         void release(); |  | ||||||
|         bool isValid() const; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct D3D12Interface : RenderInterface { |  | ||||||
|         IDXGIFactory4 *dxgiFactory = nullptr; |  | ||||||
|         RenderInterfaceCapabilities capabilities; |  | ||||||
|         std::vector<std::string> deviceNames; |  | ||||||
| 
 |  | ||||||
|         D3D12Interface(); |  | ||||||
|         ~D3D12Interface() override; |  | ||||||
|         std::unique_ptr<RenderDevice> createDevice(const std::string &preferredDeviceName) override; |  | ||||||
|         const RenderInterfaceCapabilities &getCapabilities() const override; |  | ||||||
|         const std::vector<std::string> &getDeviceNames() const override; |  | ||||||
|         bool isValid() const; |  | ||||||
|     }; |  | ||||||
| }; |  | ||||||
|  | @ -1,262 +0,0 @@ | ||||||
| //
 |  | ||||||
| // plume
 |  | ||||||
| //
 |  | ||||||
| // Copyright (c) 2024 renderbag and contributors. All rights reserved.
 |  | ||||||
| // Licensed under the MIT license. See LICENSE file for details.
 |  | ||||||
| //
 |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <climits> |  | ||||||
| 
 |  | ||||||
| #include "plume_render_interface_types.h" |  | ||||||
| 
 |  | ||||||
| namespace plume { |  | ||||||
|     // Interfaces.
 |  | ||||||
| 
 |  | ||||||
|     struct RenderBufferFormattedView { |  | ||||||
|         virtual ~RenderBufferFormattedView() { } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderBuffer { |  | ||||||
|         virtual ~RenderBuffer() { } |  | ||||||
|         virtual void *map(uint32_t subresource = 0, const RenderRange *readRange = nullptr) = 0; |  | ||||||
|         virtual void unmap(uint32_t subresource = 0, const RenderRange *writtenRange = nullptr) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderBufferFormattedView> createBufferFormattedView(RenderFormat format) = 0; |  | ||||||
|         virtual void setName(const std::string &name) = 0; |  | ||||||
|         virtual uint64_t getDeviceAddress() const = 0; |  | ||||||
| 
 |  | ||||||
|         // Concrete implementation shortcuts.
 |  | ||||||
|         inline RenderBufferReference at(uint64_t offset) const { |  | ||||||
|             return RenderBufferReference(this, offset); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderTextureView { |  | ||||||
|         virtual ~RenderTextureView() { } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderTexture { |  | ||||||
|         virtual ~RenderTexture() { } |  | ||||||
|         virtual std::unique_ptr<RenderTextureView> createTextureView(const RenderTextureViewDesc &desc) = 0; |  | ||||||
|         virtual void setName(const std::string &name) = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderAccelerationStructure { |  | ||||||
|         virtual ~RenderAccelerationStructure() { } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderShader { |  | ||||||
|         virtual ~RenderShader() { } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderSampler { |  | ||||||
|         virtual ~RenderSampler() { } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderPipeline { |  | ||||||
|         virtual ~RenderPipeline() { } |  | ||||||
|         virtual void setName(const std::string& name) const = 0; |  | ||||||
|         virtual RenderPipelineProgram getProgram(const std::string &name) const = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderPipelineLayout { |  | ||||||
|         virtual ~RenderPipelineLayout() { } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderCommandFence { |  | ||||||
|         virtual ~RenderCommandFence() { } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderCommandSemaphore { |  | ||||||
|         virtual ~RenderCommandSemaphore() { } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderDescriptorSet { |  | ||||||
|         // Descriptor indices correspond to the index assuming the descriptor set is one contiguous array. They DO NOT correspond to the bindings, which can be sparse.
 |  | ||||||
|         // User code should derive these indices on its own by looking at the order the bindings were assigned during set creation along with the descriptor count and
 |  | ||||||
|         // assume it was all allocated in one contiguous array. This allows efficient mapping between Vulkan and D3D12's descriptor models.
 |  | ||||||
| 
 |  | ||||||
|         virtual ~RenderDescriptorSet() { } |  | ||||||
|         virtual void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize = 0, const RenderBufferStructuredView *bufferStructuredView = nullptr, const RenderBufferFormattedView *bufferFormattedView = nullptr) = 0; |  | ||||||
|         virtual void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, RenderTextureLayout textureLayout, const RenderTextureView *textureView = nullptr) = 0; |  | ||||||
|         virtual void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) = 0; |  | ||||||
|         virtual void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderSwapChain { |  | ||||||
|         virtual ~RenderSwapChain() { } |  | ||||||
|         virtual bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) = 0; |  | ||||||
|         virtual void wait() = 0; |  | ||||||
|         virtual bool resize() = 0; |  | ||||||
|         virtual bool needsResize() const = 0; |  | ||||||
|         virtual void setVsyncEnabled(bool vsyncEnabled) = 0; |  | ||||||
|         virtual bool isVsyncEnabled() const = 0; |  | ||||||
|         virtual uint32_t getWidth() const = 0; |  | ||||||
|         virtual uint32_t getHeight() const = 0; |  | ||||||
|         virtual RenderTexture *getTexture(uint32_t textureIndex) = 0; |  | ||||||
|         virtual uint32_t getTextureCount() const = 0; |  | ||||||
|         virtual bool acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) = 0; |  | ||||||
|         virtual RenderWindow getWindow() const = 0; |  | ||||||
|         virtual bool isEmpty() const = 0; |  | ||||||
| 
 |  | ||||||
|         // Only valid if displayTiming is enabled in capabilities.
 |  | ||||||
|         virtual uint32_t getRefreshRate() const = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderFramebuffer { |  | ||||||
|         virtual ~RenderFramebuffer() { } |  | ||||||
|         virtual uint32_t getWidth() const = 0; |  | ||||||
|         virtual uint32_t getHeight() const = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderCommandList { |  | ||||||
|         virtual ~RenderCommandList() { } |  | ||||||
|         virtual void begin() = 0; |  | ||||||
|         virtual void end() = 0; |  | ||||||
|         virtual void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) = 0; |  | ||||||
|         virtual void dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) = 0; |  | ||||||
|         virtual void traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) = 0; |  | ||||||
|         virtual void drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) = 0; |  | ||||||
|         virtual void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) = 0; |  | ||||||
|         virtual void setPipeline(const RenderPipeline *pipeline) = 0; |  | ||||||
|         virtual void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; |  | ||||||
|         virtual void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0; |  | ||||||
|         virtual void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; |  | ||||||
|         virtual void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; |  | ||||||
|         virtual void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0; |  | ||||||
|         virtual void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; |  | ||||||
|         virtual void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) = 0; |  | ||||||
|         virtual void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) = 0; |  | ||||||
|         virtual void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) = 0; |  | ||||||
|         virtual void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) = 0; |  | ||||||
|         virtual void setIndexBuffer(const RenderIndexBufferView *view) = 0; |  | ||||||
|         virtual void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) = 0; |  | ||||||
|         virtual void setViewports(const RenderViewport *viewports, uint32_t count) = 0; |  | ||||||
|         virtual void setScissors(const RenderRect *scissorRects, uint32_t count) = 0; |  | ||||||
|         virtual void setFramebuffer(const RenderFramebuffer *framebuffer) = 0; |  | ||||||
|         virtual void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) = 0; |  | ||||||
|         virtual void clearColor(uint32_t attachmentIndex = 0, RenderColor colorValue = RenderColor(), const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0; |  | ||||||
|         virtual void clearDepth(bool clearDepth = true, float depthValue = 1.0f, const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0; |  | ||||||
|         virtual void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) = 0; |  | ||||||
|         virtual void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX = 0, uint32_t dstY = 0, uint32_t dstZ = 0, const RenderBox *srcBox = nullptr) = 0; |  | ||||||
|         virtual void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) = 0; |  | ||||||
|         virtual void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) = 0; |  | ||||||
|         virtual void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) = 0; |  | ||||||
|         virtual void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect = nullptr, RenderResolveMode resolveMode = RenderResolveMode::AVERAGE) = 0; |  | ||||||
|         virtual void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) = 0; |  | ||||||
|         virtual void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) = 0; |  | ||||||
|         virtual void discardTexture(const RenderTexture* texture) = 0; // D3D12 only.
 |  | ||||||
|         virtual void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) = 0; |  | ||||||
|         virtual void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) = 0; |  | ||||||
| 
 |  | ||||||
|         // Concrete implementation shortcuts.
 |  | ||||||
|         inline void barriers(RenderBarrierStages stages, const RenderBufferBarrier &barrier) { |  | ||||||
|             barriers(stages, &barrier, 1, nullptr, 0); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void barriers(RenderBarrierStages stages, const RenderTextureBarrier &barrier) { |  | ||||||
|             barriers(stages, nullptr, 0, &barrier, 1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void barriers(RenderBarrierStages stages, const RenderBufferBarrier &bufferBarrier, const RenderTextureBarrier &textureBarrier) { |  | ||||||
|             barriers(stages, &bufferBarrier, 1, &textureBarrier, 1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount) { |  | ||||||
|             barriers(stages, bufferBarriers, bufferBarriersCount, nullptr, 0); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void barriers(RenderBarrierStages stages, const std::vector<RenderBufferBarrier> &bufferBarriers) { |  | ||||||
|             barriers(stages, bufferBarriers.data(), uint32_t(bufferBarriers.size()), nullptr, 0); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void barriers(RenderBarrierStages stages, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) { |  | ||||||
|             barriers(stages, nullptr, 0, textureBarriers, textureBarriersCount); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void barriers(RenderBarrierStages stages, const std::vector<RenderTextureBarrier> &textureBarriers) { |  | ||||||
|             barriers(stages, nullptr, 0, textureBarriers.data(), uint32_t(textureBarriers.size())); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void barriers(RenderBarrierStages stages, const std::vector<RenderBufferBarrier> &bufferBarriers, const std::vector<RenderTextureBarrier> &textureBarriers) { |  | ||||||
|             barriers(stages, bufferBarriers.data(), uint32_t(bufferBarriers.size()), textureBarriers.data(), uint32_t(textureBarriers.size())); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void setViewports(const RenderViewport &viewport) { |  | ||||||
|             setViewports(&viewport, 1); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         inline void setScissors(const RenderRect &scissorRect) { |  | ||||||
|             setScissors(&scissorRect, 1); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderCommandQueue { |  | ||||||
|         virtual ~RenderCommandQueue() { } |  | ||||||
|         virtual std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency) = 0; |  | ||||||
|         virtual void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores = nullptr, uint32_t waitSemaphoreCount = 0, RenderCommandSemaphore **signalSemaphores = nullptr, uint32_t signalSemaphoreCount = 0, RenderCommandFence *signalFence = nullptr) = 0; |  | ||||||
|         virtual void waitForCommandFence(RenderCommandFence *fence) = 0; |  | ||||||
| 
 |  | ||||||
|         // Concrete implementation shortcuts.
 |  | ||||||
|         inline void executeCommandLists(const RenderCommandList *commandList, RenderCommandFence *signalFence = nullptr) { |  | ||||||
|             executeCommandLists(commandList != nullptr ? &commandList : nullptr, commandList != nullptr ? 1 : 0, nullptr, 0, nullptr, 0, signalFence); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderPool { |  | ||||||
|         virtual ~RenderPool() { } |  | ||||||
|         virtual std::unique_ptr<RenderBuffer> createBuffer(const RenderBufferDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderQueryPool { |  | ||||||
|         virtual ~RenderQueryPool() { } |  | ||||||
|         virtual void queryResults() = 0; |  | ||||||
|         virtual const uint64_t *getResults() const = 0; |  | ||||||
|         virtual uint32_t getCount() const = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderDevice { |  | ||||||
|         virtual ~RenderDevice() { } |  | ||||||
|         virtual std::unique_ptr<RenderCommandList> createCommandList(RenderCommandListType type) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderDescriptorSet> createDescriptorSet(const RenderDescriptorSetDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderShader> createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderSampler> createSampler(const RenderSamplerDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderPipeline> createComputePipeline(const RenderComputePipelineDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderPipeline> createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderPipeline> createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline = nullptr) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderCommandQueue> createCommandQueue(RenderCommandListType type) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderBuffer> createBuffer(const RenderBufferDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderAccelerationStructure> createAccelerationStructure(const RenderAccelerationStructureDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderPool> createPool(const RenderPoolDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderPipelineLayout> createPipelineLayout(const RenderPipelineLayoutDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderCommandFence> createCommandFence() = 0; |  | ||||||
|         virtual std::unique_ptr<RenderCommandSemaphore> createCommandSemaphore() = 0; |  | ||||||
|         virtual std::unique_ptr<RenderFramebuffer> createFramebuffer(const RenderFramebufferDesc &desc) = 0; |  | ||||||
|         virtual std::unique_ptr<RenderQueryPool> createQueryPool(uint32_t queryCount) = 0; |  | ||||||
|         virtual void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild = true, bool preferFastTrace = false) = 0; |  | ||||||
|         virtual void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild = true, bool preferFastTrace = false) = 0; |  | ||||||
|         virtual void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) = 0; |  | ||||||
|         virtual const RenderDeviceCapabilities &getCapabilities() const = 0; |  | ||||||
|         virtual const RenderDeviceDescription &getDescription() const = 0; |  | ||||||
|         virtual RenderSampleCounts getSampleCountsSupported(RenderFormat format) const = 0; |  | ||||||
|         virtual void waitIdle() const = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderInterface { |  | ||||||
|         virtual ~RenderInterface() { } |  | ||||||
|         virtual std::unique_ptr<RenderDevice> createDevice(const std::string &preferredDeviceName = "") = 0; |  | ||||||
|         virtual const std::vector<std::string> &getDeviceNames() const = 0; |  | ||||||
|         virtual const RenderInterfaceCapabilities &getCapabilities() const = 0; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     extern void RenderInterfaceTest(RenderInterface *renderInterface); |  | ||||||
|     extern void TestInitialize(RenderInterface* renderInterface, RenderWindow window); |  | ||||||
|     extern void TestDraw(); |  | ||||||
|     extern void TestResize(); |  | ||||||
|     extern void TestShutdown(); |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| #include "plume_render_interface_builders.h" |  | ||||||
|  | @ -1,281 +0,0 @@ | ||||||
| //
 |  | ||||||
| // plume
 |  | ||||||
| //
 |  | ||||||
| // Copyright (c) 2024 renderbag and contributors. All rights reserved.
 |  | ||||||
| // Licensed under the MIT license. See LICENSE file for details.
 |  | ||||||
| //
 |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <unordered_set> |  | ||||||
| 
 |  | ||||||
| namespace plume { |  | ||||||
|     struct RenderDescriptorSetBuilder { |  | ||||||
|         std::list<std::vector<const RenderSampler *>> samplerPointerVectorList; |  | ||||||
|         std::vector<RenderDescriptorRange> descriptorRanges; |  | ||||||
|         RenderDescriptorSetDesc descriptorSetDesc; |  | ||||||
|         bool open = false; |  | ||||||
|         uint32_t setIndex = 0; |  | ||||||
| 
 |  | ||||||
|         RenderDescriptorSetBuilder() = default; |  | ||||||
| 
 |  | ||||||
|         void begin() { |  | ||||||
|             assert(!open && "Builder must be closed."); |  | ||||||
| 
 |  | ||||||
|             descriptorSetDesc = RenderDescriptorSetDesc(); |  | ||||||
| 
 |  | ||||||
|             samplerPointerVectorList.clear(); |  | ||||||
|             descriptorRanges.clear(); |  | ||||||
| 
 |  | ||||||
|             open = true; |  | ||||||
|             setIndex = 0; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addConstantBuffer(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::CONSTANT_BUFFER, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addFormattedBuffer(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::FORMATTED_BUFFER, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addReadWriteFormattedBuffer(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::READ_WRITE_FORMATTED_BUFFER, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addTexture(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::TEXTURE, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addReadWriteTexture(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::READ_WRITE_TEXTURE, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addSampler(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::SAMPLER, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addImmutableSampler(uint32_t binding, const RenderSampler *immutableSampler) { |  | ||||||
|             assert(immutableSampler != nullptr); |  | ||||||
| 
 |  | ||||||
|             return addImmutableSampler(binding, &immutableSampler); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addImmutableSampler(uint32_t binding, const RenderSampler **immutableSampler, uint32_t count = 1) { |  | ||||||
|             assert(immutableSampler != nullptr); |  | ||||||
| 
 |  | ||||||
|             samplerPointerVectorList.emplace_back(std::vector<const RenderSampler *>(immutableSampler, immutableSampler + count)); |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::SAMPLER, binding, count, samplerPointerVectorList.back().data())); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addStructuredBuffer(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::STRUCTURED_BUFFER, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addReadWriteStructuredBuffer(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::READ_WRITE_STRUCTURED_BUFFER, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addByteAddressBuffer(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::BYTE_ADDRESS_BUFFER, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addReadWriteByteAddressBuffer(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::READ_WRITE_BYTE_ADDRESS_BUFFER, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addAccelerationStructure(uint32_t binding, uint32_t count = 1) { |  | ||||||
|             return addRange(RenderDescriptorRange(RenderDescriptorRangeType::ACCELERATION_STRUCTURE, binding, count, nullptr)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         uint32_t addRange(const RenderDescriptorRange &range) { |  | ||||||
|             assert(open && "Builder must be open."); |  | ||||||
| 
 |  | ||||||
|             uint32_t returnValue = setIndex; |  | ||||||
|             descriptorRanges.emplace_back(range); |  | ||||||
|             descriptorSetDesc.descriptorRangesCount++; |  | ||||||
|             setIndex += range.count; |  | ||||||
|             return returnValue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void end(bool lastRangeIsBoundless = false, uint32_t boundlessRangeSize = 0) { |  | ||||||
|             assert(open && "Builder must be open."); |  | ||||||
| 
 |  | ||||||
|             descriptorSetDesc.lastRangeIsBoundless = lastRangeIsBoundless; |  | ||||||
|             descriptorSetDesc.boundlessRangeSize = boundlessRangeSize; |  | ||||||
|             descriptorSetDesc.descriptorRanges = descriptorRanges.data(); |  | ||||||
|             open = false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         std::unique_ptr<RenderDescriptorSet> create(RenderDevice *device) const { |  | ||||||
|             assert(!open && "Builder must be closed."); |  | ||||||
| 
 |  | ||||||
|             return device->createDescriptorSet(descriptorSetDesc); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderDescriptorSetBase { |  | ||||||
|         RenderDescriptorSetBuilder builder; |  | ||||||
|         std::unique_ptr<RenderDescriptorSet> descriptorSet; |  | ||||||
| 
 |  | ||||||
|         void create(RenderDevice *device) { |  | ||||||
|             descriptorSet = builder.create(device); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         RenderDescriptorSet *get() const { |  | ||||||
|             return descriptorSet.get(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize = 0, const RenderBufferStructuredView *bufferStructuredView = nullptr, const RenderBufferFormattedView *bufferFormattedView = nullptr) { |  | ||||||
|             descriptorSet->setBuffer(descriptorIndex, buffer, bufferSize, bufferStructuredView, bufferFormattedView); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView &bufferStructuredView) { |  | ||||||
|             descriptorSet->setBuffer(descriptorIndex, buffer, bufferSize, &bufferStructuredView); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferFormattedView *bufferFormattedView) { |  | ||||||
|             descriptorSet->setBuffer(descriptorIndex, buffer, bufferSize, nullptr, bufferFormattedView); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, const RenderBufferStructuredView &bufferStructuredView) { |  | ||||||
|             descriptorSet->setBuffer(descriptorIndex, buffer, 0, &bufferStructuredView); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, const RenderBufferFormattedView *bufferFormattedView) { |  | ||||||
|             descriptorSet->setBuffer(descriptorIndex, buffer, 0, nullptr, bufferFormattedView); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, const RenderTextureLayout textureLayout, const RenderTextureView *textureView = nullptr) { |  | ||||||
|             descriptorSet->setTexture(descriptorIndex, texture, textureLayout, textureView); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) { |  | ||||||
|             descriptorSet->setSampler(descriptorIndex, sampler); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) { |  | ||||||
|             descriptorSet->setAccelerationStructure(descriptorIndex, accelerationStructure); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct RenderDescriptorSetInclusionFilter { |  | ||||||
|         const uint32_t *bindings = nullptr; |  | ||||||
|         uint32_t bindingsCount = 0; |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     struct RenderPipelineLayoutBuilder { |  | ||||||
|         std::vector<RenderPushConstantRange> pushConstantRanges; |  | ||||||
|         std::list<std::vector<const RenderSampler *>> samplerPointerVectorList; |  | ||||||
|         std::vector<RenderDescriptorRange> descriptorRanges; |  | ||||||
|         std::vector<RenderDescriptorSetDesc> descriptorSetDescs; |  | ||||||
|         std::vector<uint32_t> descriptorRangeIndexPerSet; |  | ||||||
|         std::vector<RenderRootDescriptorDesc> rootDescriptorDescs; |  | ||||||
|         RenderPipelineLayoutDesc layoutDesc; |  | ||||||
|         bool open = false; |  | ||||||
| 
 |  | ||||||
|         // Start filling the description.
 |  | ||||||
|         void begin(bool isLocal = false, bool allowInputLayout = false) { |  | ||||||
|             assert(!open && "Builder must be closed."); |  | ||||||
| 
 |  | ||||||
|             layoutDesc = RenderPipelineLayoutDesc(); |  | ||||||
|             layoutDesc.isLocal = isLocal; |  | ||||||
|             layoutDesc.allowInputLayout = allowInputLayout; |  | ||||||
| 
 |  | ||||||
|             pushConstantRanges.clear(); |  | ||||||
|             samplerPointerVectorList.clear(); |  | ||||||
|             descriptorRanges.clear(); |  | ||||||
|             descriptorSetDescs.clear(); |  | ||||||
|             descriptorRangeIndexPerSet.clear(); |  | ||||||
|             rootDescriptorDescs.clear(); |  | ||||||
| 
 |  | ||||||
|             open = true; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Returns push constant index.
 |  | ||||||
|         uint32_t addPushConstant(uint32_t binding, uint32_t set, uint32_t size, RenderShaderStageFlags stageFlags, uint32_t offset = 0) { |  | ||||||
|             assert(open && "Builder must be open."); |  | ||||||
| 
 |  | ||||||
|             uint32_t returnValue = layoutDesc.pushConstantRangesCount; |  | ||||||
|             pushConstantRanges.emplace_back(RenderPushConstantRange(binding, set, offset, size, stageFlags)); |  | ||||||
|             layoutDesc.pushConstantRangesCount++; |  | ||||||
|             return returnValue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Returns set index.
 |  | ||||||
|         uint32_t addDescriptorSet(const RenderDescriptorSetDesc &descriptorSetDesc) { |  | ||||||
|             assert(open && "Builder must be open."); |  | ||||||
| 
 |  | ||||||
|             uint32_t returnValue = layoutDesc.descriptorSetDescsCount; |  | ||||||
|             descriptorRangeIndexPerSet.emplace_back(uint32_t(descriptorRanges.size())); |  | ||||||
|             descriptorSetDescs.emplace_back(descriptorSetDesc); |  | ||||||
| 
 |  | ||||||
|             for (uint32_t j = 0; j < descriptorSetDesc.descriptorRangesCount; j++) { |  | ||||||
|                 descriptorRanges.emplace_back(descriptorSetDesc.descriptorRanges[j]); |  | ||||||
| 
 |  | ||||||
|                 // Copy the immutable sampler pointers to a local vector list.
 |  | ||||||
|                 if (descriptorRanges.back().immutableSampler != nullptr) { |  | ||||||
|                     const RenderSampler **immutableSampler = descriptorRanges.back().immutableSampler; |  | ||||||
|                     samplerPointerVectorList.emplace_back(std::vector<const RenderSampler *>(immutableSampler, immutableSampler + descriptorRanges.back().count)); |  | ||||||
|                     descriptorRanges.back().immutableSampler = samplerPointerVectorList.back().data(); |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             layoutDesc.descriptorSetDescsCount++; |  | ||||||
| 
 |  | ||||||
|             return returnValue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Returns set index.
 |  | ||||||
|         uint32_t addDescriptorSet(const RenderDescriptorSetBuilder &descriptorSetBuilder) { |  | ||||||
|             return addDescriptorSet(descriptorSetBuilder.descriptorSetDesc); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Returns set index.
 |  | ||||||
|         uint32_t addDescriptorSet(const RenderDescriptorSetBase &descriptorSetBase) { |  | ||||||
|             return addDescriptorSet(descriptorSetBase.builder); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Returns root descriptor index. D3D12 only.
 |  | ||||||
|         uint32_t addRootDescriptor(uint32_t shaderRegister, uint32_t registerSpace, RenderRootDescriptorType type) { |  | ||||||
|             assert(open && "Builder must be open."); |  | ||||||
| 
 |  | ||||||
|             uint32_t returnValue = layoutDesc.rootDescriptorDescsCount; |  | ||||||
|             rootDescriptorDescs.emplace_back(shaderRegister, registerSpace, type); |  | ||||||
|             ++layoutDesc.rootDescriptorDescsCount; |  | ||||||
| 
 |  | ||||||
|             return returnValue; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Finish the description.
 |  | ||||||
|         void end() { |  | ||||||
|             assert(open && "Builder must be open."); |  | ||||||
| 
 |  | ||||||
|             if (layoutDesc.pushConstantRangesCount > 0) { |  | ||||||
|                 layoutDesc.pushConstantRanges = pushConstantRanges.data(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (layoutDesc.descriptorSetDescsCount > 0) { |  | ||||||
|                 for (uint32_t i = 0; i < layoutDesc.descriptorSetDescsCount; i++) { |  | ||||||
|                     const uint32_t rangeIndex = descriptorRangeIndexPerSet[i]; |  | ||||||
|                     descriptorSetDescs[i].descriptorRanges = &descriptorRanges[rangeIndex]; |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 layoutDesc.descriptorSetDescs = descriptorSetDescs.data(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             if (layoutDesc.rootDescriptorDescsCount > 0) { |  | ||||||
|                 layoutDesc.rootDescriptorDescs = rootDescriptorDescs.data(); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             open = false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Create a pipeline layout with the final description.
 |  | ||||||
|         std::unique_ptr<RenderPipelineLayout> create(RenderDevice *device) const { |  | ||||||
|             assert(!open && "Builder must be closed."); |  | ||||||
| 
 |  | ||||||
|             return device->createPipelineLayout(layoutDesc); |  | ||||||
|         } |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,456 +0,0 @@ | ||||||
| //
 |  | ||||||
| // plume
 |  | ||||||
| //
 |  | ||||||
| // Copyright (c) 2024 renderbag and contributors. All rights reserved.
 |  | ||||||
| // Licensed under the MIT license. See LICENSE file for details.
 |  | ||||||
| //
 |  | ||||||
| 
 |  | ||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include "plume_render_interface.h" |  | ||||||
| 
 |  | ||||||
| #include <mutex> |  | ||||||
| #include <set> |  | ||||||
| #include <unordered_map> |  | ||||||
| #include <unordered_set> |  | ||||||
| 
 |  | ||||||
| #if defined(_WIN64) |  | ||||||
| #define VK_USE_PLATFORM_WIN32_KHR |  | ||||||
| #elif defined(__ANDROID__) |  | ||||||
| #define VK_USE_PLATFORM_ANDROID_KHR |  | ||||||
| #elif defined(__linux__) |  | ||||||
| #define VK_USE_PLATFORM_XLIB_KHR |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #include <volk.h> |  | ||||||
| 
 |  | ||||||
| #ifdef __clang__ |  | ||||||
| #pragma clang diagnostic push |  | ||||||
| #pragma clang diagnostic ignored "-Wnullability-completeness" |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| #include <vk_mem_alloc.h> |  | ||||||
| 
 |  | ||||||
| #ifdef __clang__ |  | ||||||
| #pragma clang diagnostic pop |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| namespace plume { |  | ||||||
|     struct VulkanCommandQueue; |  | ||||||
|     struct VulkanDevice; |  | ||||||
|     struct VulkanInterface; |  | ||||||
|     struct VulkanPool; |  | ||||||
|     struct VulkanQueue; |  | ||||||
| 
 |  | ||||||
|     struct VulkanBuffer : RenderBuffer { |  | ||||||
|         VkBuffer vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         VulkanPool *pool = nullptr; |  | ||||||
|         VmaAllocation allocation = VK_NULL_HANDLE; |  | ||||||
|         VmaAllocationInfo allocationInfo = {}; |  | ||||||
|         RenderBufferDesc desc; |  | ||||||
|         RenderBarrierStages barrierStages = RenderBarrierStage::NONE; |  | ||||||
| 
 |  | ||||||
|         VulkanBuffer() = default; |  | ||||||
|         VulkanBuffer(VulkanDevice *device, VulkanPool *pool, const RenderBufferDesc &desc); |  | ||||||
|         ~VulkanBuffer() override; |  | ||||||
|         void *map(uint32_t subresource, const RenderRange *readRange) override; |  | ||||||
|         void unmap(uint32_t subresource, const RenderRange *writtenRange) override; |  | ||||||
|         std::unique_ptr<RenderBufferFormattedView> createBufferFormattedView(RenderFormat format) override; |  | ||||||
|         void setName(const std::string &name) override; |  | ||||||
|         uint64_t getDeviceAddress() const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanBufferFormattedView : RenderBufferFormattedView { |  | ||||||
|         VkBufferView vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanBuffer *buffer = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanBufferFormattedView(VulkanBuffer *buffer, RenderFormat format); |  | ||||||
|         ~VulkanBufferFormattedView() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanTexture : RenderTexture { |  | ||||||
|         VkImage vk = VK_NULL_HANDLE; |  | ||||||
|         VkImageView imageView = VK_NULL_HANDLE; |  | ||||||
|         VkFormat imageFormat = VK_FORMAT_UNDEFINED; |  | ||||||
|         VkImageSubresourceRange imageSubresourceRange = {}; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         VulkanPool *pool = nullptr; |  | ||||||
|         VmaAllocation allocation = VK_NULL_HANDLE; |  | ||||||
|         VmaAllocationInfo allocationInfo = {}; |  | ||||||
|         RenderTextureLayout textureLayout = RenderTextureLayout::UNKNOWN; |  | ||||||
|         RenderBarrierStages barrierStages = RenderBarrierStage::NONE; |  | ||||||
|         bool ownership = false; |  | ||||||
|         RenderTextureDesc desc; |  | ||||||
| 
 |  | ||||||
|         VulkanTexture() = default; |  | ||||||
|         VulkanTexture(VulkanDevice *device, VulkanPool *pool, const RenderTextureDesc &desc); |  | ||||||
|         VulkanTexture(VulkanDevice *device, VkImage image); |  | ||||||
|         ~VulkanTexture() override; |  | ||||||
|         void createImageView(VkFormat format); |  | ||||||
|         std::unique_ptr<RenderTextureView> createTextureView(const RenderTextureViewDesc &desc) override; |  | ||||||
|         void setName(const std::string &name) override; |  | ||||||
|         void fillSubresourceRange(); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanTextureView : RenderTextureView { |  | ||||||
|         VkImageView vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanTexture *texture = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanTextureView(VulkanTexture *texture, const RenderTextureViewDesc &desc); |  | ||||||
|         ~VulkanTextureView() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanAccelerationStructure : RenderAccelerationStructure { |  | ||||||
|         VkAccelerationStructureKHR vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         RenderAccelerationStructureType type = RenderAccelerationStructureType::UNKNOWN; |  | ||||||
| 
 |  | ||||||
|         VulkanAccelerationStructure(VulkanDevice *device, const RenderAccelerationStructureDesc &desc); |  | ||||||
|         ~VulkanAccelerationStructure() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanDescriptorSetLayout { |  | ||||||
|         VkDescriptorSetLayout vk = VK_NULL_HANDLE; |  | ||||||
|         std::vector<VkDescriptorSetLayoutBinding> setBindings; |  | ||||||
|         std::vector<uint32_t> descriptorIndexBases; |  | ||||||
|         std::vector<uint32_t> descriptorBindingIndices; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanDescriptorSetLayout(VulkanDevice *device, const RenderDescriptorSetDesc &descriptorSetDesc); |  | ||||||
|         ~VulkanDescriptorSetLayout(); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanPipelineLayout : RenderPipelineLayout { |  | ||||||
|         VkPipelineLayout vk = VK_NULL_HANDLE; |  | ||||||
|         std::vector<VkPushConstantRange> pushConstantRanges; |  | ||||||
|         std::vector<VulkanDescriptorSetLayout *> descriptorSetLayouts; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanPipelineLayout(VulkanDevice *device, const RenderPipelineLayoutDesc &desc); |  | ||||||
|         ~VulkanPipelineLayout() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanShader : RenderShader { |  | ||||||
|         VkShaderModule vk = VK_NULL_HANDLE; |  | ||||||
|         std::string entryPointName; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         RenderShaderFormat format = RenderShaderFormat::UNKNOWN; |  | ||||||
| 
 |  | ||||||
|         VulkanShader(VulkanDevice *device, const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format); |  | ||||||
|         ~VulkanShader() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanSampler : RenderSampler { |  | ||||||
|         VkSampler vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanSampler(VulkanDevice *device, const RenderSamplerDesc &desc); |  | ||||||
|         ~VulkanSampler(); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanPipeline : RenderPipeline { |  | ||||||
|         enum class Type { |  | ||||||
|             Unknown, |  | ||||||
|             Compute, |  | ||||||
|             Graphics, |  | ||||||
|             Raytracing |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         Type type = Type::Unknown; |  | ||||||
| 
 |  | ||||||
|         VulkanPipeline(VulkanDevice *device, Type type); |  | ||||||
|         virtual ~VulkanPipeline() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanComputePipeline : VulkanPipeline { |  | ||||||
|         VkPipeline vk = VK_NULL_HANDLE; |  | ||||||
|         VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; |  | ||||||
| 
 |  | ||||||
|         VulkanComputePipeline(VulkanDevice *device, const RenderComputePipelineDesc &desc); |  | ||||||
|         ~VulkanComputePipeline() override; |  | ||||||
|         void setName(const std::string& name) const override; |  | ||||||
|         RenderPipelineProgram getProgram(const std::string &name) const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanGraphicsPipeline : VulkanPipeline { |  | ||||||
|         VkPipeline vk = VK_NULL_HANDLE; |  | ||||||
|         VkRenderPass renderPass = VK_NULL_HANDLE; |  | ||||||
| 
 |  | ||||||
|         VulkanGraphicsPipeline(VulkanDevice *device, const RenderGraphicsPipelineDesc &desc); |  | ||||||
|         ~VulkanGraphicsPipeline() override; |  | ||||||
|         void setName(const std::string& name) const override; |  | ||||||
|         RenderPipelineProgram getProgram(const std::string &name) const override; |  | ||||||
|         static VkRenderPass createRenderPass(VulkanDevice *device, const VkFormat *renderTargetFormat, uint32_t renderTargetCount, VkFormat depthTargetFormat, VkSampleCountFlagBits sampleCount); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanRaytracingPipeline : VulkanPipeline { |  | ||||||
|         VkPipeline vk = VK_NULL_HANDLE; |  | ||||||
|         std::unordered_map<std::string, RenderPipelineProgram> nameProgramMap; |  | ||||||
|         uint32_t groupCount = 0; |  | ||||||
|         uint32_t descriptorSetCount = 0; |  | ||||||
| 
 |  | ||||||
|         VulkanRaytracingPipeline(VulkanDevice *device, const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline); |  | ||||||
|         ~VulkanRaytracingPipeline() override; |  | ||||||
|         void setName(const std::string& name) const override; |  | ||||||
|         RenderPipelineProgram getProgram(const std::string &name) const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanDescriptorSet : RenderDescriptorSet { |  | ||||||
|         VkDescriptorSet vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanDescriptorSetLayout *setLayout = nullptr; |  | ||||||
|         VkDescriptorPool descriptorPool = VK_NULL_HANDLE; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanDescriptorSet(VulkanDevice *device, const RenderDescriptorSetDesc &desc); |  | ||||||
|         ~VulkanDescriptorSet() override; |  | ||||||
|         void setBuffer(uint32_t descriptorIndex, const RenderBuffer *buffer, uint64_t bufferSize, const RenderBufferStructuredView *bufferStructuredView, const RenderBufferFormattedView *bufferFormattedView) override; |  | ||||||
|         void setTexture(uint32_t descriptorIndex, const RenderTexture *texture, RenderTextureLayout textureLayout, const RenderTextureView *textureView) override; |  | ||||||
|         void setSampler(uint32_t descriptorIndex, const RenderSampler *sampler) override; |  | ||||||
|         void setAccelerationStructure(uint32_t descriptorIndex, const RenderAccelerationStructure *accelerationStructure) override; |  | ||||||
|         void setDescriptor(uint32_t descriptorIndex, const VkDescriptorBufferInfo *bufferInfo, const VkDescriptorImageInfo *imageInfo, const VkBufferView *texelBufferView, void *pNext); |  | ||||||
|         static VkDescriptorPool createDescriptorPool(VulkanDevice *device, const std::unordered_map<VkDescriptorType, uint32_t> &typeCounts, bool lastRangeIsBoundless); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanSwapChain : RenderSwapChain { |  | ||||||
|         VkSwapchainKHR vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanCommandQueue *commandQueue = nullptr; |  | ||||||
|         VkSurfaceKHR surface = VK_NULL_HANDLE; |  | ||||||
|         RenderWindow renderWindow = {}; |  | ||||||
|         uint32_t textureCount = 0; |  | ||||||
|         uint64_t presentCount = 0; |  | ||||||
|         RenderFormat format = RenderFormat::UNKNOWN; |  | ||||||
|         uint32_t width = 0; |  | ||||||
|         uint32_t height = 0; |  | ||||||
|         VkSwapchainCreateInfoKHR createInfo = {}; |  | ||||||
|         VkSurfaceFormatKHR pickedSurfaceFormat = {}; |  | ||||||
|         VkPresentModeKHR createdPresentMode = VK_PRESENT_MODE_FIFO_KHR; |  | ||||||
|         VkPresentModeKHR requiredPresentMode = VK_PRESENT_MODE_FIFO_KHR; |  | ||||||
|         VkCompositeAlphaFlagBitsKHR pickedAlphaFlag = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; |  | ||||||
|         std::vector<VulkanTexture> textures; |  | ||||||
|         uint64_t currentPresentId = 0; |  | ||||||
|         bool immediatePresentModeSupported = false; |  | ||||||
|         uint32_t maxFrameLatency = 0; |  | ||||||
| 
 |  | ||||||
|         VulkanSwapChain(VulkanCommandQueue *commandQueue, RenderWindow renderWindow, uint32_t textureCount, RenderFormat format, uint32_t maxFrameLatency); |  | ||||||
|         ~VulkanSwapChain() override; |  | ||||||
|         bool present(uint32_t textureIndex, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount) override; |  | ||||||
|         void wait() override; |  | ||||||
|         bool resize() override; |  | ||||||
|         bool needsResize() const override; |  | ||||||
|         void setVsyncEnabled(bool vsyncEnabled) override; |  | ||||||
|         bool isVsyncEnabled() const override; |  | ||||||
|         uint32_t getWidth() const override; |  | ||||||
|         uint32_t getHeight() const override; |  | ||||||
|         RenderTexture *getTexture(uint32_t textureIndex) override; |  | ||||||
|         uint32_t getTextureCount() const override; |  | ||||||
|         bool acquireTexture(RenderCommandSemaphore *signalSemaphore, uint32_t *textureIndex) override; |  | ||||||
|         RenderWindow getWindow() const override; |  | ||||||
|         bool isEmpty() const override; |  | ||||||
|         uint32_t getRefreshRate() const override; |  | ||||||
|         void getWindowSize(uint32_t &dstWidth, uint32_t &dstHeight) const; |  | ||||||
|         void releaseSwapChain(); |  | ||||||
|         void releaseImageViews(); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanFramebuffer : RenderFramebuffer { |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         VkFramebuffer vk = VK_NULL_HANDLE; |  | ||||||
|         VkRenderPass renderPass = VK_NULL_HANDLE; |  | ||||||
|         std::vector<const VulkanTexture *> colorAttachments; |  | ||||||
|         const VulkanTexture *depthAttachment = nullptr; |  | ||||||
|         bool depthAttachmentReadOnly = false; |  | ||||||
|         uint32_t width = 0; |  | ||||||
|         uint32_t height = 0; |  | ||||||
| 
 |  | ||||||
|         VulkanFramebuffer(VulkanDevice *device, const RenderFramebufferDesc &desc); |  | ||||||
|         ~VulkanFramebuffer() override; |  | ||||||
|         uint32_t getWidth() const override; |  | ||||||
|         uint32_t getHeight() const override; |  | ||||||
|         bool contains(const VulkanTexture *attachment) const; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanQueryPool : RenderQueryPool { |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         std::vector<uint64_t> results; |  | ||||||
|         VkQueryPool vk = VK_NULL_HANDLE; |  | ||||||
| 
 |  | ||||||
|         VulkanQueryPool(VulkanDevice *device, uint32_t queryCount); |  | ||||||
|         virtual ~VulkanQueryPool() override; |  | ||||||
|         virtual void queryResults() override; |  | ||||||
|         virtual const uint64_t *getResults() const override; |  | ||||||
|         virtual uint32_t getCount() const override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanCommandList : RenderCommandList { |  | ||||||
|         VkCommandBuffer vk = VK_NULL_HANDLE; |  | ||||||
|         VkCommandPool commandPool = VK_NULL_HANDLE; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         RenderCommandListType type = RenderCommandListType::UNKNOWN; |  | ||||||
|         const VulkanFramebuffer *targetFramebuffer = nullptr; |  | ||||||
|         const VulkanPipelineLayout *activeComputePipelineLayout = nullptr; |  | ||||||
|         const VulkanPipelineLayout *activeGraphicsPipelineLayout = nullptr; |  | ||||||
|         const VulkanPipelineLayout *activeRaytracingPipelineLayout = nullptr; |  | ||||||
|         VkRenderPass activeRenderPass = VK_NULL_HANDLE; |  | ||||||
| 
 |  | ||||||
|         VulkanCommandList(VulkanDevice *device, RenderCommandListType type); |  | ||||||
|         ~VulkanCommandList() override; |  | ||||||
|         void begin() override; |  | ||||||
|         void end() override; |  | ||||||
|         void barriers(RenderBarrierStages stages, const RenderBufferBarrier *bufferBarriers, uint32_t bufferBarriersCount, const RenderTextureBarrier *textureBarriers, uint32_t textureBarriersCount) override; |  | ||||||
|         void dispatch(uint32_t threadGroupCountX, uint32_t threadGroupCountY, uint32_t threadGroupCountZ) override; |  | ||||||
|         void traceRays(uint32_t width, uint32_t height, uint32_t depth, RenderBufferReference shaderBindingTable, const RenderShaderBindingGroupsInfo &shaderBindingGroupsInfo) override; |  | ||||||
|         void drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) override; |  | ||||||
|         void drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) override; |  | ||||||
|         void setPipeline(const RenderPipeline *pipeline) override; |  | ||||||
|         void setComputePipelineLayout(const RenderPipelineLayout *pipelineLayout) override; |  | ||||||
|         void setComputePushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; |  | ||||||
|         void setComputeDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; |  | ||||||
|         void setGraphicsPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; |  | ||||||
|         void setGraphicsPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; |  | ||||||
|         void setGraphicsDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; |  | ||||||
|         void setGraphicsRootDescriptor(RenderBufferReference bufferReference, uint32_t rootDescriptorIndex) override; |  | ||||||
|         void setRaytracingPipelineLayout(const RenderPipelineLayout *pipelineLayout) override; |  | ||||||
|         void setRaytracingPushConstants(uint32_t rangeIndex, const void *data, uint32_t offset = 0, uint32_t size = 0) override; |  | ||||||
|         void setRaytracingDescriptorSet(RenderDescriptorSet *descriptorSet, uint32_t setIndex) override; |  | ||||||
|         void setIndexBuffer(const RenderIndexBufferView *view) override; |  | ||||||
|         void setVertexBuffers(uint32_t startSlot, const RenderVertexBufferView *views, uint32_t viewCount, const RenderInputSlot *inputSlots) override; |  | ||||||
|         void setViewports(const RenderViewport *viewports, uint32_t count) override; |  | ||||||
|         void setScissors(const RenderRect *scissorRects, uint32_t count) override; |  | ||||||
|         void setFramebuffer(const RenderFramebuffer *framebuffer) override; |  | ||||||
|         void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) override; |  | ||||||
|         void clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) override; |  | ||||||
|         void clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) override; |  | ||||||
|         void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) override; |  | ||||||
|         void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX, uint32_t dstY, uint32_t dstZ, const RenderBox *srcBox) override; |  | ||||||
|         void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override; |  | ||||||
|         void copyTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override; |  | ||||||
|         void resolveTexture(const RenderTexture *dstTexture, const RenderTexture *srcTexture) override; |  | ||||||
|         void resolveTextureRegion(const RenderTexture *dstTexture, uint32_t dstX, uint32_t dstY, const RenderTexture *srcTexture, const RenderRect *srcRect, RenderResolveMode resolveMode) override; |  | ||||||
|         void buildBottomLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, const RenderBottomLevelASBuildInfo &buildInfo) override; |  | ||||||
|         void buildTopLevelAS(const RenderAccelerationStructure *dstAccelerationStructure, RenderBufferReference scratchBuffer, RenderBufferReference instancesBuffer, const RenderTopLevelASBuildInfo &buildInfo) override; |  | ||||||
|         void discardTexture(const RenderTexture* texture) override; |  | ||||||
|         void resetQueryPool(const RenderQueryPool *queryPool, uint32_t queryFirstIndex, uint32_t queryCount) override; |  | ||||||
|         void writeTimestamp(const RenderQueryPool *queryPool, uint32_t queryIndex) override; |  | ||||||
|         void checkActiveRenderPass(); |  | ||||||
|         void endActiveRenderPass(); |  | ||||||
|         void setDescriptorSet(VkPipelineBindPoint bindPoint, const VulkanPipelineLayout *pipelineLayout, const RenderDescriptorSet *descriptorSet, uint32_t setIndex); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanCommandFence : RenderCommandFence { |  | ||||||
|         VkFence vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanCommandFence(VulkanDevice *device); |  | ||||||
|         ~VulkanCommandFence() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanCommandSemaphore : RenderCommandSemaphore { |  | ||||||
|         VkSemaphore vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanCommandSemaphore(VulkanDevice *device); |  | ||||||
|         ~VulkanCommandSemaphore() override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanCommandQueue : RenderCommandQueue { |  | ||||||
|         VulkanQueue *queue = nullptr; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
|         uint32_t familyIndex = 0; |  | ||||||
|         uint32_t queueIndex = 0; |  | ||||||
|         std::unordered_set<VulkanSwapChain *> swapChains; |  | ||||||
| 
 |  | ||||||
|         VulkanCommandQueue(VulkanDevice *device, RenderCommandListType commandListType); |  | ||||||
|         ~VulkanCommandQueue() override; |  | ||||||
|         std::unique_ptr<RenderSwapChain> createSwapChain(RenderWindow renderWindow, uint32_t bufferCount, RenderFormat format, uint32_t maxFrameLatency) override; |  | ||||||
|         void executeCommandLists(const RenderCommandList **commandLists, uint32_t commandListCount, RenderCommandSemaphore **waitSemaphores, uint32_t waitSemaphoreCount, RenderCommandSemaphore **signalSemaphores, uint32_t signalSemaphoreCount, RenderCommandFence *signalFence) override; |  | ||||||
|         void waitForCommandFence(RenderCommandFence *fence) override; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanPool : RenderPool { |  | ||||||
|         VmaPool vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanDevice *device = nullptr; |  | ||||||
| 
 |  | ||||||
|         VulkanPool(VulkanDevice *device, const RenderPoolDesc &desc); |  | ||||||
|         ~VulkanPool() override; |  | ||||||
|         std::unique_ptr<RenderBuffer> createBuffer(const RenderBufferDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) override; |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|     struct VulkanQueue { |  | ||||||
|         VkQueue vk; |  | ||||||
|         std::unique_ptr<std::mutex> mutex; |  | ||||||
|         std::unordered_set<const VulkanCommandQueue *> virtualQueues; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanQueueFamily { |  | ||||||
|         std::vector<VulkanQueue> queues; |  | ||||||
| 
 |  | ||||||
|         void add(VulkanCommandQueue *virtualQueue); |  | ||||||
|         void remove(VulkanCommandQueue *virtualQueue); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanDevice : RenderDevice { |  | ||||||
|         VkDevice vk = VK_NULL_HANDLE; |  | ||||||
|         VulkanInterface *renderInterface = nullptr; |  | ||||||
|         VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; |  | ||||||
|         VkPhysicalDeviceProperties physicalDeviceProperties = {}; |  | ||||||
|         VmaAllocator allocator = VK_NULL_HANDLE; |  | ||||||
|         uint32_t queueFamilyIndices[3] = {}; |  | ||||||
|         std::vector<VulkanQueueFamily> queueFamilies; |  | ||||||
|         RenderDeviceCapabilities capabilities; |  | ||||||
|         RenderDeviceDescription description; |  | ||||||
|         VkPhysicalDeviceRayTracingPipelinePropertiesKHR rtPipelineProperties = {}; |  | ||||||
|         VkPhysicalDeviceSampleLocationsPropertiesEXT sampleLocationProperties = {}; |  | ||||||
|         bool loadStoreOpNoneSupported = false; |  | ||||||
| 
 |  | ||||||
|         VulkanDevice(VulkanInterface *renderInterface, const std::string &preferredDeviceName); |  | ||||||
|         ~VulkanDevice() override; |  | ||||||
|         std::unique_ptr<RenderCommandList> createCommandList(RenderCommandListType type) override; |  | ||||||
|         std::unique_ptr<RenderDescriptorSet> createDescriptorSet(const RenderDescriptorSetDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderShader> createShader(const void *data, uint64_t size, const char *entryPointName, RenderShaderFormat format) override; |  | ||||||
|         std::unique_ptr<RenderSampler> createSampler(const RenderSamplerDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPipeline> createComputePipeline(const RenderComputePipelineDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPipeline> createGraphicsPipeline(const RenderGraphicsPipelineDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPipeline> createRaytracingPipeline(const RenderRaytracingPipelineDesc &desc, const RenderPipeline *previousPipeline) override; |  | ||||||
|         std::unique_ptr<RenderCommandQueue> createCommandQueue(RenderCommandListType type) override; |  | ||||||
|         std::unique_ptr<RenderBuffer> createBuffer(const RenderBufferDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderTexture> createTexture(const RenderTextureDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderAccelerationStructure> createAccelerationStructure(const RenderAccelerationStructureDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPool> createPool(const RenderPoolDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderPipelineLayout> createPipelineLayout(const RenderPipelineLayoutDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderCommandFence> createCommandFence() override; |  | ||||||
|         std::unique_ptr<RenderCommandSemaphore> createCommandSemaphore() override; |  | ||||||
|         std::unique_ptr<RenderFramebuffer> createFramebuffer(const RenderFramebufferDesc &desc) override; |  | ||||||
|         std::unique_ptr<RenderQueryPool> createQueryPool(uint32_t queryCount) override; |  | ||||||
|         void setBottomLevelASBuildInfo(RenderBottomLevelASBuildInfo &buildInfo, const RenderBottomLevelASMesh *meshes, uint32_t meshCount, bool preferFastBuild, bool preferFastTrace) override; |  | ||||||
|         void setTopLevelASBuildInfo(RenderTopLevelASBuildInfo &buildInfo, const RenderTopLevelASInstance *instances, uint32_t instanceCount, bool preferFastBuild, bool preferFastTrace) override; |  | ||||||
|         void setShaderBindingTableInfo(RenderShaderBindingTableInfo &tableInfo, const RenderShaderBindingGroups &groups, const RenderPipeline *pipeline, RenderDescriptorSet **descriptorSets, uint32_t descriptorSetCount) override; |  | ||||||
|         const RenderDeviceCapabilities &getCapabilities() const override; |  | ||||||
|         const RenderDeviceDescription &getDescription() const override; |  | ||||||
|         RenderSampleCounts getSampleCountsSupported(RenderFormat format) const override; |  | ||||||
|         void waitIdle() const override; |  | ||||||
|         void release(); |  | ||||||
|         bool isValid() const; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     struct VulkanInterface : RenderInterface { |  | ||||||
|         VkInstance instance = VK_NULL_HANDLE; |  | ||||||
|         VkApplicationInfo appInfo = {}; |  | ||||||
|         RenderInterfaceCapabilities capabilities; |  | ||||||
|         std::vector<std::string> deviceNames; |  | ||||||
| 
 |  | ||||||
| #   if SDL_VULKAN_ENABLED |  | ||||||
|         VulkanInterface(RenderWindow sdlWindow); |  | ||||||
| #   else |  | ||||||
|         VulkanInterface(); |  | ||||||
| #   endif |  | ||||||
| 
 |  | ||||||
|         ~VulkanInterface() override; |  | ||||||
|         std::unique_ptr<RenderDevice> createDevice(const std::string &preferredDeviceName) override; |  | ||||||
|         const RenderInterfaceCapabilities &getCapabilities() const override; |  | ||||||
|         const std::vector<std::string> &getDeviceNames() const override; |  | ||||||
|         bool isValid() const; |  | ||||||
|     }; |  | ||||||
| }; |  | ||||||
|  | @ -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 | ||||||
|  | @ -1837,7 +1838,7 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) | ||||||
|     g_queue = g_device->createCommandQueue(RenderCommandListType::DIRECT); |     g_queue = g_device->createCommandQueue(RenderCommandListType::DIRECT); | ||||||
| 
 | 
 | ||||||
|     for (auto& commandList : g_commandLists) |     for (auto& commandList : g_commandLists) | ||||||
|         commandList = g_device->createCommandList(RenderCommandListType::DIRECT); |         commandList = g_queue->createCommandList(); | ||||||
| 
 | 
 | ||||||
|     for (auto& commandFence : g_commandFences) |     for (auto& commandFence : g_commandFences) | ||||||
|         commandFence = g_device->createCommandFence(); |         commandFence = g_device->createCommandFence(); | ||||||
|  | @ -1846,7 +1847,7 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) | ||||||
|         queryPool = g_device->createQueryPool(NUM_QUERIES); |         queryPool = g_device->createQueryPool(NUM_QUERIES); | ||||||
| 
 | 
 | ||||||
|     g_copyQueue = g_device->createCommandQueue(RenderCommandListType::COPY); |     g_copyQueue = g_device->createCommandQueue(RenderCommandListType::COPY); | ||||||
|     g_copyCommandList = g_device->createCommandList(RenderCommandListType::COPY); |     g_copyCommandList = g_copyQueue->createCommandList(); | ||||||
|     g_copyCommandFence = g_device->createCommandFence(); |     g_copyCommandFence = g_device->createCommandFence(); | ||||||
| 
 | 
 | ||||||
|     uint32_t bufferCount = 2; |     uint32_t bufferCount = 2; | ||||||
|  | @ -2074,12 +2075,7 @@ void Video::WaitForGPU() | ||||||
| { | { | ||||||
|     g_waitForGPUCount++; |     g_waitForGPUCount++; | ||||||
| 
 | 
 | ||||||
|     if (g_vulkan) |     // Wait for all queued frames to finish.
 | ||||||
|     { |  | ||||||
|         g_device->waitIdle(); |  | ||||||
|     } |  | ||||||
|     else  |  | ||||||
|     { |  | ||||||
|     for (size_t i = 0; i < NUM_FRAMES; i++) |     for (size_t i = 0; i < NUM_FRAMES; i++) | ||||||
|     { |     { | ||||||
|         if (g_commandListStates[i]) |         if (g_commandListStates[i]) | ||||||
|  | @ -2088,10 +2084,13 @@ void Video::WaitForGPU() | ||||||
|             g_commandListStates[i] = false; |             g_commandListStates[i] = false; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|         g_queue->executeCommandLists(nullptr, g_commandFences[0].get()); | 
 | ||||||
|  |     // Execute an empty command list and wait for it to end to guarantee that any remaining presentation has finished.
 | ||||||
|  |     g_commandLists[0]->begin(); | ||||||
|  |     g_commandLists[0]->end(); | ||||||
|  |     g_queue->executeCommandLists(g_commandLists[0].get(), g_commandFences[0].get()); | ||||||
|     g_queue->waitForCommandFence(g_commandFences[0].get()); |     g_queue->waitForCommandFence(g_commandFences[0].get()); | ||||||
| } | } | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5, be<uint32_t>* a6) | static uint32_t CreateDevice(uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5, be<uint32_t>* a6) | ||||||
| { | { | ||||||
|  | @ -5736,7 +5735,7 @@ static bool LoadTexture(GuestTexture& texture, const uint8_t* data, size_t dataS | ||||||
|                 auto copyTextureRegion = [&](Slice& slice, uint32_t subresourceIndex) |                 auto copyTextureRegion = [&](Slice& slice, uint32_t subresourceIndex) | ||||||
|                     { |                     { | ||||||
|                         g_copyCommandList->copyTextureRegion( |                         g_copyCommandList->copyTextureRegion( | ||||||
|                             RenderTextureCopyLocation::Subresource(texture.texture, subresourceIndex), |                             RenderTextureCopyLocation::Subresource(texture.texture, subresourceIndex % ddsDesc.numMips, subresourceIndex / ddsDesc.numMips), | ||||||
|                             RenderTextureCopyLocation::PlacedFootprint(uploadBuffer.get(), desc.format, slice.width, slice.height, slice.depth, (slice.dstRowPitch * 8) / ddsDesc.bitsPerPixelOrBlock * ddsDesc.blockWidth, slice.dstOffset)); |                             RenderTextureCopyLocation::PlacedFootprint(uploadBuffer.get(), desc.format, slice.width, slice.height, slice.depth, (slice.dstRowPitch * 8) / ddsDesc.bitsPerPixelOrBlock * ddsDesc.blockWidth, slice.dstOffset)); | ||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ | ||||||
| /////////////////////////////////////////////////////////////////////#define PSO_CACHING
 | /////////////////////////////////////////////////////////////////////#define PSO_CACHING
 | ||||||
| //#define PSO_CACHING_CLEANUP
 | //#define PSO_CACHING_CLEANUP
 | ||||||
| 
 | 
 | ||||||
| #include "rhi/plume_render_interface.h" | #include <plume_render_interface.h> | ||||||
| 
 | 
 | ||||||
| #define D3DCLEAR_TARGET  0x1 | #define D3DCLEAR_TARGET  0x1 | ||||||
| #define D3DCLEAR_ZBUFFER 0x10 | #define D3DCLEAR_ZBUFFER 0x10 | ||||||
|  |  | ||||||
|  | @ -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]; | ||||||
|  |  | ||||||
|  | @ -64,6 +64,30 @@ bool UseAlternateTitleMidAsmHook() | ||||||
|     return isSWA; |     return isSWA; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | bool UseAlternateTitleStaffRollMidAsmHook(PPCRegister& r1) | ||||||
|  | { | ||||||
|  |     auto pGroupName = (Hedgehog::Base::CSharedString*)g_memory.Translate(r1.s64 + 0x60); | ||||||
|  | 
 | ||||||
|  |     if (Config::UseAlternateTitle) | ||||||
|  |     { | ||||||
|  |         // Redirect English title to Japanese title.
 | ||||||
|  |         if (strcmp(pGroupName->c_str(), "OFCI5") == 0 || strcmp(pGroupName->c_str(), "OTLR11") == 0) | ||||||
|  |             return Config::Language == ELanguage::Japanese; | ||||||
|  | 
 | ||||||
|  |         // Redirect Japanese title to English title.
 | ||||||
|  |         if (strcmp(pGroupName->c_str(), "JFCI7") == 0 || strcmp(pGroupName->c_str(), "JTLR13") == 0) | ||||||
|  |             return Config::Language != ELanguage::Japanese; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (pGroupName->c_str()[0] == 'J') | ||||||
|  |         return Config::Language == ELanguage::Japanese; | ||||||
|  | 
 | ||||||
|  |     if (pGroupName->c_str()[0] == 'O') | ||||||
|  |         return Config::Language != ELanguage::Japanese; | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /* Hook function that gets the game region
 | /* Hook function that gets the game region
 | ||||||
|    and force result to zero for Japanese |    and force result to zero for Japanese | ||||||
|    to display the correct logos. */ |    to display the correct logos. */ | ||||||
|  |  | ||||||
							
								
								
									
										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 = info.info.cocoa.window; | ||||||
|  |     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 | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <gpu/rhi/plume_render_interface_types.h> | #include <plume_render_interface_types.h> | ||||||
| #include <user/config.h> | #include <user/config.h> | ||||||
| #include <sdl_events.h> | #include <sdl_events.h> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1146,7 +1146,11 @@ static void PickerStart(bool folderMode) { | ||||||
|     g_currentPickerVisible = true; |     g_currentPickerVisible = true; | ||||||
| 
 | 
 | ||||||
|     // Optional single thread mode for testing on systems that do not interact well with the separate thread being used for NFD.
 |     // Optional single thread mode for testing on systems that do not interact well with the separate thread being used for NFD.
 | ||||||
|  | #ifdef __APPLE__ | ||||||
|  |     constexpr bool singleThreadMode = true; | ||||||
|  | #else | ||||||
|     constexpr bool singleThreadMode = false; |     constexpr bool singleThreadMode = false; | ||||||
|  | #endif | ||||||
|     if (singleThreadMode) |     if (singleThreadMode) | ||||||
|         PickerThreadProcess(); |         PickerThreadProcess(); | ||||||
|     else |     else | ||||||
|  |  | ||||||
|  | @ -41,7 +41,7 @@ static ImFont* g_fntSeurat; | ||||||
| 
 | 
 | ||||||
| std::string g_text; | std::string g_text; | ||||||
| int g_result; | int g_result; | ||||||
| std::vector<std::string> g_buttons; | static std::vector<std::string> g_buttons; | ||||||
| int g_defaultButtonIndex; | int g_defaultButtonIndex; | ||||||
| int g_cancelButtonIndex; | int g_cancelButtonIndex; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| #include "paths.h" | #include "paths.h" | ||||||
| #include <os/process.h> | #include <os/process.h> | ||||||
| 
 | 
 | ||||||
| std::filesystem::path g_executableRoot = os::process::GetExecutablePath().remove_filename(); | std::filesystem::path g_executableRoot = os::process::GetExecutableRoot(); | ||||||
| std::filesystem::path g_userPath = BuildUserPath(); | std::filesystem::path g_userPath = BuildUserPath(); | ||||||
| 
 | 
 | ||||||
| bool CheckPortable() | bool CheckPortable() | ||||||
|  | @ -22,18 +22,24 @@ std::filesystem::path BuildUserPath() | ||||||
|         userPath = std::filesystem::path{ knownPath } / USER_DIRECTORY; |         userPath = std::filesystem::path{ knownPath } / USER_DIRECTORY; | ||||||
| 
 | 
 | ||||||
|     CoTaskMemFree(knownPath); |     CoTaskMemFree(knownPath); | ||||||
| #elif defined(__linux__) | #elif defined(__linux__) || defined(__APPLE__) | ||||||
|     const char* homeDir = getenv("HOME"); |     const char* homeDir = getenv("HOME"); | ||||||
|  | #if defined(__linux__) | ||||||
|     if (homeDir == nullptr) |     if (homeDir == nullptr) | ||||||
|     { |     { | ||||||
|         homeDir = getpwuid(getuid())->pw_dir; |         homeDir = getpwuid(getuid())->pw_dir; | ||||||
|     } |     } | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
|     if (homeDir != nullptr) |     if (homeDir != nullptr) | ||||||
|     { |     { | ||||||
|         // Prefer to store in the .config directory if it exists. Use the home directory otherwise.
 |         // Prefer to store in the .config directory if it exists. Use the home directory otherwise.
 | ||||||
|         std::filesystem::path homePath = homeDir; |         std::filesystem::path homePath = homeDir; | ||||||
|  | #if defined(__linux__) | ||||||
|         std::filesystem::path configPath = homePath / ".config"; |         std::filesystem::path configPath = homePath / ".config"; | ||||||
|  | #else | ||||||
|  |         std::filesystem::path configPath = homePath / "Library" / "Application Support"; | ||||||
|  | #endif | ||||||
|         if (std::filesystem::exists(configPath)) |         if (std::filesystem::exists(configPath)) | ||||||
|             userPath = configPath / USER_DIRECTORY; |             userPath = configPath / USER_DIRECTORY; | ||||||
|         else |         else | ||||||
|  |  | ||||||
|  | @ -10,15 +10,22 @@ | ||||||
| 
 | 
 | ||||||
| extern std::filesystem::path g_executableRoot; | extern std::filesystem::path g_executableRoot; | ||||||
| 
 | 
 | ||||||
| inline std::filesystem::path GetGamePath() |  | ||||||
| { |  | ||||||
|     return GAME_INSTALL_DIRECTORY; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool CheckPortable(); | bool CheckPortable(); | ||||||
| std::filesystem::path BuildUserPath(); | std::filesystem::path BuildUserPath(); | ||||||
| const std::filesystem::path& GetUserPath(); | const std::filesystem::path& GetUserPath(); | ||||||
| 
 | 
 | ||||||
|  | inline std::filesystem::path GetGamePath() | ||||||
|  | { | ||||||
|  | #ifdef __APPLE__ | ||||||
|  |     // On macOS, there is the expectation that the app may be installed to
 | ||||||
|  |     // /Applications/, and the bundle should not be modified. Thus we need
 | ||||||
|  |     // to install game files to the user directory instead of next to the app.
 | ||||||
|  |     return GetUserPath(); | ||||||
|  | #else | ||||||
|  |     return GAME_INSTALL_DIRECTORY; | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
| inline std::filesystem::path GetSavePath(bool checkForMods) | inline std::filesystem::path GetSavePath(bool checkForMods) | ||||||
| { | { | ||||||
|     if (checkForMods && !ModLoader::s_saveFilePath.empty()) |     if (checkForMods && !ModLoader::s_saveFilePath.empty()) | ||||||
|  |  | ||||||
|  | @ -35,6 +35,7 @@ add_custom_command( | ||||||
|         "${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex" |         "${CMAKE_CURRENT_SOURCE_DIR}/private/default.xex" | ||||||
|         "${CMAKE_CURRENT_SOURCE_DIR}/private/default.xexp" |         "${CMAKE_CURRENT_SOURCE_DIR}/private/default.xexp" | ||||||
|         "${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml" |         "${CMAKE_CURRENT_SOURCE_DIR}/config/SWA.toml" | ||||||
|  |     USES_TERMINAL | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| add_custom_command( | add_custom_command( | ||||||
|  | @ -53,6 +54,7 @@ target_compile_definitions(XenosRecomp PRIVATE | ||||||
|     XENOS_RECOMP_INPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/private\"  |     XENOS_RECOMP_INPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/private\"  | ||||||
|     XENOS_RECOMP_OUTPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/shader/shader_cache.cpp\" |     XENOS_RECOMP_OUTPUT=\"${CMAKE_CURRENT_SOURCE_DIR}/shader/shader_cache.cpp\" | ||||||
|     XENOS_RECOMP_INCLUDE_INPUT=\"${XENOS_RECOMP_INCLUDE}\" |     XENOS_RECOMP_INCLUDE_INPUT=\"${XENOS_RECOMP_INCLUDE}\" | ||||||
|  |     UNLEASHED_RECOMP | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| file(GLOB XENOS_RECOMP_SOURCES  | file(GLOB XENOS_RECOMP_SOURCES  | ||||||
|  | @ -70,6 +72,7 @@ add_custom_command( | ||||||
|         "${CMAKE_CURRENT_SOURCE_DIR}/private/shader_decompressed.ar"  |         "${CMAKE_CURRENT_SOURCE_DIR}/private/shader_decompressed.ar"  | ||||||
|         ${XENOS_RECOMP_SOURCES}  |         ${XENOS_RECOMP_SOURCES}  | ||||||
|         ${XENOS_RECOMP_INCLUDE} |         ${XENOS_RECOMP_INCLUDE} | ||||||
|  |     USES_TERMINAL | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| add_library(UnleashedRecompLib  | add_library(UnleashedRecompLib  | ||||||
|  | @ -79,4 +82,5 @@ add_library(UnleashedRecompLib | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| target_include_directories(UnleashedRecompLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) | target_include_directories(UnleashedRecompLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) | ||||||
|  | target_include_directories(UnleashedRecompLib PRIVATE "${UNLEASHED_RECOMP_TOOLS_ROOT}/XenonRecomp/thirdparty/simde") | ||||||
| target_precompile_headers(UnleashedRecompLib PUBLIC "ppc/ppc_recomp_shared.h") | target_precompile_headers(UnleashedRecompLib PUBLIC "ppc/ppc_recomp_shared.h") | ||||||
|  |  | ||||||
|  | @ -1101,12 +1101,35 @@ name = "ObjGrindDashPanelAllocMidAsmHook" | ||||||
| address = 0x82614948 | address = 0x82614948 | ||||||
| registers = ["r3"] | registers = ["r3"] | ||||||
| 
 | 
 | ||||||
|  | # Title screen logo | ||||||
| [[midasm_hook]] | [[midasm_hook]] | ||||||
| name = "UseAlternateTitleMidAsmHook" | name = "UseAlternateTitleMidAsmHook" | ||||||
| address = 0x82580F44 | address = 0x82580F44 | ||||||
| jump_address_on_true = 0x82580F48 | jump_address_on_true = 0x82580F48 | ||||||
| jump_address_on_false = 0x82580FA0 | jump_address_on_false = 0x82580FA0 | ||||||
| 
 | 
 | ||||||
|  | # Advertise movie logo | ||||||
|  | [[midasm_hook]] | ||||||
|  | name = "UseAlternateTitleMidAsmHook" | ||||||
|  | address = 0x82B73780 | ||||||
|  | jump_address_on_true = 0x82B73784 | ||||||
|  | jump_address_on_false = 0x82B737F8 | ||||||
|  | 
 | ||||||
|  | # Opening movie logo | ||||||
|  | [[midasm_hook]] | ||||||
|  | name = "UseAlternateTitleMidAsmHook" | ||||||
|  | address = 0x82B73630 | ||||||
|  | jump_address_on_true = 0x82B73634 | ||||||
|  | jump_address_on_false = 0x82B736B0 | ||||||
|  | 
 | ||||||
|  | # Staff roll logo | ||||||
|  | [[midasm_hook]] | ||||||
|  | name = "UseAlternateTitleStaffRollMidAsmHook" | ||||||
|  | address = 0x8257EBF0 | ||||||
|  | registers = ["r1"] | ||||||
|  | jump_address_on_true = 0x8257EC7C | ||||||
|  | jump_address_on_false = 0x8257ECC0 | ||||||
|  | 
 | ||||||
| [[midasm_hook]] | [[midasm_hook]] | ||||||
| name = "EndingTextAllocMidAsmHook" | name = "EndingTextAllocMidAsmHook" | ||||||
| address = 0x8257E284 | address = 0x8257E284 | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  | ``` | ||||||
|  |  | ||||||
							
								
								
									
										5
									
								
								thirdparty/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								thirdparty/CMakeLists.txt
									
										
									
									
										vendored
									
									
								
							|  | @ -20,3 +20,8 @@ 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") | ||||||
|  | add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/plume") | ||||||
|  | 
 | ||||||
|  | if (APPLE) | ||||||
|  |     add_subdirectory("${UNLEASHED_RECOMP_THIRDPARTY_ROOT}/MoltenVK") | ||||||
|  | endif() | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								thirdparty/D3D12MemoryAllocator
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/D3D12MemoryAllocator
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +0,0 @@ | ||||||
| Subproject commit e00c4a7c85cf9c28c6f4a6cc75032736f416410f |  | ||||||
							
								
								
									
										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}/plume/contrib/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 | ||||||
							
								
								
									
										1
									
								
								thirdparty/Vulkan-Headers
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/Vulkan-Headers
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +0,0 @@ | ||||||
| Subproject commit 14345dab231912ee9601136e96ca67a6e1f632e7 |  | ||||||
							
								
								
									
										1
									
								
								thirdparty/VulkanMemoryAllocator
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/VulkanMemoryAllocator
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +0,0 @@ | ||||||
| Subproject commit 1c35ba99ce775f8342d87a83a3f0f696f99c2a39 |  | ||||||
							
								
								
									
										1
									
								
								thirdparty/plume
									
										
									
									
										vendored
									
									
										Submodule
									
								
							
							
						
						
									
										1
									
								
								thirdparty/plume
									
										
									
									
										vendored
									
									
										Submodule
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | Subproject commit fffeb35f836d8c945697ec82b735e77db401e2de | ||||||
							
								
								
									
										1
									
								
								thirdparty/volk
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								thirdparty/volk
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +0,0 @@ | ||||||
| Subproject commit 447e21b5d92ed8d5271b0d39b071f938fcfa875f |  | ||||||
|  | @ -1 +1 @@ | ||||||
| Subproject commit c017eb630ab917bffd3bc6a0a46995b49e7d8049 | Subproject commit c5bfd90d87f2ed0db8cff5c19ea3aff0e161e527 | ||||||
|  | @ -1 +1 @@ | ||||||
| Subproject commit 56738e5893ed7c4dc108996590475c52726623e3 | Subproject commit 990d03b28a27b50277ee5d8d942e1c5f873869d1 | ||||||
|  | @ -9,8 +9,12 @@ | ||||||
|             "name": "directx12-agility", |             "name": "directx12-agility", | ||||||
|             "platform": "windows" |             "platform": "windows" | ||||||
|         }, |         }, | ||||||
|         "directx-dxc", |  | ||||||
|         "freetype", |         "freetype", | ||||||
|         "curl" |         "curl" | ||||||
|  |     ], | ||||||
|  |     "vcpkg-configuration": { | ||||||
|  |         "overlay-triplets": [ | ||||||
|  |             "vcpkg/triplets" | ||||||
|         ] |         ] | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								vcpkg/triplets/arm64-osx.cmake
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vcpkg/triplets/arm64-osx.cmake
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | set(VCPKG_TARGET_ARCHITECTURE arm64) | ||||||
|  | set(VCPKG_CRT_LINKAGE dynamic) | ||||||
|  | set(VCPKG_LIBRARY_LINKAGE static) | ||||||
|  | 
 | ||||||
|  | set(VCPKG_CMAKE_SYSTEM_NAME Darwin) | ||||||
|  | set(VCPKG_OSX_ARCHITECTURES arm64) | ||||||
|  | set(VCPKG_OSX_DEPLOYMENT_TARGET "13.0") | ||||||
							
								
								
									
										7
									
								
								vcpkg/triplets/x64-osx.cmake
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								vcpkg/triplets/x64-osx.cmake
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | set(VCPKG_TARGET_ARCHITECTURE x64) | ||||||
|  | set(VCPKG_CRT_LINKAGE dynamic) | ||||||
|  | set(VCPKG_LIBRARY_LINKAGE static) | ||||||
|  | 
 | ||||||
|  | set(VCPKG_CMAKE_SYSTEM_NAME Darwin) | ||||||
|  | set(VCPKG_OSX_ARCHITECTURES x86_64) | ||||||
|  | set(VCPKG_OSX_DEPLOYMENT_TARGET "13.0") | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue