diff --git a/UnleashedRecomp/CMakeLists.txt b/UnleashedRecomp/CMakeLists.txt index 1312f90f..a538fe1b 100644 --- a/UnleashedRecomp/CMakeLists.txt +++ b/UnleashedRecomp/CMakeLists.txt @@ -1,18 +1,18 @@ -project("UnleashedRecomp") - -set(UNLEASHED_RECOMP_HOST_TOOLS_DIR "" CACHE PATH "Directory containing host-built recompilation tools.") - -function(unleashed_recomp_resolve_tool OUT_VAR TARGET_NAME RELATIVE_PATH) - if (UNLEASHED_RECOMP_HOST_TOOLS_DIR) - set(${OUT_VAR} "${UNLEASHED_RECOMP_HOST_TOOLS_DIR}/${RELATIVE_PATH}" PARENT_SCOPE) - elseif (TARGET ${TARGET_NAME}) - set(${OUT_VAR} "$" PARENT_SCOPE) - else() - message(FATAL_ERROR "Tool ${TARGET_NAME} is not available. Set UNLEASHED_RECOMP_HOST_TOOLS_DIR.") - endif() -endfunction() - -unleashed_recomp_resolve_tool(UNLEASHED_RECOMP_FILE_TO_C_TOOL file_to_c "tools/file_to_c/file_to_c") +project("UnleashedRecomp") + +set(UNLEASHED_RECOMP_HOST_TOOLS_DIR "" CACHE PATH "Directory containing host-built recompilation tools.") + +function(unleashed_recomp_resolve_tool OUT_VAR TARGET_NAME RELATIVE_PATH) + if (UNLEASHED_RECOMP_HOST_TOOLS_DIR) + set(${OUT_VAR} "${UNLEASHED_RECOMP_HOST_TOOLS_DIR}/${RELATIVE_PATH}" PARENT_SCOPE) + elseif (TARGET ${TARGET_NAME}) + set(${OUT_VAR} "$" PARENT_SCOPE) + else() + message(FATAL_ERROR "Tool ${TARGET_NAME} is not available. Set UNLEASHED_RECOMP_HOST_TOOLS_DIR.") + endif() +endfunction() + +unleashed_recomp_resolve_tool(UNLEASHED_RECOMP_FILE_TO_C_TOOL file_to_c "tools/file_to_c/file_to_c") if (WIN32) option(UNLEASHED_RECOMP_D3D12 "Add D3D12 support for rendering" ON) @@ -41,8 +41,8 @@ function(BIN2C) set(BIN2C_ARGS_COMPRESSION_TYPE "none") endif() - add_custom_command(OUTPUT "${BIN2C_ARGS_DEST_FILE}.c" - COMMAND "${UNLEASHED_RECOMP_FILE_TO_C_TOOL}" "${BIN2C_ARGS_SOURCE_FILE}" "${BIN2C_ARGS_ARRAY_NAME}" "${BIN2C_ARGS_COMPRESSION_TYPE}" "${BIN2C_ARGS_DEST_FILE}.c" "${BIN2C_ARGS_DEST_FILE}.h" + add_custom_command(OUTPUT "${BIN2C_ARGS_DEST_FILE}.c" + COMMAND "${UNLEASHED_RECOMP_FILE_TO_C_TOOL}" "${BIN2C_ARGS_SOURCE_FILE}" "${BIN2C_ARGS_ARRAY_NAME}" "${BIN2C_ARGS_COMPRESSION_TYPE}" "${BIN2C_ARGS_DEST_FILE}.c" "${BIN2C_ARGS_DEST_FILE}.h" DEPENDS "${BIN2C_ARGS_SOURCE_FILE}" BYPRODUCTS "${BIN2C_ARGS_DEST_FILE}.h" COMMENT "Generating binary header for ${BIN2C_ARGS_SOURCE_FILE}..." @@ -72,17 +72,17 @@ else() add_compile_options(-ffp-model=strict) endif() -set(UNLEASHED_RECOMP_COMPILE_DEFINITIONS - _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR # Microsoft wtf? - _CRT_SECURE_NO_WARNINGS) - -if (NOT CMAKE_SYSTEM_NAME STREQUAL "iOS") - list(APPEND UNLEASHED_RECOMP_COMPILE_DEFINITIONS SDL_MAIN_HANDLED) -else() - list(APPEND UNLEASHED_RECOMP_COMPILE_DEFINITIONS UNLEASHED_RECOMP_IOS) -endif() - -add_compile_definitions(${UNLEASHED_RECOMP_COMPILE_DEFINITIONS}) +set(UNLEASHED_RECOMP_COMPILE_DEFINITIONS + _DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR # Microsoft wtf? + _CRT_SECURE_NO_WARNINGS) + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "iOS") + list(APPEND UNLEASHED_RECOMP_COMPILE_DEFINITIONS SDL_MAIN_HANDLED) +else() + list(APPEND UNLEASHED_RECOMP_COMPILE_DEFINITIONS UNLEASHED_RECOMP_IOS) +endif() + +add_compile_definitions(${UNLEASHED_RECOMP_COMPILE_DEFINITIONS}) set(UNLEASHED_RECOMP_PRECOMPILED_HEADERS "stdafx.h" @@ -118,18 +118,18 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Linux") "os/linux/user_linux.cpp" "os/linux/version_linux.cpp" ) -elseif (CMAKE_SYSTEM_NAME STREQUAL "iOS") - set(UNLEASHED_RECOMP_OS_CXX_SOURCES - "os/ios/logger_ios.cpp" - "os/ios/media_ios.cpp" - "os/ios/process_ios.mm" - "os/ios/user_ios.mm" - "os/ios/version_ios.mm" - ) -elseif (APPLE) - set(UNLEASHED_RECOMP_OS_CXX_SOURCES - "os/macos/logger_macos.cpp" - "os/macos/media_macos.cpp" +elseif (CMAKE_SYSTEM_NAME STREQUAL "iOS") + set(UNLEASHED_RECOMP_OS_CXX_SOURCES + "os/ios/logger_ios.cpp" + "os/ios/media_ios.cpp" + "os/ios/process_ios.mm" + "os/ios/user_ios.mm" + "os/ios/version_ios.mm" + ) +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" @@ -185,10 +185,12 @@ set(UNLEASHED_RECOMP_UI_CXX_SOURCES "ui/fader.cpp" "ui/game_window.cpp" "ui/imgui_utils.cpp" + "ui/input_coords.cpp" "ui/installer_wizard.cpp" "ui/message_window.cpp" "ui/options_menu.cpp" "ui/options_menu_thumbnails.cpp" + "ui/touch_controls.cpp" "ui/tv_static.cpp" ) @@ -321,49 +323,49 @@ if (WIN32) if (${CMAKE_BUILD_TYPE} MATCHES "Release") target_link_options(UnleashedRecomp PRIVATE "/SUBSYSTEM:WINDOWS" "/ENTRY:mainCRTStartup") endif() -elseif (CMAKE_SYSTEM_NAME STREQUAL "iOS") - CreateVersionString( - VERSION_TXT ${VERSION_TXT} - OUTPUT_VAR IOS_BUNDLE_VERSION - ) - string(REGEX REPLACE "^v" "" IOS_BUNDLE_VERSION "${IOS_BUNDLE_VERSION}") - - set(UNLEASHED_RECOMP_IOS_ICON_FILES - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon20x20@2x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon20x20@3x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon29x29@2x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon29x29@3x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon40x40@2x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon40x40@3x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon60x60@2x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon60x60@3x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon76x76.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon76x76@2x.png" - "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon83.5x83.5@2x.png" - ) - - add_executable(UnleashedRecomp MACOSX_BUNDLE - ${UNLEASHED_RECOMP_CXX_SOURCES} - ) - set_target_properties(UnleashedRecomp PROPERTIES - OUTPUT_NAME "Unleashed Recompiled" - MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/res/ios/Info.plist.in - MACOSX_BUNDLE_GUI_IDENTIFIER hedge-dev.UnleashedRecomp - MACOSX_BUNDLE_BUNDLE_NAME "Unleashed Recompiled" - MACOSX_BUNDLE_BUNDLE_VERSION ${IOS_BUNDLE_VERSION} - MACOSX_BUNDLE_SHORT_VERSION_STRING ${IOS_BUNDLE_VERSION} - XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "hedge-dev.UnleashedRecomp" - XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" - XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" - ) - foreach(UNLEASHED_RECOMP_IOS_ICON_FILE IN LISTS UNLEASHED_RECOMP_IOS_ICON_FILES) - add_custom_command(TARGET UnleashedRecomp POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different - "${UNLEASHED_RECOMP_IOS_ICON_FILE}" - "$" - ) - endforeach() -elseif (APPLE) +elseif (CMAKE_SYSTEM_NAME STREQUAL "iOS") + CreateVersionString( + VERSION_TXT ${VERSION_TXT} + OUTPUT_VAR IOS_BUNDLE_VERSION + ) + string(REGEX REPLACE "^v" "" IOS_BUNDLE_VERSION "${IOS_BUNDLE_VERSION}") + + set(UNLEASHED_RECOMP_IOS_ICON_FILES + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon20x20@2x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon20x20@3x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon29x29@2x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon29x29@3x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon40x40@2x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon40x40@3x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon60x60@2x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon60x60@3x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon76x76.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon76x76@2x.png" + "${CMAKE_CURRENT_SOURCE_DIR}/res/ios/icons/AppIcon83.5x83.5@2x.png" + ) + + add_executable(UnleashedRecomp MACOSX_BUNDLE + ${UNLEASHED_RECOMP_CXX_SOURCES} + ) + set_target_properties(UnleashedRecomp PROPERTIES + OUTPUT_NAME "Unleashed Recompiled" + MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/res/ios/Info.plist.in + MACOSX_BUNDLE_GUI_IDENTIFIER hedge-dev.UnleashedRecomp + MACOSX_BUNDLE_BUNDLE_NAME "Unleashed Recompiled" + MACOSX_BUNDLE_BUNDLE_VERSION ${IOS_BUNDLE_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${IOS_BUNDLE_VERSION} + XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER "hedge-dev.UnleashedRecomp" + XCODE_ATTRIBUTE_TARGETED_DEVICE_FAMILY "1,2" + XCODE_ATTRIBUTE_ENABLE_BITCODE "NO" + ) + foreach(UNLEASHED_RECOMP_IOS_ICON_FILE IN LISTS UNLEASHED_RECOMP_IOS_ICON_FILES) + add_custom_command(TARGET UnleashedRecomp POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${UNLEASHED_RECOMP_IOS_ICON_FILE}" + "$" + ) + endforeach() +elseif (APPLE) # Create version number for app bundle. CreateVersionString( VERSION_TXT ${VERSION_TXT} @@ -458,33 +460,36 @@ if (WIN32) ) endif() -set(UNLEASHED_RECOMP_SDL_LIBS SDL2::SDL2-static) -if (CMAKE_SYSTEM_NAME STREQUAL "iOS" AND TARGET SDL2::SDL2main) - list(PREPEND UNLEASHED_RECOMP_SDL_LIBS SDL2::SDL2main) -endif() - -set(UNLEASHED_RECOMP_PLATFORM_LIBS) -if (CMAKE_SYSTEM_NAME STREQUAL "iOS") - list(APPEND UNLEASHED_RECOMP_PLATFORM_LIBS MoltenVK) - target_link_options(UnleashedRecomp PRIVATE "LINKER:-u,_vkGetInstanceProcAddr") -endif() - -target_link_libraries(UnleashedRecomp PRIVATE - fmt::fmt - libzstd_static - msdf-atlas-gen::msdf-atlas-gen +set(UNLEASHED_RECOMP_SDL_LIBS SDL2::SDL2-static) +if (CMAKE_SYSTEM_NAME STREQUAL "iOS" AND TARGET SDL2::SDL2main) + list(PREPEND UNLEASHED_RECOMP_SDL_LIBS SDL2::SDL2main) +endif() + +set(UNLEASHED_RECOMP_PLATFORM_LIBS) +if (CMAKE_SYSTEM_NAME STREQUAL "iOS") + list(APPEND UNLEASHED_RECOMP_PLATFORM_LIBS MoltenVK) + target_link_options(UnleashedRecomp PRIVATE + "LINKER:-u,_vkGetInstanceProcAddr" + "LINKER:-ObjC" + ) +endif() + +target_link_libraries(UnleashedRecomp PRIVATE + fmt::fmt + libzstd_static + msdf-atlas-gen::msdf-atlas-gen nfd::nfd - o1heap - XenonUtils - ${UNLEASHED_RECOMP_SDL_LIBS} - SDL2_mixer + o1heap + XenonUtils + ${UNLEASHED_RECOMP_SDL_LIBS} + SDL2_mixer tomlplusplus::tomlplusplus - UnleashedRecompLib - xxHash::xxhash - CURL::libcurl - plume - ${UNLEASHED_RECOMP_PLATFORM_LIBS} -) + UnleashedRecompLib + xxHash::xxhash + CURL::libcurl + plume + ${UNLEASHED_RECOMP_PLATFORM_LIBS} +) target_include_directories(UnleashedRecomp PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/UnleashedRecomp/gpu/video.cpp b/UnleashedRecomp/gpu/video.cpp index a9edd0b3..36fc1a38 100644 --- a/UnleashedRecomp/gpu/video.cpp +++ b/UnleashedRecomp/gpu/video.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -1645,6 +1647,39 @@ static void ApplyLowEndDefault(ConfigDef &configDef, T newDefault, bool &chan configDef.DefaultValue = newDefault; } +#ifdef UNLEASHED_RECOMP_IOS +template +static void ApplyIOSDefault(ConfigDef& configDef, T desktopDefault, T iosDefault, bool& changed) +{ + const bool shouldApply = !configDef.IsLoadedFromConfig || configDef.Value == desktopDefault; + + if (shouldApply && configDef.Value != iosDefault) + { + configDef = iosDefault; + changed = true; + } + + configDef.DefaultValue = iosDefault; +} + +static void ApplyIOSPerformanceDefaults() +{ + bool changed = false; + + ApplyIOSDefault(Config::ResolutionScale, 1.0f, 0.65f, changed); + ApplyIOSDefault(Config::AntiAliasing, EAntiAliasing::MSAA4x, EAntiAliasing::None, changed); + ApplyIOSDefault(Config::TransparencyAntiAliasing, true, false, changed); + ApplyIOSDefault(Config::AnisotropicFiltering, 16u, 4u, changed); + ApplyIOSDefault(Config::ShadowResolution, EShadowResolution::x4096, EShadowResolution::Original, changed); + ApplyIOSDefault(Config::GITextureFiltering, EGITextureFiltering::Bicubic, EGITextureFiltering::Bilinear, changed); + ApplyIOSDefault(Config::DepthOfFieldQuality, EDepthOfFieldQuality::Auto, EDepthOfFieldQuality::Low, changed); + ApplyIOSDefault(Config::MaxFrameLatency, 2u, 1u, changed); + + if (changed) + Config::Save(); +} +#endif + static void ApplyLowEndDefaults() { bool changed = false; @@ -1820,6 +1855,10 @@ bool Video::CreateHostDevice(const char *sdlVideoDriver, bool graphicsApiRetry) ApplyLowEndDefaults(); } +#ifdef UNLEASHED_RECOMP_IOS + ApplyIOSPerformanceDefaults(); +#endif + const RenderSampleCounts colourSampleCount = g_device->getSampleCountsSupported(RenderFormat::R16G16B16A16_FLOAT); const RenderSampleCounts depthSampleCount = g_device->getSampleCountsSupported(RenderFormat::D32_FLOAT); const RenderSampleCounts commonSampleCount = colourSampleCount & depthSampleCount; @@ -2543,30 +2582,22 @@ static void DrawImGui() auto& io = ImGui::GetIO(); io.DisplaySize = { float(Video::s_viewportWidth), float(Video::s_viewportHeight) }; + Video::s_drawableWidth = g_swapChain->getWidth(); + Video::s_drawableHeight = g_swapChain->getHeight(); + // ImGui doesn't know that we center the screen for specific aspect ratio // settings, which causes mouse events to not work correctly. To fix this, // we can adjust the mouse events before ImGui processes them. - uint32_t width = g_swapChain->getWidth(); - uint32_t height = g_swapChain->getHeight(); - float mousePosScaleX = float(width) / float(GameWindow::s_width); - float mousePosScaleY = float(height) / float(GameWindow::s_height); - float mousePosOffsetX = (width - Video::s_viewportWidth) / 2.0f; - float mousePosOffsetY = (height - Video::s_viewportHeight) / 2.0f; for (int i = 0; i < io.Ctx->InputEventsQueue.Size; i++) { auto& e = io.Ctx->InputEventsQueue[i]; if (e.Type == ImGuiInputEventType_MousePos) { - if (e.MousePos.PosX != -FLT_MAX) + if (e.MousePos.PosX != -FLT_MAX && e.MousePos.PosY != -FLT_MAX) { - e.MousePos.PosX *= mousePosScaleX; - e.MousePos.PosX -= mousePosOffsetX; - } - - if (e.MousePos.PosY != -FLT_MAX) - { - e.MousePos.PosY *= mousePosScaleY; - e.MousePos.PosY -= mousePosOffsetY; + const ImVec2 transformed = TransformWindowPointToViewport(e.MousePos.PosX, e.MousePos.PosY); + e.MousePos.PosX = transformed.x; + e.MousePos.PosY = transformed.y; } } } @@ -2597,6 +2628,7 @@ static void DrawImGui() InstallerWizard::Draw(); MessageWindow::Draw(); ButtonGuide::Draw(); + TouchControls::Draw(); Fader::Draw(); BlackBar::Draw(); diff --git a/UnleashedRecomp/gpu/video.h b/UnleashedRecomp/gpu/video.h index 6c24d301..beb04423 100644 --- a/UnleashedRecomp/gpu/video.h +++ b/UnleashedRecomp/gpu/video.h @@ -24,6 +24,9 @@ struct Video static void StartPipelinePrecompilation(); static void WaitForGPU(); static void ComputeViewportDimensions(); + + static inline uint32_t s_drawableWidth{}; + static inline uint32_t s_drawableHeight{}; }; struct GuestSamplerState diff --git a/UnleashedRecomp/hid/driver/sdl_hid.cpp b/UnleashedRecomp/hid/driver/sdl_hid.cpp index 76235524..bf705adf 100644 --- a/UnleashedRecomp/hid/driver/sdl_hid.cpp +++ b/UnleashedRecomp/hid/driver/sdl_hid.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -339,6 +340,10 @@ void hid::Init() SDL_AddEventWatch(HID_OnSDLEvent, nullptr); SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER); + +#ifdef UNLEASHED_RECOMP_IOS + TouchControls::Init(); +#endif } uint32_t hid::GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState) @@ -352,6 +357,14 @@ uint32_t hid::GetState(uint32_t dwUserIndex, XAMINPUT_STATE* pState) pState->dwPacketNumber = packet++; +#ifdef UNLEASHED_RECOMP_IOS + if (TouchControls::IsActive() && TouchControls::IsEnabled()) + { + pState->Gamepad = TouchControls::GetState(); + return ERROR_SUCCESS; + } +#endif + if (!g_activeController) return ERROR_DEVICE_NOT_CONNECTED; diff --git a/UnleashedRecomp/hid/hid.cpp b/UnleashedRecomp/hid/hid.cpp index 900de327..7842edb5 100644 --- a/UnleashedRecomp/hid/hid.cpp +++ b/UnleashedRecomp/hid/hid.cpp @@ -1,5 +1,7 @@ #include "hid.h" #include +#include +#include #include hid::EInputDevice hid::g_inputDevice; @@ -19,6 +21,9 @@ void hid::SetProhibitedInputs(uint16_t wButtons, bool leftStick, bool rightStick bool hid::IsInputAllowed() { + if (InstallerWizard::s_isVisible || MessageWindow::s_isVisible) + return true; + return GameWindow::s_isFocused || Config::AllowBackgroundInput; } diff --git a/UnleashedRecomp/install/directory_file_system.h b/UnleashedRecomp/install/directory_file_system.h index a246351d..867bf566 100644 --- a/UnleashedRecomp/install/directory_file_system.h +++ b/UnleashedRecomp/install/directory_file_system.h @@ -29,6 +29,19 @@ struct DirectoryFileSystem : VirtualFileSystem } } + bool read(const std::string &path, size_t offset, uint8_t *fileData, size_t size) const override + { + std::ifstream fileStream(directoryPath / std::filesystem::path(std::u8string_view((const char8_t *)(path.c_str()))), std::ios::binary); + if (!fileStream.is_open()) + { + return false; + } + + fileStream.seekg(offset, std::ios::beg); + fileStream.read(reinterpret_cast(fileData), size); + return !fileStream.fail() && static_cast(fileStream.gcount()) == size; + } + size_t getSize(const std::string &path) const override { std::error_code ec; diff --git a/UnleashedRecomp/install/installer.cpp b/UnleashedRecomp/install/installer.cpp index 774a141e..c06ea571 100644 --- a/UnleashedRecomp/install/installer.cpp +++ b/UnleashedRecomp/install/installer.cpp @@ -134,7 +134,7 @@ static bool checkFile(const FilePair &pair, const uint64_t *fileHashes, const st return true; } -static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, bool skipHashChecks, std::vector &fileData, Journal &journal, const std::function &progressCallback) { +static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, const std::function &progressCallback) { const std::string filename(pair.first); const uint32_t hashCount = pair.second; if (!sourceVfs.exists(filename)) @@ -144,30 +144,14 @@ static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFi return false; } - if (!sourceVfs.load(filename, fileData)) + const size_t fileSize = sourceVfs.getSize(filename); + if (fileSize == 0) { journal.lastResult = Journal::Result::FileReadFailed; journal.lastErrorMessage = fmt::format("Failed to read file {} from {}.", filename, sourceVfs.getName()); return false; } - if (!skipHashChecks) - { - uint64_t fileHash = XXH3_64bits(fileData.data(), fileData.size()); - bool fileHashFound = false; - for (uint32_t i = 0; i < hashCount && !fileHashFound; i++) - { - fileHashFound = fileHash == fileHashes[i]; - } - - if (!fileHashFound) - { - journal.lastResult = Journal::Result::FileHashFailed; - journal.lastErrorMessage = fmt::format("File {} from {} did not match any of the known hashes.", filename, sourceVfs.getName()); - return false; - } - } - std::filesystem::path targetPath = targetDirectory / std::filesystem::path(std::u8string_view((const char8_t *)(pair.first))); std::filesystem::path parentPath = targetPath.parent_path(); if (!std::filesystem::exists(parentPath)) @@ -197,15 +181,59 @@ static bool copyFile(const FilePair &pair, const uint64_t *fileHashes, VirtualFi journal.createdFiles.push_back(targetPath); - outStream.write((const char *)(fileData.data()), fileData.size()); - if (outStream.bad()) + static constexpr size_t CopyChunkSize = 4 * 1024 * 1024; + std::vector chunk(std::min(fileSize, CopyChunkSize)); + XXH3_state_t hashState; + if (!skipHashChecks) { - journal.lastResult = Journal::Result::FileWriteFailed; - journal.lastErrorMessage = fmt::format("Failed to create file at {}.", fromPath(targetPath)); - return false; + XXH3_64bits_reset(&hashState); } - journal.progressCounter += fileData.size(); + size_t offset = 0; + while (offset < fileSize) + { + const size_t bytesToRead = std::min(CopyChunkSize, fileSize - offset); + if (!sourceVfs.read(filename, offset, chunk.data(), bytesToRead)) + { + journal.lastResult = Journal::Result::FileReadFailed; + journal.lastErrorMessage = fmt::format("Failed to read file {} from {}.", filename, sourceVfs.getName()); + return false; + } + + if (!skipHashChecks) + { + XXH3_64bits_update(&hashState, chunk.data(), bytesToRead); + } + + outStream.write(reinterpret_cast(chunk.data()), bytesToRead); + if (outStream.bad()) + { + journal.lastResult = Journal::Result::FileWriteFailed; + journal.lastErrorMessage = fmt::format("Failed to create file at {}.", fromPath(targetPath)); + return false; + } + + offset += bytesToRead; + } + + if (!skipHashChecks) + { + const uint64_t fileHash = XXH3_64bits_digest(&hashState); + bool fileHashFound = false; + for (uint32_t i = 0; i < hashCount && !fileHashFound; i++) + { + fileHashFound = fileHash == fileHashes[i]; + } + + if (!fileHashFound) + { + journal.lastResult = Journal::Result::FileHashFailed; + journal.lastErrorMessage = fmt::format("File {} from {} did not match any of the known hashes.", filename, sourceVfs.getName()); + return false; + } + } + + journal.progressCounter += fileSize; if (!progressCallback()) { @@ -447,7 +475,6 @@ bool Installer::copyFiles(std::span filePairs, const uint64_t *f uint32_t validationHashIndex = 0; uint32_t hashIndex = 0; uint32_t hashCount = 0; - std::vector fileData; for (FilePair pair : filePairs) { hashIndex = hashCount; @@ -460,7 +487,7 @@ bool Installer::copyFiles(std::span filePairs, const uint64_t *f continue; } - if (!copyFile(pair, &fileHashes[hashIndex], sourceVfs, targetDirectory, skipHashChecks, fileData, journal, progressCallback)) + if (!copyFile(pair, &fileHashes[hashIndex], sourceVfs, targetDirectory, skipHashChecks, journal, progressCallback)) { return false; } @@ -469,7 +496,7 @@ bool Installer::copyFiles(std::span filePairs, const uint64_t *f // Validation file is copied last after all other files have been copied. if (validationPair.first != nullptr) { - if (!copyFile(validationPair, &fileHashes[validationHashIndex], sourceVfs, targetDirectory, skipHashChecks, fileData, journal, progressCallback)) + if (!copyFile(validationPair, &fileHashes[validationHashIndex], sourceVfs, targetDirectory, skipHashChecks, journal, progressCallback)) { return false; } @@ -565,7 +592,7 @@ bool Installer::parseSources(const Input &input, Journal &journal, Sources &sour return true; } -bool Installer::install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function &progressCallback) +bool Installer::install(Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function &progressCallback) { // Install files in reverse order of importance. In case of a process crash or power outage, this will increase the likelihood of the installation // missing critical files required for the game to run. These files are used as the way to detect if the game is installed. @@ -576,14 +603,18 @@ bool Installer::install(const Sources &sources, const std::filesystem::path &tar journal.createdDirectories.insert(targetDirectory / DLCDirectory); } - for (const DLCSource &dlcSource : sources.dlc) + for (DLCSource &dlcSource : sources.dlc) { if (!copyFiles(dlcSource.filePairs, dlcSource.fileHashes, *dlcSource.sourceVfs, targetDirectory / dlcSource.targetSubDirectory, DLCValidationFile, skipHashChecks, journal, progressCallback)) { return false; } + + dlcSource.sourceVfs.reset(); } + sources.dlc.clear(); + // If no game or update was specified, we're finished. This means the user was only installing the DLC. if ((sources.game == nullptr) && (sources.update == nullptr)) { @@ -596,12 +627,16 @@ bool Installer::install(const Sources &sources, const std::filesystem::path &tar return false; } + sources.update.reset(); + // Install the base game. if (!copyFiles({ GameFiles, GameFilesSize }, GameHashes, *sources.game, targetDirectory / GameDirectory, GameExecutableFile, skipHashChecks, journal, progressCallback)) { return false; } + sources.game.reset(); + // Create the directory where the patched executable will be stored. std::error_code ec; std::filesystem::path patchedDirectory = targetDirectory / PatchedDirectory; diff --git a/UnleashedRecomp/install/installer.h b/UnleashedRecomp/install/installer.h index 8bc04777..b39c583f 100644 --- a/UnleashedRecomp/install/installer.h +++ b/UnleashedRecomp/install/installer.h @@ -81,7 +81,7 @@ struct Installer static bool copyFiles(std::span filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function &progressCallback); static bool parseContent(const std::filesystem::path &sourcePath, std::unique_ptr &targetVfs, Journal &journal); static bool parseSources(const Input &input, Journal &journal, Sources &sources); - static bool install(const Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function &progressCallback); + static bool install(Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function &progressCallback); static void rollback(Journal &journal); // Convenience method for checking if the specified file contains the game. This should be used when the user selects the file. diff --git a/UnleashedRecomp/install/iso_file_system.cpp b/UnleashedRecomp/install/iso_file_system.cpp index b0a89ef6..b75b5c03 100644 --- a/UnleashedRecomp/install/iso_file_system.cpp +++ b/UnleashedRecomp/install/iso_file_system.cpp @@ -23,22 +23,31 @@ ISOFileSystem::ISOFileSystem(const std::filesystem::path &isoPath) name = (const char *)(isoPath.filename().u8string().data()); + auto readBytes = [this](size_t offset, void *dest, size_t size) -> bool + { + return mappedFile.readAt(offset, dest, size); + }; + // Find root sector. - const uint8_t *mappedFileData = mappedFile.data(); uint32_t gameOffset = 0; const size_t XeSectorSize = 2048; static const size_t PossibleOffsets[] = { 0x00000000, 0x0000FB20, 0x00020600, 0x02080000, 0x0FD90000, }; bool magicFound = false; - const char RefMagic[] = "MICROSOFT*XBOX*MEDIA"; + static constexpr char RefMagic[] = "MICROSOFT*XBOX*MEDIA"; + static constexpr size_t RefMagicSize = sizeof(RefMagic) - 1; for (size_t i = 0; i < std::size(PossibleOffsets); i++) { size_t fileOffset = PossibleOffsets[i] + (32 * XeSectorSize); - if ((fileOffset + strlen(RefMagic)) > mappedFile.size()) + if ((fileOffset + RefMagicSize) > mappedFile.size()) { continue; } - if (std::memcmp(&mappedFileData[fileOffset], RefMagic, strlen(RefMagic)) == 0) + char magic[RefMagicSize]; + if (!readBytes(fileOffset, magic, sizeof(magic))) + continue; + + if (std::memcmp(magic, RefMagic, RefMagicSize) == 0) { gameOffset = PossibleOffsets[i]; magicFound = true; @@ -53,8 +62,15 @@ ISOFileSystem::ISOFileSystem(const std::filesystem::path &isoPath) } // Parse root information. - uint32_t rootSector = *(uint32_t *)(&mappedFileData[rootInfoOffset + 0]); - uint32_t rootSize = *(uint32_t *)(&mappedFileData[rootInfoOffset + 4]); + uint32_t rootSector = 0; + uint32_t rootSize = 0; + if (!readBytes(rootInfoOffset + 0, &rootSector, sizeof(rootSector)) || + !readBytes(rootInfoOffset + 4, &rootSize, sizeof(rootSize))) + { + mappedFile.close(); + return; + } + size_t rootOffset = gameOffset + (rootSector * XeSectorSize); const uint32_t MinRootSize = 13; const uint32_t MaxRootSize = 32 * 1024 * 1024; @@ -95,12 +111,16 @@ ISOFileSystem::ISOFileSystem(const std::filesystem::path &isoPath) return; } - nodeL = *(uint16_t *)(&mappedFileData[infoOffset + 0]); - nodeR = *(uint16_t *)(&mappedFileData[infoOffset + 2]); - sector = *(uint32_t *)(&mappedFileData[infoOffset + 4]); - length = *(uint32_t *)(&mappedFileData[infoOffset + 8]); - attributes = *(uint8_t *)(&mappedFileData[infoOffset + 12]); - nameLength = *(uint8_t *)(&mappedFileData[infoOffset + 13]); + if (!readBytes(infoOffset + 0, &nodeL, sizeof(nodeL)) || + !readBytes(infoOffset + 2, &nodeR, sizeof(nodeR)) || + !readBytes(infoOffset + 4, §or, sizeof(sector)) || + !readBytes(infoOffset + 8, &length, sizeof(length)) || + !readBytes(infoOffset + 12, &attributes, sizeof(attributes)) || + !readBytes(infoOffset + 13, &nameLength, sizeof(nameLength))) + { + mappedFile.close(); + return; + } size_t nameOffset = infoOffset + 14; if ((nameOffset + nameLength) > mappedFile.size()) @@ -109,7 +129,12 @@ ISOFileSystem::ISOFileSystem(const std::filesystem::path &isoPath) return; } - memcpy(fileName, &mappedFileData[nameOffset], nameLength); + if (!readBytes(nameOffset, fileName, nameLength)) + { + mappedFile.close(); + return; + } + fileName[nameLength] = '\0'; if (nodeL) @@ -147,9 +172,7 @@ bool ISOFileSystem::load(const std::string &path, uint8_t *fileData, size_t file return false; } - const uint8_t *mappedFileData = mappedFile.data(); - memcpy(fileData, &mappedFileData[std::get<0>(it->second)], std::get<1>(it->second)); - return true; + return mappedFile.readAt(std::get<0>(it->second), fileData, std::get<1>(it->second)); } else { @@ -157,6 +180,24 @@ bool ISOFileSystem::load(const std::string &path, uint8_t *fileData, size_t file } } +bool ISOFileSystem::read(const std::string &path, size_t offset, uint8_t *fileData, size_t size) const +{ + auto it = fileMap.find(path); + if (it == fileMap.end()) + { + return false; + } + + size_t fileOffset = std::get<0>(it->second); + size_t fileSize = std::get<1>(it->second); + if (offset + size > fileSize) + { + return false; + } + + return mappedFile.readAt(fileOffset + offset, fileData, size); +} + size_t ISOFileSystem::getSize(const std::string &path) const { auto it = fileMap.find(path); diff --git a/UnleashedRecomp/install/iso_file_system.h b/UnleashedRecomp/install/iso_file_system.h index dceca077..424f7c61 100644 --- a/UnleashedRecomp/install/iso_file_system.h +++ b/UnleashedRecomp/install/iso_file_system.h @@ -26,6 +26,7 @@ struct ISOFileSystem : VirtualFileSystem ISOFileSystem(const std::filesystem::path &isoPath); bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const override; + bool read(const std::string &path, size_t offset, uint8_t *fileData, size_t size) const override; size_t getSize(const std::string &path) const override; bool exists(const std::string &path) const override; const std::string &getName() const override; diff --git a/UnleashedRecomp/install/virtual_file_system.h b/UnleashedRecomp/install/virtual_file_system.h index 079f16ee..da700c36 100644 --- a/UnleashedRecomp/install/virtual_file_system.h +++ b/UnleashedRecomp/install/virtual_file_system.h @@ -6,6 +6,7 @@ struct VirtualFileSystem { virtual ~VirtualFileSystem() { }; virtual bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const = 0; + virtual bool read(const std::string &path, size_t offset, uint8_t *fileData, size_t size) const = 0; virtual size_t getSize(const std::string &path) const = 0; virtual bool exists(const std::string &path) const = 0; virtual const std::string &getName() const = 0; diff --git a/UnleashedRecomp/install/xcontent_file_system.cpp b/UnleashedRecomp/install/xcontent_file_system.cpp index 911d6962..a4777ec9 100644 --- a/UnleashedRecomp/install/xcontent_file_system.cpp +++ b/UnleashedRecomp/install/xcontent_file_system.cpp @@ -13,6 +13,7 @@ #include "xcontent_file_system.h" #include +#include #include #include #include @@ -216,11 +217,12 @@ size_t blockIndexToHashBlockOffset(uint64_t baseOffset, uint32_t blockIndex) return baseOffset + (blockNumber << 12); } -const StfsHashEntry *hashEntryFromBlockIndex(const uint8_t *fileData, uint64_t baseOffset, uint64_t blockIndex) +static bool readHashEntry(const MemoryMappedFile &file, uint64_t baseOffset, uint64_t blockIndex, StfsHashEntry &outEntry) { size_t hashOffset = blockIndexToHashBlockOffset(baseOffset, blockIndex); - const StfsHashTable *hashTable = (const StfsHashTable *)(&fileData[hashOffset]); - return &hashTable->entries[blockIndex % StfsBlocksPerHashLevel[0]]; + size_t entryIndex = blockIndex % StfsBlocksPerHashLevel[0]; + size_t entryOffset = hashOffset + offsetof(StfsHashTable, entries) + entryIndex * sizeof(StfsHashEntry); + return file.readAt(entryOffset, &outEntry, sizeof(outEntry)); } void blockToOffsetAndFile(SvodLayoutType svodLayoutType, size_t svodStartDataBlock, size_t svodBaseOffset, size_t block, size_t &outOffset, size_t &outFileIndex) @@ -273,14 +275,20 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) name = (const char *)(contentPath.filename().u8string().data()); - const uint8_t *rootMappedFileData = rootMappedFile.data(); if (sizeof(XContentContainerHeader) > rootMappedFile.size()) { mappedFiles.clear(); return; } - XContentContainerHeader contentContainerHeader = *(const XContentContainerHeader *)(rootMappedFileData); + alignas(XContentContainerHeader) uint8_t headerBuffer[sizeof(XContentContainerHeader)]; + if (!rootMappedFile.readAt(0, headerBuffer, sizeof(headerBuffer))) + { + mappedFiles.clear(); + return; + } + + const XContentContainerHeader &contentContainerHeader = *reinterpret_cast(headerBuffer); XContentPackageType packageType = XContentPackageType(contentContainerHeader.contentHeader.magic.get()); if (packageType != XContentPackageType::CON && packageType != XContentPackageType::LIVE && packageType != XContentPackageType::PIRS) { @@ -314,10 +322,16 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) return; } - StfsDirectoryBlock *directoryBlock = (StfsDirectoryBlock *)(&rootMappedFileData[offset]); + StfsDirectoryBlock directoryBlock; + if (!rootMappedFile.readAt(offset, &directoryBlock, sizeof(directoryBlock))) + { + mappedFiles.clear(); + return; + } + for (uint32_t j = 0; j < StfsEntriesPerDirectoryBlock; j++) { - const StfsDirectoryEntry &directoryEntry = directoryBlock->entries[j]; + const StfsDirectoryEntry &directoryEntry = directoryBlock.entries[j]; if (directoryEntry.name[0] == '\0') { break; @@ -337,8 +351,14 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) entryCount++; } - const StfsHashEntry *hashEntry = hashEntryFromBlockIndex(rootMappedFileData, baseOffset, tableBlockIndex); - tableBlockIndex = hashEntry->infoRaw & 0xFFFFFF; + StfsHashEntry hashEntry; + if (!readHashEntry(rootMappedFile, baseOffset, tableBlockIndex, hashEntry)) + { + mappedFiles.clear(); + return; + } + + tableBlockIndex = hashEntry.infoRaw.get() & 0xFFFFFF; if (tableBlockIndex == StfsEndOfChain) { break; @@ -386,14 +406,26 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) // Determine the layout of the SVOD from the first file. MemoryMappedFile &firstMappedFile = mappedFiles.front(); - const uint8_t *firstMappedFileData = firstMappedFile.data(); const char *RefMagic = "MICROSOFT*XBOX*MEDIA"; + static constexpr size_t RefMagicSize = 20; size_t RefXSFMagicOffset = 0x12000; size_t SingleFileMagicOffset = 0xD000; + + auto readMagicAt = [&](size_t offset) -> bool + { + if (offset + RefMagicSize > firstMappedFile.size()) + { + return false; + } + + char magic[RefMagicSize]; + return firstMappedFile.readAt(offset, magic, sizeof(magic)) && std::memcmp(magic, RefMagic, RefMagicSize) == 0; + }; + if (metadata.svodDeviceDescriptor.features.bits.enhancedGdfLayout) { size_t EGDFMagicOffset = 0x2000; - if (EGDFMagicOffset >= firstMappedFile.size() || std::memcmp(&firstMappedFileData[EGDFMagicOffset], RefMagic, strlen(RefMagic)) != 0) + if (!readMagicAt(EGDFMagicOffset)) { mappedFiles.clear(); return; @@ -403,14 +435,15 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) svodMagicOffset = EGDFMagicOffset; svodLayoutType = SvodLayoutType::EnhancedGDF; } - else if (RefXSFMagicOffset < firstMappedFile.size() && std::memcmp(&firstMappedFileData[RefXSFMagicOffset], RefMagic, strlen(RefMagic)) == 0) + else if (readMagicAt(RefXSFMagicOffset)) { const char *XSFMagic = "XSF"; size_t XSFMagicOffset = 0x2000; svodBaseOffset = 0x10000; svodMagicOffset = 0x12000; - if (std::memcmp(&firstMappedFileData[XSFMagicOffset], XSFMagic, strlen(XSFMagic)) == 0) + char xsfMagic[4]; + if (firstMappedFile.readAt(XSFMagicOffset, xsfMagic, 3) && std::memcmp(xsfMagic, XSFMagic, 3) == 0) { svodLayoutType = SvodLayoutType::XSF; } @@ -419,7 +452,7 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) svodLayoutType = SvodLayoutType::Unknown; } } - else if (SingleFileMagicOffset < firstMappedFile.size() && std::memcmp(&firstMappedFileData[SingleFileMagicOffset], RefMagic, strlen(RefMagic)) == 0) + else if (readMagicAt(SingleFileMagicOffset)) { svodBaseOffset = 0xB000; svodMagicOffset = 0xD000; @@ -443,7 +476,12 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) }; std::stack iterationStack; - uint32_t rootBlock = *(uint32_t *)(&firstMappedFileData[svodMagicOffset + 0x14]); + uint32_t rootBlock = 0; + if (!firstMappedFile.readAt(svodMagicOffset + 0x14, &rootBlock, sizeof(rootBlock))) + { + mappedFiles.clear(); + return; + } iterationStack.emplace("", rootBlock, 0); IterationStep step; @@ -473,39 +511,48 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) return; } - const uint8_t *mappedFileData = mappedFile.data(); - const SvodDirectoryEntry *directoryEntry = (const SvodDirectoryEntry *)(&mappedFileData[fileOffset]); - size_t nameOffset = fileOffset + sizeof(SvodDirectoryEntry); - if ((nameOffset + directoryEntry->nameLength) > mappedFile.size()) + SvodDirectoryEntry directoryEntry; + if (!mappedFile.readAt(fileOffset, &directoryEntry, sizeof(directoryEntry))) { mappedFiles.clear(); return; } - memcpy(fileName, &mappedFileData[nameOffset], directoryEntry->nameLength); - fileName[directoryEntry->nameLength] = '\0'; - - if (directoryEntry->nodeL) + size_t nameOffset = fileOffset + sizeof(SvodDirectoryEntry); + if ((nameOffset + directoryEntry.nameLength) > mappedFile.size()) { - iterationStack.emplace(step.fileNameBase, step.blockIndex, directoryEntry->nodeL); + mappedFiles.clear(); + return; } - if (directoryEntry->nodeR) + if (!mappedFile.readAt(nameOffset, fileName, directoryEntry.nameLength)) { - iterationStack.emplace(step.fileNameBase, step.blockIndex, directoryEntry->nodeR); + mappedFiles.clear(); + return; + } + fileName[directoryEntry.nameLength] = '\0'; + + if (directoryEntry.nodeL) + { + iterationStack.emplace(step.fileNameBase, step.blockIndex, directoryEntry.nodeL); + } + + if (directoryEntry.nodeR) + { + iterationStack.emplace(step.fileNameBase, step.blockIndex, directoryEntry.nodeR); } std::string fileNameUTF8 = step.fileNameBase + fileName; - if (directoryEntry->attributes & FileAttributeDirectory) + if (directoryEntry.attributes & FileAttributeDirectory) { - if (directoryEntry->length > 0) + if (directoryEntry.length > 0) { - iterationStack.emplace(fileNameUTF8 + "/", directoryEntry->dataBlock, 0); + iterationStack.emplace(fileNameUTF8 + "/", directoryEntry.dataBlock, 0); } } else { - fileMap[fileNameUTF8] = { directoryEntry->length, directoryEntry->dataBlock, 0 }; + fileMap[fileNameUTF8] = { directoryEntry.length, directoryEntry.dataBlock, 0 }; } } } @@ -515,6 +562,121 @@ XContentFileSystem::XContentFileSystem(const std::filesystem::path &contentPath) } } +static bool readStfsFileRange(const MemoryMappedFile &rootMappedFile, uint64_t baseOffset, const XContentFileSystem::File &file, size_t offset, uint8_t *fileData, size_t size) +{ + size_t logicalOffset = 0; + uint32_t fileBlockIndex = file.blockIndex; + while (logicalOffset + StfsBlockSize <= offset && fileBlockIndex != StfsEndOfChain) + { + logicalOffset += StfsBlockSize; + StfsHashEntry hashEntry; + if (!readHashEntry(rootMappedFile, baseOffset, fileBlockIndex, hashEntry)) + { + return false; + } + + fileBlockIndex = hashEntry.infoRaw.get() & 0xFFFFFF; + } + + size_t skipInBlock = offset - logicalOffset; + size_t remainingSize = size; + size_t fileDataOffset = 0; + while (remainingSize > 0 && fileBlockIndex != StfsEndOfChain) + { + size_t blockSize = std::min(StfsBlockSize - skipInBlock, remainingSize); + size_t blockOffset = blockIndexToOffset(baseOffset, fileBlockIndex) + skipInBlock; + if (blockOffset + blockSize > rootMappedFile.size()) + { + return false; + } + + if (!rootMappedFile.readAt(blockOffset, &fileData[fileDataOffset], blockSize)) + { + return false; + } + + skipInBlock = 0; + fileDataOffset += blockSize; + remainingSize -= blockSize; + if (remainingSize > 0) + { + StfsHashEntry hashEntry; + if (!readHashEntry(rootMappedFile, baseOffset, fileBlockIndex, hashEntry)) + { + return false; + } + + fileBlockIndex = hashEntry.infoRaw.get() & 0xFFFFFF; + } + } + + return remainingSize == 0; +} + +static bool readSvodFileRange(const std::vector &mappedFiles, SvodLayoutType svodLayoutType, size_t svodStartDataBlock, size_t svodBaseOffset, const XContentFileSystem::File &file, size_t offset, uint8_t *fileData, size_t size) +{ + static constexpr size_t SvodBlockSize = 0x800; + size_t logicalOffset = 0; + size_t currentBlock = file.blockIndex; + while (logicalOffset + SvodBlockSize <= offset) + { + logicalOffset += SvodBlockSize; + currentBlock++; + } + + size_t skipInBlock = offset - logicalOffset; + size_t remainingSize = size; + size_t fileDataOffset = 0; + while (remainingSize > 0) + { + size_t blockFileOffset, blockFileIndex; + blockToOffsetAndFile(svodLayoutType, svodStartDataBlock, svodBaseOffset, currentBlock, blockFileOffset, blockFileIndex); + if (blockFileIndex >= mappedFiles.size()) + { + return false; + } + + const MemoryMappedFile &mappedFile = mappedFiles[blockFileIndex]; + size_t blockSize = std::min(SvodBlockSize - skipInBlock, remainingSize); + if (blockFileOffset + skipInBlock + blockSize > mappedFile.size()) + { + return false; + } + + if (!mappedFile.readAt(blockFileOffset + skipInBlock, &fileData[fileDataOffset], blockSize)) + { + return false; + } + + skipInBlock = 0; + fileDataOffset += blockSize; + remainingSize -= blockSize; + currentBlock++; + } + + return true; +} + +bool XContentFileSystem::read(const std::string &path, size_t offset, uint8_t *fileData, size_t size) const +{ + auto it = fileMap.find(path); + if (it == fileMap.end() || offset + size > it->second.size) + { + return false; + } + + if (volumeType == XContentVolumeType::STFS) + { + return readStfsFileRange(mappedFiles.back(), baseOffset, it->second, offset, fileData, size); + } + else if (volumeType == XContentVolumeType::SVOD) + { + return readSvodFileRange(mappedFiles, svodLayoutType, svodStartDataBlock, svodBaseOffset, it->second, offset, fileData, size); + } + + return false; +} + bool XContentFileSystem::load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const { auto it = fileMap.find(path); @@ -528,7 +690,6 @@ bool XContentFileSystem::load(const std::string &path, uint8_t *fileData, size_t if (volumeType == XContentVolumeType::STFS) { const MemoryMappedFile &rootMappedFile = mappedFiles.back(); - const uint8_t *rootMappedFileData = rootMappedFile.data(); size_t fileDataOffset = 0; size_t remainingSize = it->second.size; uint32_t fileBlockIndex = it->second.blockIndex; @@ -541,10 +702,18 @@ bool XContentFileSystem::load(const std::string &path, uint8_t *fileData, size_t return false; } - memcpy(&fileData[fileDataOffset], &rootMappedFileData[blockOffset], blockSize); + if (!rootMappedFile.readAt(blockOffset, &fileData[fileDataOffset], blockSize)) + { + return false; + } - const StfsHashEntry *hashEntry = hashEntryFromBlockIndex(rootMappedFileData, baseOffset, fileBlockIndex); - fileBlockIndex = hashEntry->infoRaw & 0xFFFFFF; + StfsHashEntry hashEntry; + if (!readHashEntry(rootMappedFile, baseOffset, fileBlockIndex, hashEntry)) + { + return false; + } + + fileBlockIndex = hashEntry.infoRaw.get() & 0xFFFFFF; fileDataOffset += blockSize; remainingSize -= blockSize; } @@ -566,14 +735,16 @@ bool XContentFileSystem::load(const std::string &path, uint8_t *fileData, size_t } const MemoryMappedFile &mappedFile = mappedFiles[blockFileIndex]; - const uint8_t *mappedFileData = mappedFile.data(); size_t blockSize = std::min(size_t(0x800), remainingSize); if (blockFileOffset + blockSize > mappedFile.size()) { return false; } - memcpy(&fileData[fileDataOffset], &mappedFileData[blockFileOffset], blockSize); + if (!mappedFile.readAt(blockFileOffset, &fileData[fileDataOffset], blockSize)) + { + return false; + } fileDataOffset += blockSize; remainingSize -= blockSize; diff --git a/UnleashedRecomp/install/xcontent_file_system.h b/UnleashedRecomp/install/xcontent_file_system.h index c776975f..d383400f 100644 --- a/UnleashedRecomp/install/xcontent_file_system.h +++ b/UnleashedRecomp/install/xcontent_file_system.h @@ -53,6 +53,7 @@ struct XContentFileSystem : VirtualFileSystem XContentFileSystem(const std::filesystem::path &contentPath); bool load(const std::string &path, uint8_t *fileData, size_t fileDataMaxByteCount) const override; + bool read(const std::string &path, size_t offset, uint8_t *fileData, size_t size) const override; size_t getSize(const std::string &path) const override; bool exists(const std::string &path) const override; const std::string &getName() const override; diff --git a/UnleashedRecomp/kernel/memory.cpp b/UnleashedRecomp/kernel/memory.cpp index a52b7e7a..91f84c63 100644 --- a/UnleashedRecomp/kernel/memory.cpp +++ b/UnleashedRecomp/kernel/memory.cpp @@ -17,11 +17,14 @@ Memory::Memory() #else base = (uint8_t*)mmap((void*)0x100000000ull, PPC_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (base == (uint8_t*)MAP_FAILED) + if (base == MAP_FAILED) base = (uint8_t*)mmap(NULL, PPC_MEMORY_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (base == nullptr) + if (base == MAP_FAILED) + { + base = nullptr; return; + } mprotect(base, 4096, PROT_NONE); #endif diff --git a/UnleashedRecomp/main.cpp b/UnleashedRecomp/main.cpp index bb241760..ad2526e8 100644 --- a/UnleashedRecomp/main.cpp +++ b/UnleashedRecomp/main.cpp @@ -200,6 +200,8 @@ int main(int argc, char *argv[]) os::process::CheckConsole(); + InitPaths(); + if (!os::registry::Init()) LOGN_WARNING("OS does not support registry."); diff --git a/UnleashedRecomp/ui/game_window.cpp b/UnleashedRecomp/ui/game_window.cpp index d15aac63..f8745517 100644 --- a/UnleashedRecomp/ui/game_window.cpp +++ b/UnleashedRecomp/ui/game_window.cpp @@ -161,6 +161,11 @@ void GameWindow::Init(const char* sdlVideoDriver) SDL_SetHint("SDL_APP_ID", "io.github.hedge_dev.unleashedrecomp"); #endif +#ifdef UNLEASHED_RECOMP_IOS + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "1"); + SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); +#endif + if (SDL_VideoInit(sdlVideoDriver) != 0 && sdlVideoDriver) { LOGFN_ERROR("Failed to initialise the SDL video driver: \"{}\". Falling back to default.", sdlVideoDriver); @@ -192,6 +197,10 @@ void GameWindow::Init(const char* sdlVideoDriver) s_pWindow = SDL_CreateWindow("Unleashed Recompiled", s_x, s_y, s_width, s_height, GetWindowFlags()); +#ifdef UNLEASHED_RECOMP_IOS + SDL_GetWindowSize(s_pWindow, &s_width, &s_height); +#endif + if (IsFullscreen()) SDL_ShowCursor(SDL_DISABLE); @@ -227,6 +236,10 @@ void GameWindow::Init(const char* sdlVideoDriver) SetTitleBarColour(); SDL_ShowWindow(s_pWindow); + +#ifdef UNLEASHED_RECOMP_IOS + s_isFocused = true; +#endif } void GameWindow::Update() diff --git a/UnleashedRecomp/ui/input_coords.cpp b/UnleashedRecomp/ui/input_coords.cpp new file mode 100644 index 00000000..e91952ab --- /dev/null +++ b/UnleashedRecomp/ui/input_coords.cpp @@ -0,0 +1,61 @@ +#include "input_coords.h" + +#include +#include + +static ImVec2 GetCurrentWindowSize() +{ + int width = GameWindow::s_width; + int height = GameWindow::s_height; + + if (GameWindow::s_pWindow) + SDL_GetWindowSize(GameWindow::s_pWindow, &width, &height); + + return { float(width), float(height) }; +} + +ImVec2 TransformWindowPointToViewport(float x, float y) +{ + const ImVec2 windowSize = GetCurrentWindowSize(); + + if (windowSize.x <= 0.0f || windowSize.y <= 0.0f || Video::s_drawableWidth == 0 || Video::s_drawableHeight == 0) + return { x, y }; + + const float scaleX = float(Video::s_drawableWidth) / windowSize.x; + const float scaleY = float(Video::s_drawableHeight) / windowSize.y; + const float offsetX = (Video::s_drawableWidth - Video::s_viewportWidth) / 2.0f; + const float offsetY = (Video::s_drawableHeight - Video::s_viewportHeight) / 2.0f; + + return { x * scaleX - offsetX, y * scaleY - offsetY }; +} + +ImVec2 GetViewportPointFromSDLEvent(const SDL_Event* event) +{ + switch (event->type) + { + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + return TransformWindowPointToViewport(float(event->button.x), float(event->button.y)); + + case SDL_MOUSEMOTION: + return TransformWindowPointToViewport(float(event->motion.x), float(event->motion.y)); + + case SDL_FINGERDOWN: + case SDL_FINGERUP: + case SDL_FINGERMOTION: + { + const ImVec2 windowSize = GetCurrentWindowSize(); + return TransformWindowPointToViewport( + event->tfinger.x * windowSize.x, + event->tfinger.y * windowSize.y); + } + + default: + return {}; + } +} + +bool IsPointInRect(const ImVec2& point, const ImVec2& min, const ImVec2& max) +{ + return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y; +} diff --git a/UnleashedRecomp/ui/input_coords.h b/UnleashedRecomp/ui/input_coords.h new file mode 100644 index 00000000..b5c0b7e6 --- /dev/null +++ b/UnleashedRecomp/ui/input_coords.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#include + +ImVec2 TransformWindowPointToViewport(float x, float y); +ImVec2 GetViewportPointFromSDLEvent(const SDL_Event* event); +bool IsPointInRect(const ImVec2& point, const ImVec2& min, const ImVec2& max); diff --git a/UnleashedRecomp/ui/installer_wizard.cpp b/UnleashedRecomp/ui/installer_wizard.cpp index 03a93272..722120e0 100644 --- a/UnleashedRecomp/ui/installer_wizard.cpp +++ b/UnleashedRecomp/ui/installer_wizard.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -124,6 +125,14 @@ static std::atomic g_installerHalted = false; static std::atomic g_installerCancelled = false; static bool g_installerFailed = false; static std::string g_installerErrorMessage; +static std::atomic g_parseSourcesActive = false; +static std::atomic g_parseSourcesFinished = false; +static std::atomic g_parseSourcesSuccess = false; +static std::string g_parseSourcesErrorMessage; +static std::unique_ptr g_parseSourcesThread; +static bool g_parseSourcesDlcIncomplete = false; +static bool g_parseSourcesDlcInstallerMode = false; +static bool g_parseSourcesSkipButton = false; enum class WizardPage { @@ -268,18 +277,27 @@ public: } case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: case SDL_MOUSEMOTION: + case SDL_FINGERDOWN: + case SDL_FINGERUP: + case SDL_FINGERMOTION: { + const ImVec2 uiPos = GetViewportPointFromSDLEvent(event); + for (size_t i = 0; i < g_currentCursorRects.size(); i++) { auto ¤tRect = g_currentCursorRects[i]; - if (ImGui::IsMouseHoveringRect(currentRect.first, currentRect.second, false)) + if (IsPointInRect(uiPos, currentRect.first, currentRect.second)) { newCursorIndex = int(i); - if (event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT) + if ((event->type == SDL_MOUSEBUTTONDOWN && event->button.button == SDL_BUTTON_LEFT) || + event->type == SDL_FINGERDOWN) + { g_currentCursorAccepted = true; + } break; } @@ -1367,6 +1385,90 @@ static void InstallerStart() g_installerThread = std::make_unique(InstallerThread); } +static bool InstallerParseSources(std::string &errorMessage); + +static void StartParseSources(bool dlcIncomplete, bool dlcInstallerMode, bool skipButton) +{ + g_parseSourcesDlcIncomplete = dlcIncomplete; + g_parseSourcesDlcInstallerMode = dlcInstallerMode; + g_parseSourcesSkipButton = skipButton; + g_parseSourcesActive = true; + g_parseSourcesFinished = false; + g_parseSourcesSuccess = false; + g_parseSourcesErrorMessage.clear(); + + g_parseSourcesThread = std::make_unique([]() + { + std::string errorMessage; + bool success = InstallerParseSources(errorMessage); + g_parseSourcesErrorMessage = std::move(errorMessage); + g_parseSourcesSuccess = success; + g_parseSourcesFinished = true; + }); +} + +static void ProcessParseSourcesResult() +{ + if (!g_parseSourcesActive || !g_parseSourcesFinished) + { + return; + } + + g_parseSourcesThread->join(); + g_parseSourcesThread.reset(); + g_parseSourcesActive = false; + g_parseSourcesFinished = false; + + if (!g_parseSourcesSuccess) + { + std::stringstream stringStream; + stringStream << Localise("Installer_Message_InvalidFiles"); + if (!g_parseSourcesErrorMessage.empty()) + { + stringStream << std::endl << std::endl << g_parseSourcesErrorMessage; + } + + g_currentMessagePrompt = stringStream.str(); + g_currentMessagePromptConfirmation = false; + g_currentPage = g_parseSourcesDlcInstallerMode ? WizardPage::SelectDLC : WizardPage::SelectGameAndUpdate; + } + else if (g_parseSourcesDlcIncomplete && !g_parseSourcesDlcInstallerMode) + { + g_currentMessagePrompt = Localise("Installer_Message_DLCWarning"); + g_currentMessagePromptSource = MessagePromptSource::Next; + g_currentMessagePromptConfirmation = true; + } + else if (g_parseSourcesSkipButton && g_parseSourcesDlcInstallerMode) + { + g_isDisappearing = true; + g_disappearTime = ImGui::GetTime(); + } + else + { + g_currentPage = WizardPage::CheckSpace; + } +} + +static void DrawParseSourcesOverlay() +{ + if (!g_parseSourcesActive) + { + return; + } + + auto drawList = ImGui::GetBackgroundDrawList(); + drawList->AddRectFilled({ 0.0f, 0.0f }, ImGui::GetIO().DisplaySize, IM_COL32(0, 0, 0, 190)); + + const char *text = "..."; + float fontSize = Scale(28.0f); + ImVec2 textSize = g_dfsogeistdFont->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, text); + ImVec2 textPos = { + (ImGui::GetIO().DisplaySize.x - textSize.x) * 0.5f, + (ImGui::GetIO().DisplaySize.y - textSize.y) * 0.5f + }; + drawList->AddText(g_dfsogeistdFont, fontSize, textPos, IM_COL32(255, 255, 255, 255), text); +} + static bool InstallerParseSources(std::string &errorMessage) { std::error_code spaceErrorCode; @@ -1401,7 +1503,7 @@ static void DrawNavigationButton() return; } - bool nextButtonEnabled = !g_isDisappearing && (g_currentPage != WizardPage::Installing); + bool nextButtonEnabled = !g_isDisappearing && (g_currentPage != WizardPage::Installing) && !g_parseSourcesActive; if (nextButtonEnabled && g_currentPage == WizardPage::SelectGameAndUpdate) { nextButtonEnabled = !g_gameSourcePath.empty() && !g_updateSourcePath.empty(); @@ -1454,37 +1556,7 @@ static void DrawNavigationButton() } bool dlcInstallerMode = g_gameSourcePath.empty(); - std::string sourcesErrorMessage; - if (!InstallerParseSources(sourcesErrorMessage)) - { - // Some of the sources that were provided to the installer are not valid. Restart the file selection process. - std::stringstream stringStream; - stringStream << Localise("Installer_Message_InvalidFiles"); - if (!sourcesErrorMessage.empty()) { - stringStream << std::endl << std::endl << sourcesErrorMessage; - } - - g_currentMessagePrompt = stringStream.str(); - g_currentMessagePromptConfirmation = false; - g_currentPage = dlcInstallerMode ? WizardPage::SelectDLC : WizardPage::SelectGameAndUpdate; - } - else if (dlcIncomplete && !dlcInstallerMode) - { - // Not all the DLC was specified, we show a prompt and await a confirmation before starting the installer. - g_currentMessagePrompt = Localise("Installer_Message_DLCWarning"); - g_currentMessagePromptSource = MessagePromptSource::Next; - g_currentMessagePromptConfirmation = true; - } - else if (skipButton && dlcInstallerMode) - { - // Nothing was selected and the installer was in DLC mode, just close it. - g_isDisappearing = true; - g_disappearTime = ImGui::GetTime(); - } - else - { - g_currentPage = WizardPage::CheckSpace; - } + StartParseSources(dlcIncomplete, dlcInstallerMode, skipButton); } else if (g_currentPage == WizardPage::CheckSpace) { @@ -1786,6 +1858,8 @@ void InstallerWizard::Draw() DrawSourcePickers(); DrawSources(); DrawInstallingProgress(); + ProcessParseSourcesResult(); + DrawParseSourcesOverlay(); DrawNavigationButton(); CheckCancelAction(); DrawBorders(); @@ -1825,6 +1899,12 @@ void InstallerWizard::Shutdown() g_currentPickerThread.reset(); } + if (g_parseSourcesThread != nullptr) + { + g_parseSourcesThread->join(); + g_parseSourcesThread.reset(); + } + // Erase the sources. g_installerSources.game.reset(); g_installerSources.update.reset(); diff --git a/UnleashedRecomp/ui/touch_controls.cpp b/UnleashedRecomp/ui/touch_controls.cpp new file mode 100644 index 00000000..0e03de04 --- /dev/null +++ b/UnleashedRecomp/ui/touch_controls.cpp @@ -0,0 +1,583 @@ +#include "touch_controls.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef UNLEASHED_RECOMP_IOS + +namespace +{ + struct VirtualButton + { + ImVec2 center{}; + float drawRadius{}; + float hitRadius{}; + uint16_t button{}; + SDL_FingerID fingerId{ -1 }; + bool pressed{}; + }; + + struct VirtualStick + { + ImVec2 center{}; + float radius{}; + float hitRadius{}; + SDL_FingerID fingerId{ -1 }; + ImVec2 delta{}; + }; + + struct ToggleButton + { + ImVec2 min{}; + ImVec2 max{}; + SDL_FingerID fingerId{ -1 }; + }; + + static XAMINPUT_GAMEPAD g_gamepadState{}; + static VirtualStick g_leftStick{}; + static VirtualStick g_rightStick{}; + static std::vector g_buttons; + static ToggleButton g_toggleButton{}; + + static float ViewportHeight() + { + return Video::s_viewportHeight != 0 ? float(Video::s_viewportHeight) : float(GameWindow::s_height); + } + + static float TouchScale() + { + return std::max(1.0f, ViewportHeight() / 720.0f); + } + + static ImVec2 ScreenPoint(float x, float y) + { + return { std::round(x), std::round(y) }; + } + + static ImVec2 LogicalPoint(float x, float y) + { + return ScreenPoint(g_aspectRatioOffsetX + Scale(x), g_aspectRatioOffsetY + Scale(y)); + } + + static void ResetGamepadState() + { + g_gamepadState = {}; + g_leftStick.fingerId = -1; + g_leftStick.delta = {}; + g_rightStick.fingerId = -1; + g_rightStick.delta = {}; + + for (auto& button : g_buttons) + { + button.fingerId = -1; + button.pressed = false; + } + } + + static void SetButtonLayout(size_t index, const ImVec2& center, float drawRadius, uint16_t button) + { + if (index >= g_buttons.size()) + g_buttons.resize(index + 1); + + auto& virtualButton = g_buttons[index]; + virtualButton.center = center; + virtualButton.drawRadius = drawRadius; + virtualButton.hitRadius = std::max(drawRadius * 1.65f, 62.0f * TouchScale()); + virtualButton.button = button; + } + + static void UpdateLayout() + { + const float scale = TouchScale(); + const float stickRadius = std::max(Scale(112.0f), 112.0f * scale); + const float rightStickRadius = std::max(Scale(96.0f), 96.0f * scale); + const float buttonRadius = std::max(Scale(58.0f), 58.0f * scale); + const float smallButtonRadius = std::max(Scale(44.0f), 44.0f * scale); + + g_leftStick.center = LogicalPoint(106.0f, 590.0f); + g_leftStick.radius = stickRadius; + g_leftStick.hitRadius = stickRadius * 1.55f; + + g_rightStick.center = LogicalPoint(1118.0f, 594.0f); + g_rightStick.radius = rightStickRadius; + g_rightStick.hitRadius = rightStickRadius * 1.5f; + + SetButtonLayout(0, LogicalPoint(90.0f, 440.0f), smallButtonRadius, XAMINPUT_GAMEPAD_DPAD_UP); + SetButtonLayout(1, LogicalPoint(90.0f, 540.0f), smallButtonRadius, XAMINPUT_GAMEPAD_DPAD_DOWN); + SetButtonLayout(2, LogicalPoint(32.0f, 490.0f), smallButtonRadius, XAMINPUT_GAMEPAD_DPAD_LEFT); + SetButtonLayout(3, LogicalPoint(148.0f, 490.0f), smallButtonRadius, XAMINPUT_GAMEPAD_DPAD_RIGHT); + + SetButtonLayout(4, LogicalPoint(74.0f, 86.0f), smallButtonRadius, XAMINPUT_GAMEPAD_LEFT_SHOULDER); + SetButtonLayout(5, LogicalPoint(1200.0f, 86.0f), smallButtonRadius, XAMINPUT_GAMEPAD_RIGHT_SHOULDER); + + SetButtonLayout(6, LogicalPoint(1194.0f, 510.0f), buttonRadius, XAMINPUT_GAMEPAD_A); + SetButtonLayout(7, LogicalPoint(1114.0f, 570.0f), buttonRadius, XAMINPUT_GAMEPAD_B); + SetButtonLayout(8, LogicalPoint(1114.0f, 450.0f), buttonRadius, XAMINPUT_GAMEPAD_X); + SetButtonLayout(9, LogicalPoint(1194.0f, 390.0f), buttonRadius, XAMINPUT_GAMEPAD_Y); + + SetButtonLayout(10, LogicalPoint(664.0f, 664.0f), smallButtonRadius, XAMINPUT_GAMEPAD_START); + SetButtonLayout(11, LogicalPoint(564.0f, 664.0f), smallButtonRadius, XAMINPUT_GAMEPAD_BACK); + + g_toggleButton.min = LogicalPoint(1020.0f, 18.0f); + g_toggleButton.max = LogicalPoint(1266.0f, 64.0f); + } + + static bool IsTouchMouseEvent(const SDL_Event* event) + { + switch (event->type) + { + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + return event->button.which == SDL_TOUCH_MOUSEID; + + case SDL_MOUSEMOTION: + return event->motion.which == SDL_TOUCH_MOUSEID; + + default: + return false; + } + } + + static bool IsPointInToggle(const ImVec2& point) + { + return point.x >= g_toggleButton.min.x && point.x <= g_toggleButton.max.x && + point.y >= g_toggleButton.min.y && point.y <= g_toggleButton.max.y; + } + + static VirtualButton* FindButtonAtPoint(const ImVec2& point) + { + for (auto& button : g_buttons) + { + const ImVec2 delta = { point.x - button.center.x, point.y - button.center.y }; + const float distanceSq = delta.x * delta.x + delta.y * delta.y; + if (distanceSq <= button.hitRadius * button.hitRadius) + return &button; + } + + return nullptr; + } + + static VirtualStick* FindStickAtPoint(const ImVec2& point) + { + auto testStick = [&](VirtualStick& stick) -> VirtualStick* + { + const ImVec2 delta = { point.x - stick.center.x, point.y - stick.center.y }; + const float distanceSq = delta.x * delta.x + delta.y * delta.y; + if (distanceSq <= stick.hitRadius * stick.hitRadius) + return &stick; + + return nullptr; + }; + + if (auto* stick = testStick(g_leftStick)) + return stick; + + return testStick(g_rightStick); + } + + static ImVec2 ClampDelta(const ImVec2& delta, float radius) + { + const float length = sqrtf(delta.x * delta.x + delta.y * delta.y); + if (length <= radius || length <= 0.0f) + return delta; + + const float scale = radius / length; + return { delta.x * scale, delta.y * scale }; + } + + static void SetStickPoint(VirtualStick& stick, const ImVec2& point) + { + stick.delta = ClampDelta({ point.x - stick.center.x, point.y - stick.center.y }, stick.radius); + } + + static void UpdateStickValue(VirtualStick& stick) + { + float normX = stick.delta.x / stick.radius; + float normY = stick.delta.y / stick.radius; + const float length = sqrtf(normX * normX + normY * normY); + if (length > 1.0f) + { + normX /= length; + normY /= length; + } + + const int16_t axisX = int16_t(normX * 32767.0f); + const int16_t axisY = int16_t(-normY * 32767.0f); + + if (&stick == &g_leftStick) + { + g_gamepadState.sThumbLX = axisX; + g_gamepadState.sThumbLY = axisY; + } + else + { + g_gamepadState.sThumbRX = axisX; + g_gamepadState.sThumbRY = axisY; + } + } + + static void ResetStick(VirtualStick& stick) + { + stick.fingerId = -1; + stick.delta = {}; + + if (&stick == &g_leftStick) + { + g_gamepadState.sThumbLX = 0; + g_gamepadState.sThumbLY = 0; + } + else + { + g_gamepadState.sThumbRX = 0; + g_gamepadState.sThumbRY = 0; + } + } + + static void RebuildGamepadButtons() + { + g_gamepadState.wButtons = 0; + + for (const auto& button : g_buttons) + { + if (button.pressed) + g_gamepadState.wButtons |= button.button; + } + + g_gamepadState.bLeftTrigger = (g_gamepadState.wButtons & XAMINPUT_GAMEPAD_LEFT_SHOULDER) ? 255 : 0; + g_gamepadState.bRightTrigger = (g_gamepadState.wButtons & XAMINPUT_GAMEPAD_RIGHT_SHOULDER) ? 255 : 0; + } + + static bool HandleTogglePress(const ImVec2& point, SDL_FingerID fingerId, bool pressed) + { + if (pressed) + { + if (!IsPointInToggle(point)) + return false; + + if (g_toggleButton.fingerId < 0) + g_toggleButton.fingerId = fingerId; + + return true; + } + + if (g_toggleButton.fingerId != fingerId) + return false; + + if (IsPointInToggle(point)) + { + Config::TouchControls = !Config::TouchControls; + Config::Save(); + ResetGamepadState(); + } + + g_toggleButton.fingerId = -1; + return true; + } + + static bool HandlePointerDown(const ImVec2& point, SDL_FingerID fingerId) + { + if (HandleTogglePress(point, fingerId, true)) + return true; + + if (!TouchControls::IsEnabled()) + return false; + + if (VirtualButton* button = FindButtonAtPoint(point)) + { + if (button->fingerId < 0) + { + button->fingerId = fingerId; + button->pressed = true; + RebuildGamepadButtons(); + } + + return true; + } + + if (VirtualStick* stick = FindStickAtPoint(point)) + { + if (stick->fingerId < 0) + { + stick->fingerId = fingerId; + SetStickPoint(*stick, point); + UpdateStickValue(*stick); + } + + return true; + } + + return false; + } + + static bool HandlePointerMove(const ImVec2& point, SDL_FingerID fingerId) + { + if (!TouchControls::IsEnabled()) + return false; + + VirtualButton* ownedButton = nullptr; + for (auto& button : g_buttons) + { + if (button.fingerId == fingerId) + { + ownedButton = &button; + break; + } + } + + if (ownedButton) + { + VirtualButton* hoveredButton = FindButtonAtPoint(point); + if (hoveredButton != ownedButton) + { + ownedButton->fingerId = -1; + ownedButton->pressed = false; + + if (hoveredButton && hoveredButton->fingerId < 0) + { + hoveredButton->fingerId = fingerId; + hoveredButton->pressed = true; + } + + RebuildGamepadButtons(); + } + + return true; + } + + for (VirtualStick* stick : { &g_leftStick, &g_rightStick }) + { + if (stick->fingerId != fingerId) + continue; + + SetStickPoint(*stick, point); + UpdateStickValue(*stick); + return true; + } + + return false; + } + + static bool HandlePointerUp(const ImVec2& point, SDL_FingerID fingerId) + { + if (g_toggleButton.fingerId == fingerId) + { + HandleTogglePress(point, fingerId, false); + return true; + } + + if (!TouchControls::IsEnabled()) + return false; + + for (VirtualStick* stick : { &g_leftStick, &g_rightStick }) + { + if (stick->fingerId != fingerId) + continue; + + ResetStick(*stick); + return true; + } + + bool releasedButton = false; + for (auto& button : g_buttons) + { + if (button.fingerId == fingerId) + { + button.fingerId = -1; + button.pressed = false; + releasedButton = true; + } + } + + if (releasedButton) + { + RebuildGamepadButtons(); + return true; + } + + return false; + } + + static void DrawStick(const VirtualStick& stick, const char* label) + { + auto* drawList = ImGui::GetBackgroundDrawList(); + const ImU32 baseColor = IM_COL32(255, 255, 255, 55); + const ImU32 activeColor = IM_COL32(120, 220, 255, 140); + const ImU32 knobColor = IM_COL32(255, 255, 255, 200); + + drawList->AddCircle(stick.center, stick.radius, IM_COL32(255, 255, 255, 120), 32, Scale(3.0f)); + drawList->AddCircleFilled(stick.center, stick.radius, baseColor, 32); + + const ImVec2 knobCenter = { stick.center.x + stick.delta.x, stick.center.y + stick.delta.y }; + drawList->AddCircleFilled(knobCenter, stick.radius * 0.38f, stick.fingerId >= 0 ? activeColor : knobColor, 24); + + if (label && label[0] != '\0') + { + const auto* font = ImGui::GetFont(); + const float fontSize = Scale(14.0f); + const ImVec2 textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, label); + drawList->AddText(font, fontSize, { stick.center.x - textSize.x * 0.5f, stick.center.y - stick.radius - Scale(20.0f) }, IM_COL32(255, 255, 255, 200), label); + } + } + + static void DrawButton(const VirtualButton& button, const char* label) + { + auto* drawList = ImGui::GetBackgroundDrawList(); + const ImU32 fillColor = button.pressed ? IM_COL32(120, 220, 255, 190) : IM_COL32(255, 255, 255, 70); + const ImU32 borderColor = button.pressed ? IM_COL32(180, 240, 255, 230) : IM_COL32(255, 255, 255, 140); + + drawList->AddCircleFilled(button.center, button.drawRadius, fillColor, 24); + drawList->AddCircle(button.center, button.drawRadius, borderColor, 24, Scale(2.5f)); + + if (label && label[0] != '\0') + { + const auto* font = ImGui::GetFont(); + const float fontSize = Scale(16.0f); + const ImVec2 textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, label); + drawList->AddText( + font, + fontSize, + { button.center.x - textSize.x * 0.5f, button.center.y - textSize.y * 0.5f }, + IM_COL32(255, 255, 255, 240), + label); + } + } + + static void DrawToggle() + { + auto* drawList = ImGui::GetBackgroundDrawList(); + const bool enabled = TouchControls::IsEnabled(); + const ImU32 fillColor = enabled ? IM_COL32(70, 150, 90, 170) : IM_COL32(90, 90, 90, 170); + const char* label = enabled ? "Touch ON" : "Touch OFF"; + + drawList->AddRectFilled(g_toggleButton.min, g_toggleButton.max, fillColor, Scale(8.0f)); + drawList->AddRect(g_toggleButton.min, g_toggleButton.max, IM_COL32(255, 255, 255, 180), Scale(8.0f), 0, Scale(2.0f)); + + const auto* font = ImGui::GetFont(); + const float fontSize = Scale(16.0f); + const ImVec2 textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0.0f, label); + const ImVec2 textPos = { + (g_toggleButton.min.x + g_toggleButton.max.x - textSize.x) * 0.5f, + (g_toggleButton.min.y + g_toggleButton.max.y - textSize.y) * 0.5f + }; + drawList->AddText(font, fontSize, textPos, IM_COL32(255, 255, 255, 240), label); + } + + class SDLEventListenerForTouchControls : public SDLEventListener + { + public: + bool OnSDLEvent(SDL_Event* event) override + { + if (!TouchControls::IsActive()) + return false; + + UpdateLayout(); + + switch (event->type) + { + case SDL_FINGERDOWN: + { + const ImVec2 point = GetViewportPointFromSDLEvent(event); + return HandlePointerDown(point, event->tfinger.fingerId); + } + + case SDL_FINGERMOTION: + { + const ImVec2 point = GetViewportPointFromSDLEvent(event); + return HandlePointerMove(point, event->tfinger.fingerId); + } + + case SDL_FINGERUP: + { + const ImVec2 point = GetViewportPointFromSDLEvent(event); + return HandlePointerUp(point, event->tfinger.fingerId); + } + + case SDL_MOUSEBUTTONDOWN: + case SDL_MOUSEBUTTONUP: + { + if (!IsTouchMouseEvent(event)) + break; + + const ImVec2 point = GetViewportPointFromSDLEvent(event); + const SDL_FingerID fingerId = 0; + if (event->type == SDL_MOUSEBUTTONDOWN) + return HandlePointerDown(point, fingerId); + + return HandlePointerUp(point, fingerId); + } + + case SDL_MOUSEMOTION: + { + if (!IsTouchMouseEvent(event)) + break; + + const ImVec2 point = GetViewportPointFromSDLEvent(event); + return HandlePointerMove(point, 0); + } + } + + return false; + } + }; + + static SDLEventListenerForTouchControls g_touchControlsListener; +} + +void TouchControls::Init() +{ + UpdateLayout(); + ResetGamepadState(); +} + +bool TouchControls::IsActive() +{ + return App::s_isInit && !InstallerWizard::s_isVisible; +} + +bool TouchControls::IsEnabled() +{ + return Config::TouchControls; +} + +XAMINPUT_GAMEPAD TouchControls::GetState() +{ + return g_gamepadState; +} + +void TouchControls::Draw() +{ + if (!IsActive()) + return; + + UpdateLayout(); + DrawToggle(); + + if (!IsEnabled()) + return; + + DrawStick(g_leftStick, "Move"); + DrawStick(g_rightStick, "Camera"); + + static const char* labels[] = { "^", "v", "<", ">", "LB", "RB", "A", "B", "X", "Y", "Start", "Back" }; + for (size_t i = 0; i < g_buttons.size() && i < std::size(labels); i++) + DrawButton(g_buttons[i], labels[i]); +} + +#else + +void TouchControls::Init() {} +bool TouchControls::IsActive() { return false; } +bool TouchControls::IsEnabled() { return false; } +XAMINPUT_GAMEPAD TouchControls::GetState() { return {}; } +void TouchControls::Draw() {} + +#endif diff --git a/UnleashedRecomp/ui/touch_controls.h b/UnleashedRecomp/ui/touch_controls.h new file mode 100644 index 00000000..00e0e964 --- /dev/null +++ b/UnleashedRecomp/ui/touch_controls.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace TouchControls +{ + void Init(); + void Draw(); + bool IsActive(); + bool IsEnabled(); + XAMINPUT_GAMEPAD GetState(); +} diff --git a/UnleashedRecomp/user/config_def.h b/UnleashedRecomp/user/config_def.h index 80eb29c9..85f1869f 100644 --- a/UnleashedRecomp/user/config_def.h +++ b/UnleashedRecomp/user/config_def.h @@ -14,6 +14,7 @@ CONFIG_DEFINE_ENUM_LOCALISED("Input", ECameraRotationMode, HorizontalCamera, ECa CONFIG_DEFINE_ENUM_LOCALISED("Input", ECameraRotationMode, VerticalCamera, ECameraRotationMode::Normal); CONFIG_DEFINE_LOCALISED("Input", bool, Vibration, true); CONFIG_DEFINE_LOCALISED("Input", bool, AllowBackgroundInput, false); +CONFIG_DEFINE_HIDDEN("Input", bool, TouchControls, true); CONFIG_DEFINE_ENUM_LOCALISED("Input", EControllerIcons, ControllerIcons, EControllerIcons::Auto); CONFIG_DEFINE_ENUM("Bindings", SDL_Scancode, Key_A, SDL_SCANCODE_S); diff --git a/UnleashedRecomp/user/paths.cpp b/UnleashedRecomp/user/paths.cpp index 35907fe1..2dd19f4f 100644 --- a/UnleashedRecomp/user/paths.cpp +++ b/UnleashedRecomp/user/paths.cpp @@ -1,9 +1,27 @@ #include "paths.h" #include +#if defined(UNLEASHED_RECOMP_IOS) +std::filesystem::path g_executableRoot; +std::filesystem::path g_userPath; + +void InitPaths() +{ + if (!g_executableRoot.empty()) + return; + + g_executableRoot = os::process::GetExecutableRoot(); + g_userPath = BuildUserPath(); +} +#else std::filesystem::path g_executableRoot = os::process::GetExecutableRoot(); std::filesystem::path g_userPath = BuildUserPath(); +void InitPaths() +{ +} +#endif + bool CheckPortable() { return std::filesystem::exists(g_executableRoot / "portable.txt"); diff --git a/UnleashedRecomp/user/paths.h b/UnleashedRecomp/user/paths.h index ecb3e042..87fe55c9 100644 --- a/UnleashedRecomp/user/paths.h +++ b/UnleashedRecomp/user/paths.h @@ -10,6 +10,8 @@ extern std::filesystem::path g_executableRoot; +void InitPaths(); + bool CheckPortable(); std::filesystem::path BuildUserPath(); const std::filesystem::path& GetUserPath(); diff --git a/tools/apply_ios_submodule_patches.sh b/tools/apply_ios_submodule_patches.sh index e8d96633..cefffea4 100755 --- a/tools/apply_ios_submodule_patches.sh +++ b/tools/apply_ios_submodule_patches.sh @@ -3,21 +3,54 @@ set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" PLUME_DIR="$ROOT/thirdparty/plume" -PATCH_FILE="$ROOT/tools/patches/plume-ios-sdl-vulkan.patch" +PLUME_PATCH_FILE="$ROOT/tools/patches/plume-ios-sdl-vulkan.patch" +XENON_RECOMP_DIR="$ROOT/tools/XenonRecomp" +XENON_RECOMP_PATCH_FILE="$ROOT/tools/patches/xenonrecomp-ios-streaming-memory-map.patch" +PLUME_VOLK_HEADER="$PLUME_DIR/contrib/volk/volk.h" +PLUME_VOLK_RENAME_HEADER="$PLUME_DIR/plume_volk_rename_ios.h" if [[ ! -d "$PLUME_DIR/.git" && ! -f "$PLUME_DIR/.git" ]]; then printf 'Missing Plume submodule. Run: git submodule update --init --recursive\n' >&2 exit 1 fi -if git -C "$PLUME_DIR" apply --check "$PATCH_FILE" >/dev/null 2>&1; then - git -C "$PLUME_DIR" apply "$PATCH_FILE" +if [[ ! -d "$XENON_RECOMP_DIR/.git" && ! -f "$XENON_RECOMP_DIR/.git" ]]; then + printf 'Missing XenonRecomp submodule. Run: git submodule update --init --recursive\n' >&2 + exit 1 +fi + +if git -C "$PLUME_DIR" apply --check "$PLUME_PATCH_FILE" >/dev/null 2>&1; then + git -C "$PLUME_DIR" apply "$PLUME_PATCH_FILE" printf 'Applied Plume iOS patch.\n' else - if git -C "$PLUME_DIR" apply --reverse --check "$PATCH_FILE" >/dev/null 2>&1; then + if git -C "$PLUME_DIR" apply --reverse --check "$PLUME_PATCH_FILE" >/dev/null 2>&1; then printf 'Plume iOS patch already applied.\n' else printf 'Plume iOS patch cannot be applied cleanly. Check thirdparty/plume for local changes.\n' >&2 exit 1 fi fi + +if [[ ! -f "$PLUME_VOLK_HEADER" ]]; then + printf 'Missing Plume volk header: %s\n' "$PLUME_VOLK_HEADER" >&2 + exit 1 +fi + +{ + printf '#pragma once\n\n' + printf '// Keep Plume'\''s embedded volk function-pointer globals from colliding with statically linked MoltenVK on iOS.\n' + awk '/^extern PFN_vk/ { name = $3; sub(/;$/, "", name); print "#define " name " plumeVolk_" name }' "$PLUME_VOLK_HEADER" +} > "$PLUME_VOLK_RENAME_HEADER" +printf 'Generated Plume iOS volk rename header.\n' + +if git -C "$XENON_RECOMP_DIR" apply --check "$XENON_RECOMP_PATCH_FILE" >/dev/null 2>&1; then + git -C "$XENON_RECOMP_DIR" apply "$XENON_RECOMP_PATCH_FILE" + printf 'Applied XenonRecomp iOS patch.\n' +else + if git -C "$XENON_RECOMP_DIR" apply --reverse --check "$XENON_RECOMP_PATCH_FILE" >/dev/null 2>&1; then + printf 'XenonRecomp iOS patch already applied.\n' + else + printf 'XenonRecomp iOS patch cannot be applied cleanly. Check tools/XenonRecomp for local changes.\n' >&2 + exit 1 + fi +fi diff --git a/tools/patches/plume-ios-sdl-vulkan.patch b/tools/patches/plume-ios-sdl-vulkan.patch index 67b35fbc..15f7a88e 100644 --- a/tools/patches/plume-ios-sdl-vulkan.patch +++ b/tools/patches/plume-ios-sdl-vulkan.patch @@ -39,7 +39,7 @@ index 6a7645a..6e6e887 100644 ${CMAKE_CURRENT_SOURCE_DIR}/contrib/metal-cpp ) diff --git a/plume_vulkan.cpp b/plume_vulkan.cpp -index 9103ca8..d69b4de 100644 +index 9103ca8..63de1cc 100644 --- a/plume_vulkan.cpp +++ b/plume_vulkan.cpp @@ -8,6 +8,9 @@ @@ -63,7 +63,27 @@ index 9103ca8..d69b4de 100644 #ifndef NDEBUG # define VULKAN_VALIDATION_LAYER_ENABLED # define VULKAN_OBJECT_NAMES_ENABLED -@@ -2112,6 +2119,12 @@ namespace plume { +@@ -88,6 +95,19 @@ namespace plume { + VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME, + }; + ++ static std::unordered_set getRequiredDeviceExtensions(uint32_t apiVersion) { ++ std::unordered_set extensions = RequiredDeviceExtensions; ++ ++ // MoltenVK and other Vulkan 1.2+ implementations expose these as core features ++ // and no longer enumerate them as separate device extensions. ++ if (apiVersion >= VK_API_VERSION_1_2) { ++ extensions.erase(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); ++ extensions.erase(VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_EXTENSION_NAME); ++ } ++ ++ return extensions; ++ } ++ + // Common functions. + + static uint32_t roundUp(uint32_t value, uint32_t powerOf2Alignment) { +@@ -2112,6 +2132,12 @@ namespace plume { fprintf(stderr, "vkCreateXlibSurfaceKHR failed with error code 0x%X.\n", res); return; } @@ -76,7 +96,7 @@ index 9103ca8..d69b4de 100644 # elif defined(__APPLE__) assert(renderWindow.window != 0); assert(renderWindow.view != 0); -@@ -2443,7 +2456,7 @@ namespace plume { +@@ -2443,7 +2469,7 @@ namespace plume { // The attributes width and height members do not include the border. dstWidth = attributes.width; dstHeight = attributes.height; @@ -85,7 +105,36 @@ index 9103ca8..d69b4de 100644 CocoaWindowAttributes attributes; windowWrapper->getWindowAttributes(&attributes); dstWidth = attributes.width; -@@ -4398,11 +4411,16 @@ namespace plume { +@@ -3754,6 +3780,10 @@ namespace plume { + return; + } + ++ VkPhysicalDeviceProperties selectedDeviceProperties; ++ vkGetPhysicalDeviceProperties(physicalDevice, &selectedDeviceProperties); ++ const std::unordered_set requiredDeviceExtensions = getRequiredDeviceExtensions(selectedDeviceProperties.apiVersion); ++ + // Check for extensions. + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); +@@ -3761,7 +3791,7 @@ namespace plume { + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data()); + +- std::unordered_set missingRequiredExtensions = RequiredDeviceExtensions; ++ std::unordered_set missingRequiredExtensions = requiredDeviceExtensions; + std::unordered_set supportedOptionalExtensions; + # if DLSS_ENABLED + const std::unordered_set dlssExtensions = DLSS::getRequiredDeviceExtensionsVulkan(this); +@@ -3969,7 +3999,7 @@ namespace plume { + } + + std::vector enabledExtensions; +- for (const std::string &extension : RequiredDeviceExtensions) { ++ for (const std::string &extension : requiredDeviceExtensions) { + enabledExtensions.push_back(extension.c_str()); + } + +@@ -4398,11 +4428,16 @@ namespace plume { #else VulkanInterface::VulkanInterface() { #endif @@ -127,771 +176,3 @@ index 73022bb..9d89adf 100644 std::unique_ptr windowWrapper; #endif uint32_t textureCount = 0; -diff --git a/plume_volk_rename_ios.h b/plume_volk_rename_ios.h -new file mode 100644 -index 0000000..327d094 ---- /dev/null -+++ b/plume_volk_rename_ios.h -@@ -0,0 +1,762 @@ -+#pragma once -+ -+// Keep Plume's embedded volk function-pointer globals from colliding with statically linked MoltenVK on iOS. -+#define vkAcquireDrmDisplayEXT plumeVolk_vkAcquireDrmDisplayEXT -+#define vkAcquireFullScreenExclusiveModeEXT plumeVolk_vkAcquireFullScreenExclusiveModeEXT -+#define vkAcquireNextImage2KHR plumeVolk_vkAcquireNextImage2KHR -+#define vkAcquireNextImageKHR plumeVolk_vkAcquireNextImageKHR -+#define vkAcquirePerformanceConfigurationINTEL plumeVolk_vkAcquirePerformanceConfigurationINTEL -+#define vkAcquireProfilingLockKHR plumeVolk_vkAcquireProfilingLockKHR -+#define vkAcquireWinrtDisplayNV plumeVolk_vkAcquireWinrtDisplayNV -+#define vkAcquireXlibDisplayEXT plumeVolk_vkAcquireXlibDisplayEXT -+#define vkAllocateCommandBuffers plumeVolk_vkAllocateCommandBuffers -+#define vkAllocateDescriptorSets plumeVolk_vkAllocateDescriptorSets -+#define vkAllocateMemory plumeVolk_vkAllocateMemory -+#define vkAntiLagUpdateAMD plumeVolk_vkAntiLagUpdateAMD -+#define vkBeginCommandBuffer plumeVolk_vkBeginCommandBuffer -+#define vkBindAccelerationStructureMemoryNV plumeVolk_vkBindAccelerationStructureMemoryNV -+#define vkBindBufferMemory plumeVolk_vkBindBufferMemory -+#define vkBindBufferMemory2 plumeVolk_vkBindBufferMemory2 -+#define vkBindBufferMemory2KHR plumeVolk_vkBindBufferMemory2KHR -+#define vkBindDataGraphPipelineSessionMemoryARM plumeVolk_vkBindDataGraphPipelineSessionMemoryARM -+#define vkBindImageMemory plumeVolk_vkBindImageMemory -+#define vkBindImageMemory2 plumeVolk_vkBindImageMemory2 -+#define vkBindImageMemory2KHR plumeVolk_vkBindImageMemory2KHR -+#define vkBindOpticalFlowSessionImageNV plumeVolk_vkBindOpticalFlowSessionImageNV -+#define vkBindTensorMemoryARM plumeVolk_vkBindTensorMemoryARM -+#define vkBindVideoSessionMemoryKHR plumeVolk_vkBindVideoSessionMemoryKHR -+#define vkBuildAccelerationStructuresKHR plumeVolk_vkBuildAccelerationStructuresKHR -+#define vkBuildMicromapsEXT plumeVolk_vkBuildMicromapsEXT -+#define vkCmdBeginConditionalRenderingEXT plumeVolk_vkCmdBeginConditionalRenderingEXT -+#define vkCmdBeginDebugUtilsLabelEXT plumeVolk_vkCmdBeginDebugUtilsLabelEXT -+#define vkCmdBeginPerTileExecutionQCOM plumeVolk_vkCmdBeginPerTileExecutionQCOM -+#define vkCmdBeginQuery plumeVolk_vkCmdBeginQuery -+#define vkCmdBeginQueryIndexedEXT plumeVolk_vkCmdBeginQueryIndexedEXT -+#define vkCmdBeginRenderPass plumeVolk_vkCmdBeginRenderPass -+#define vkCmdBeginRenderPass2 plumeVolk_vkCmdBeginRenderPass2 -+#define vkCmdBeginRenderPass2KHR plumeVolk_vkCmdBeginRenderPass2KHR -+#define vkCmdBeginRendering plumeVolk_vkCmdBeginRendering -+#define vkCmdBeginRenderingKHR plumeVolk_vkCmdBeginRenderingKHR -+#define vkCmdBeginTransformFeedbackEXT plumeVolk_vkCmdBeginTransformFeedbackEXT -+#define vkCmdBeginVideoCodingKHR plumeVolk_vkCmdBeginVideoCodingKHR -+#define vkCmdBindDescriptorBufferEmbeddedSamplers2EXT plumeVolk_vkCmdBindDescriptorBufferEmbeddedSamplers2EXT -+#define vkCmdBindDescriptorBufferEmbeddedSamplersEXT plumeVolk_vkCmdBindDescriptorBufferEmbeddedSamplersEXT -+#define vkCmdBindDescriptorBuffersEXT plumeVolk_vkCmdBindDescriptorBuffersEXT -+#define vkCmdBindDescriptorSets plumeVolk_vkCmdBindDescriptorSets -+#define vkCmdBindDescriptorSets2 plumeVolk_vkCmdBindDescriptorSets2 -+#define vkCmdBindDescriptorSets2KHR plumeVolk_vkCmdBindDescriptorSets2KHR -+#define vkCmdBindIndexBuffer plumeVolk_vkCmdBindIndexBuffer -+#define vkCmdBindIndexBuffer2 plumeVolk_vkCmdBindIndexBuffer2 -+#define vkCmdBindIndexBuffer2KHR plumeVolk_vkCmdBindIndexBuffer2KHR -+#define vkCmdBindInvocationMaskHUAWEI plumeVolk_vkCmdBindInvocationMaskHUAWEI -+#define vkCmdBindPipeline plumeVolk_vkCmdBindPipeline -+#define vkCmdBindPipelineShaderGroupNV plumeVolk_vkCmdBindPipelineShaderGroupNV -+#define vkCmdBindShadersEXT plumeVolk_vkCmdBindShadersEXT -+#define vkCmdBindShadingRateImageNV plumeVolk_vkCmdBindShadingRateImageNV -+#define vkCmdBindTileMemoryQCOM plumeVolk_vkCmdBindTileMemoryQCOM -+#define vkCmdBindTransformFeedbackBuffersEXT plumeVolk_vkCmdBindTransformFeedbackBuffersEXT -+#define vkCmdBindVertexBuffers plumeVolk_vkCmdBindVertexBuffers -+#define vkCmdBindVertexBuffers2 plumeVolk_vkCmdBindVertexBuffers2 -+#define vkCmdBindVertexBuffers2EXT plumeVolk_vkCmdBindVertexBuffers2EXT -+#define vkCmdBlitImage plumeVolk_vkCmdBlitImage -+#define vkCmdBlitImage2 plumeVolk_vkCmdBlitImage2 -+#define vkCmdBlitImage2KHR plumeVolk_vkCmdBlitImage2KHR -+#define vkCmdBuildAccelerationStructureNV plumeVolk_vkCmdBuildAccelerationStructureNV -+#define vkCmdBuildAccelerationStructuresIndirectKHR plumeVolk_vkCmdBuildAccelerationStructuresIndirectKHR -+#define vkCmdBuildAccelerationStructuresKHR plumeVolk_vkCmdBuildAccelerationStructuresKHR -+#define vkCmdBuildClusterAccelerationStructureIndirectNV plumeVolk_vkCmdBuildClusterAccelerationStructureIndirectNV -+#define vkCmdBuildMicromapsEXT plumeVolk_vkCmdBuildMicromapsEXT -+#define vkCmdBuildPartitionedAccelerationStructuresNV plumeVolk_vkCmdBuildPartitionedAccelerationStructuresNV -+#define vkCmdClearAttachments plumeVolk_vkCmdClearAttachments -+#define vkCmdClearColorImage plumeVolk_vkCmdClearColorImage -+#define vkCmdClearDepthStencilImage plumeVolk_vkCmdClearDepthStencilImage -+#define vkCmdControlVideoCodingKHR plumeVolk_vkCmdControlVideoCodingKHR -+#define vkCmdConvertCooperativeVectorMatrixNV plumeVolk_vkCmdConvertCooperativeVectorMatrixNV -+#define vkCmdCopyAccelerationStructureKHR plumeVolk_vkCmdCopyAccelerationStructureKHR -+#define vkCmdCopyAccelerationStructureNV plumeVolk_vkCmdCopyAccelerationStructureNV -+#define vkCmdCopyAccelerationStructureToMemoryKHR plumeVolk_vkCmdCopyAccelerationStructureToMemoryKHR -+#define vkCmdCopyBuffer plumeVolk_vkCmdCopyBuffer -+#define vkCmdCopyBuffer2 plumeVolk_vkCmdCopyBuffer2 -+#define vkCmdCopyBuffer2KHR plumeVolk_vkCmdCopyBuffer2KHR -+#define vkCmdCopyBufferToImage plumeVolk_vkCmdCopyBufferToImage -+#define vkCmdCopyBufferToImage2 plumeVolk_vkCmdCopyBufferToImage2 -+#define vkCmdCopyBufferToImage2KHR plumeVolk_vkCmdCopyBufferToImage2KHR -+#define vkCmdCopyImage plumeVolk_vkCmdCopyImage -+#define vkCmdCopyImage2 plumeVolk_vkCmdCopyImage2 -+#define vkCmdCopyImage2KHR plumeVolk_vkCmdCopyImage2KHR -+#define vkCmdCopyImageToBuffer plumeVolk_vkCmdCopyImageToBuffer -+#define vkCmdCopyImageToBuffer2 plumeVolk_vkCmdCopyImageToBuffer2 -+#define vkCmdCopyImageToBuffer2KHR plumeVolk_vkCmdCopyImageToBuffer2KHR -+#define vkCmdCopyMemoryIndirectNV plumeVolk_vkCmdCopyMemoryIndirectNV -+#define vkCmdCopyMemoryToAccelerationStructureKHR plumeVolk_vkCmdCopyMemoryToAccelerationStructureKHR -+#define vkCmdCopyMemoryToImageIndirectNV plumeVolk_vkCmdCopyMemoryToImageIndirectNV -+#define vkCmdCopyMemoryToMicromapEXT plumeVolk_vkCmdCopyMemoryToMicromapEXT -+#define vkCmdCopyMicromapEXT plumeVolk_vkCmdCopyMicromapEXT -+#define vkCmdCopyMicromapToMemoryEXT plumeVolk_vkCmdCopyMicromapToMemoryEXT -+#define vkCmdCopyQueryPoolResults plumeVolk_vkCmdCopyQueryPoolResults -+#define vkCmdCopyTensorARM plumeVolk_vkCmdCopyTensorARM -+#define vkCmdCuLaunchKernelNVX plumeVolk_vkCmdCuLaunchKernelNVX -+#define vkCmdCudaLaunchKernelNV plumeVolk_vkCmdCudaLaunchKernelNV -+#define vkCmdDebugMarkerBeginEXT plumeVolk_vkCmdDebugMarkerBeginEXT -+#define vkCmdDebugMarkerEndEXT plumeVolk_vkCmdDebugMarkerEndEXT -+#define vkCmdDebugMarkerInsertEXT plumeVolk_vkCmdDebugMarkerInsertEXT -+#define vkCmdDecodeVideoKHR plumeVolk_vkCmdDecodeVideoKHR -+#define vkCmdDecompressMemoryIndirectCountNV plumeVolk_vkCmdDecompressMemoryIndirectCountNV -+#define vkCmdDecompressMemoryNV plumeVolk_vkCmdDecompressMemoryNV -+#define vkCmdDispatch plumeVolk_vkCmdDispatch -+#define vkCmdDispatchBase plumeVolk_vkCmdDispatchBase -+#define vkCmdDispatchBaseKHR plumeVolk_vkCmdDispatchBaseKHR -+#define vkCmdDispatchDataGraphARM plumeVolk_vkCmdDispatchDataGraphARM -+#define vkCmdDispatchGraphAMDX plumeVolk_vkCmdDispatchGraphAMDX -+#define vkCmdDispatchGraphIndirectAMDX plumeVolk_vkCmdDispatchGraphIndirectAMDX -+#define vkCmdDispatchGraphIndirectCountAMDX plumeVolk_vkCmdDispatchGraphIndirectCountAMDX -+#define vkCmdDispatchIndirect plumeVolk_vkCmdDispatchIndirect -+#define vkCmdDispatchTileQCOM plumeVolk_vkCmdDispatchTileQCOM -+#define vkCmdDraw plumeVolk_vkCmdDraw -+#define vkCmdDrawClusterHUAWEI plumeVolk_vkCmdDrawClusterHUAWEI -+#define vkCmdDrawClusterIndirectHUAWEI plumeVolk_vkCmdDrawClusterIndirectHUAWEI -+#define vkCmdDrawIndexed plumeVolk_vkCmdDrawIndexed -+#define vkCmdDrawIndexedIndirect plumeVolk_vkCmdDrawIndexedIndirect -+#define vkCmdDrawIndexedIndirectCount plumeVolk_vkCmdDrawIndexedIndirectCount -+#define vkCmdDrawIndexedIndirectCountAMD plumeVolk_vkCmdDrawIndexedIndirectCountAMD -+#define vkCmdDrawIndexedIndirectCountKHR plumeVolk_vkCmdDrawIndexedIndirectCountKHR -+#define vkCmdDrawIndirect plumeVolk_vkCmdDrawIndirect -+#define vkCmdDrawIndirectByteCountEXT plumeVolk_vkCmdDrawIndirectByteCountEXT -+#define vkCmdDrawIndirectCount plumeVolk_vkCmdDrawIndirectCount -+#define vkCmdDrawIndirectCountAMD plumeVolk_vkCmdDrawIndirectCountAMD -+#define vkCmdDrawIndirectCountKHR plumeVolk_vkCmdDrawIndirectCountKHR -+#define vkCmdDrawMeshTasksEXT plumeVolk_vkCmdDrawMeshTasksEXT -+#define vkCmdDrawMeshTasksIndirectCountEXT plumeVolk_vkCmdDrawMeshTasksIndirectCountEXT -+#define vkCmdDrawMeshTasksIndirectCountNV plumeVolk_vkCmdDrawMeshTasksIndirectCountNV -+#define vkCmdDrawMeshTasksIndirectEXT plumeVolk_vkCmdDrawMeshTasksIndirectEXT -+#define vkCmdDrawMeshTasksIndirectNV plumeVolk_vkCmdDrawMeshTasksIndirectNV -+#define vkCmdDrawMeshTasksNV plumeVolk_vkCmdDrawMeshTasksNV -+#define vkCmdDrawMultiEXT plumeVolk_vkCmdDrawMultiEXT -+#define vkCmdDrawMultiIndexedEXT plumeVolk_vkCmdDrawMultiIndexedEXT -+#define vkCmdEncodeVideoKHR plumeVolk_vkCmdEncodeVideoKHR -+#define vkCmdEndConditionalRenderingEXT plumeVolk_vkCmdEndConditionalRenderingEXT -+#define vkCmdEndDebugUtilsLabelEXT plumeVolk_vkCmdEndDebugUtilsLabelEXT -+#define vkCmdEndPerTileExecutionQCOM plumeVolk_vkCmdEndPerTileExecutionQCOM -+#define vkCmdEndQuery plumeVolk_vkCmdEndQuery -+#define vkCmdEndQueryIndexedEXT plumeVolk_vkCmdEndQueryIndexedEXT -+#define vkCmdEndRenderPass plumeVolk_vkCmdEndRenderPass -+#define vkCmdEndRenderPass2 plumeVolk_vkCmdEndRenderPass2 -+#define vkCmdEndRenderPass2KHR plumeVolk_vkCmdEndRenderPass2KHR -+#define vkCmdEndRendering plumeVolk_vkCmdEndRendering -+#define vkCmdEndRendering2EXT plumeVolk_vkCmdEndRendering2EXT -+#define vkCmdEndRenderingKHR plumeVolk_vkCmdEndRenderingKHR -+#define vkCmdEndTransformFeedbackEXT plumeVolk_vkCmdEndTransformFeedbackEXT -+#define vkCmdEndVideoCodingKHR plumeVolk_vkCmdEndVideoCodingKHR -+#define vkCmdExecuteCommands plumeVolk_vkCmdExecuteCommands -+#define vkCmdExecuteGeneratedCommandsEXT plumeVolk_vkCmdExecuteGeneratedCommandsEXT -+#define vkCmdExecuteGeneratedCommandsNV plumeVolk_vkCmdExecuteGeneratedCommandsNV -+#define vkCmdFillBuffer plumeVolk_vkCmdFillBuffer -+#define vkCmdInitializeGraphScratchMemoryAMDX plumeVolk_vkCmdInitializeGraphScratchMemoryAMDX -+#define vkCmdInsertDebugUtilsLabelEXT plumeVolk_vkCmdInsertDebugUtilsLabelEXT -+#define vkCmdNextSubpass plumeVolk_vkCmdNextSubpass -+#define vkCmdNextSubpass2 plumeVolk_vkCmdNextSubpass2 -+#define vkCmdNextSubpass2KHR plumeVolk_vkCmdNextSubpass2KHR -+#define vkCmdOpticalFlowExecuteNV plumeVolk_vkCmdOpticalFlowExecuteNV -+#define vkCmdPipelineBarrier plumeVolk_vkCmdPipelineBarrier -+#define vkCmdPipelineBarrier2 plumeVolk_vkCmdPipelineBarrier2 -+#define vkCmdPipelineBarrier2KHR plumeVolk_vkCmdPipelineBarrier2KHR -+#define vkCmdPreprocessGeneratedCommandsEXT plumeVolk_vkCmdPreprocessGeneratedCommandsEXT -+#define vkCmdPreprocessGeneratedCommandsNV plumeVolk_vkCmdPreprocessGeneratedCommandsNV -+#define vkCmdPushConstants plumeVolk_vkCmdPushConstants -+#define vkCmdPushConstants2 plumeVolk_vkCmdPushConstants2 -+#define vkCmdPushConstants2KHR plumeVolk_vkCmdPushConstants2KHR -+#define vkCmdPushDescriptorSet plumeVolk_vkCmdPushDescriptorSet -+#define vkCmdPushDescriptorSet2 plumeVolk_vkCmdPushDescriptorSet2 -+#define vkCmdPushDescriptorSet2KHR plumeVolk_vkCmdPushDescriptorSet2KHR -+#define vkCmdPushDescriptorSetKHR plumeVolk_vkCmdPushDescriptorSetKHR -+#define vkCmdPushDescriptorSetWithTemplate plumeVolk_vkCmdPushDescriptorSetWithTemplate -+#define vkCmdPushDescriptorSetWithTemplate2 plumeVolk_vkCmdPushDescriptorSetWithTemplate2 -+#define vkCmdPushDescriptorSetWithTemplate2KHR plumeVolk_vkCmdPushDescriptorSetWithTemplate2KHR -+#define vkCmdPushDescriptorSetWithTemplateKHR plumeVolk_vkCmdPushDescriptorSetWithTemplateKHR -+#define vkCmdResetEvent plumeVolk_vkCmdResetEvent -+#define vkCmdResetEvent2 plumeVolk_vkCmdResetEvent2 -+#define vkCmdResetEvent2KHR plumeVolk_vkCmdResetEvent2KHR -+#define vkCmdResetQueryPool plumeVolk_vkCmdResetQueryPool -+#define vkCmdResolveImage plumeVolk_vkCmdResolveImage -+#define vkCmdResolveImage2 plumeVolk_vkCmdResolveImage2 -+#define vkCmdResolveImage2KHR plumeVolk_vkCmdResolveImage2KHR -+#define vkCmdSetAlphaToCoverageEnableEXT plumeVolk_vkCmdSetAlphaToCoverageEnableEXT -+#define vkCmdSetAlphaToOneEnableEXT plumeVolk_vkCmdSetAlphaToOneEnableEXT -+#define vkCmdSetAttachmentFeedbackLoopEnableEXT plumeVolk_vkCmdSetAttachmentFeedbackLoopEnableEXT -+#define vkCmdSetBlendConstants plumeVolk_vkCmdSetBlendConstants -+#define vkCmdSetCheckpointNV plumeVolk_vkCmdSetCheckpointNV -+#define vkCmdSetCoarseSampleOrderNV plumeVolk_vkCmdSetCoarseSampleOrderNV -+#define vkCmdSetColorBlendAdvancedEXT plumeVolk_vkCmdSetColorBlendAdvancedEXT -+#define vkCmdSetColorBlendEnableEXT plumeVolk_vkCmdSetColorBlendEnableEXT -+#define vkCmdSetColorBlendEquationEXT plumeVolk_vkCmdSetColorBlendEquationEXT -+#define vkCmdSetColorWriteEnableEXT plumeVolk_vkCmdSetColorWriteEnableEXT -+#define vkCmdSetColorWriteMaskEXT plumeVolk_vkCmdSetColorWriteMaskEXT -+#define vkCmdSetConservativeRasterizationModeEXT plumeVolk_vkCmdSetConservativeRasterizationModeEXT -+#define vkCmdSetCoverageModulationModeNV plumeVolk_vkCmdSetCoverageModulationModeNV -+#define vkCmdSetCoverageModulationTableEnableNV plumeVolk_vkCmdSetCoverageModulationTableEnableNV -+#define vkCmdSetCoverageModulationTableNV plumeVolk_vkCmdSetCoverageModulationTableNV -+#define vkCmdSetCoverageReductionModeNV plumeVolk_vkCmdSetCoverageReductionModeNV -+#define vkCmdSetCoverageToColorEnableNV plumeVolk_vkCmdSetCoverageToColorEnableNV -+#define vkCmdSetCoverageToColorLocationNV plumeVolk_vkCmdSetCoverageToColorLocationNV -+#define vkCmdSetCullMode plumeVolk_vkCmdSetCullMode -+#define vkCmdSetCullModeEXT plumeVolk_vkCmdSetCullModeEXT -+#define vkCmdSetDepthBias plumeVolk_vkCmdSetDepthBias -+#define vkCmdSetDepthBias2EXT plumeVolk_vkCmdSetDepthBias2EXT -+#define vkCmdSetDepthBiasEnable plumeVolk_vkCmdSetDepthBiasEnable -+#define vkCmdSetDepthBiasEnableEXT plumeVolk_vkCmdSetDepthBiasEnableEXT -+#define vkCmdSetDepthBounds plumeVolk_vkCmdSetDepthBounds -+#define vkCmdSetDepthBoundsTestEnable plumeVolk_vkCmdSetDepthBoundsTestEnable -+#define vkCmdSetDepthBoundsTestEnableEXT plumeVolk_vkCmdSetDepthBoundsTestEnableEXT -+#define vkCmdSetDepthClampEnableEXT plumeVolk_vkCmdSetDepthClampEnableEXT -+#define vkCmdSetDepthClampRangeEXT plumeVolk_vkCmdSetDepthClampRangeEXT -+#define vkCmdSetDepthClipEnableEXT plumeVolk_vkCmdSetDepthClipEnableEXT -+#define vkCmdSetDepthClipNegativeOneToOneEXT plumeVolk_vkCmdSetDepthClipNegativeOneToOneEXT -+#define vkCmdSetDepthCompareOp plumeVolk_vkCmdSetDepthCompareOp -+#define vkCmdSetDepthCompareOpEXT plumeVolk_vkCmdSetDepthCompareOpEXT -+#define vkCmdSetDepthTestEnable plumeVolk_vkCmdSetDepthTestEnable -+#define vkCmdSetDepthTestEnableEXT plumeVolk_vkCmdSetDepthTestEnableEXT -+#define vkCmdSetDepthWriteEnable plumeVolk_vkCmdSetDepthWriteEnable -+#define vkCmdSetDepthWriteEnableEXT plumeVolk_vkCmdSetDepthWriteEnableEXT -+#define vkCmdSetDescriptorBufferOffsets2EXT plumeVolk_vkCmdSetDescriptorBufferOffsets2EXT -+#define vkCmdSetDescriptorBufferOffsetsEXT plumeVolk_vkCmdSetDescriptorBufferOffsetsEXT -+#define vkCmdSetDeviceMask plumeVolk_vkCmdSetDeviceMask -+#define vkCmdSetDeviceMaskKHR plumeVolk_vkCmdSetDeviceMaskKHR -+#define vkCmdSetDiscardRectangleEXT plumeVolk_vkCmdSetDiscardRectangleEXT -+#define vkCmdSetDiscardRectangleEnableEXT plumeVolk_vkCmdSetDiscardRectangleEnableEXT -+#define vkCmdSetDiscardRectangleModeEXT plumeVolk_vkCmdSetDiscardRectangleModeEXT -+#define vkCmdSetEvent plumeVolk_vkCmdSetEvent -+#define vkCmdSetEvent2 plumeVolk_vkCmdSetEvent2 -+#define vkCmdSetEvent2KHR plumeVolk_vkCmdSetEvent2KHR -+#define vkCmdSetExclusiveScissorEnableNV plumeVolk_vkCmdSetExclusiveScissorEnableNV -+#define vkCmdSetExclusiveScissorNV plumeVolk_vkCmdSetExclusiveScissorNV -+#define vkCmdSetExtraPrimitiveOverestimationSizeEXT plumeVolk_vkCmdSetExtraPrimitiveOverestimationSizeEXT -+#define vkCmdSetFragmentShadingRateEnumNV plumeVolk_vkCmdSetFragmentShadingRateEnumNV -+#define vkCmdSetFragmentShadingRateKHR plumeVolk_vkCmdSetFragmentShadingRateKHR -+#define vkCmdSetFrontFace plumeVolk_vkCmdSetFrontFace -+#define vkCmdSetFrontFaceEXT plumeVolk_vkCmdSetFrontFaceEXT -+#define vkCmdSetLineRasterizationModeEXT plumeVolk_vkCmdSetLineRasterizationModeEXT -+#define vkCmdSetLineStipple plumeVolk_vkCmdSetLineStipple -+#define vkCmdSetLineStippleEXT plumeVolk_vkCmdSetLineStippleEXT -+#define vkCmdSetLineStippleEnableEXT plumeVolk_vkCmdSetLineStippleEnableEXT -+#define vkCmdSetLineStippleKHR plumeVolk_vkCmdSetLineStippleKHR -+#define vkCmdSetLineWidth plumeVolk_vkCmdSetLineWidth -+#define vkCmdSetLogicOpEXT plumeVolk_vkCmdSetLogicOpEXT -+#define vkCmdSetLogicOpEnableEXT plumeVolk_vkCmdSetLogicOpEnableEXT -+#define vkCmdSetPatchControlPointsEXT plumeVolk_vkCmdSetPatchControlPointsEXT -+#define vkCmdSetPerformanceMarkerINTEL plumeVolk_vkCmdSetPerformanceMarkerINTEL -+#define vkCmdSetPerformanceOverrideINTEL plumeVolk_vkCmdSetPerformanceOverrideINTEL -+#define vkCmdSetPerformanceStreamMarkerINTEL plumeVolk_vkCmdSetPerformanceStreamMarkerINTEL -+#define vkCmdSetPolygonModeEXT plumeVolk_vkCmdSetPolygonModeEXT -+#define vkCmdSetPrimitiveRestartEnable plumeVolk_vkCmdSetPrimitiveRestartEnable -+#define vkCmdSetPrimitiveRestartEnableEXT plumeVolk_vkCmdSetPrimitiveRestartEnableEXT -+#define vkCmdSetPrimitiveTopology plumeVolk_vkCmdSetPrimitiveTopology -+#define vkCmdSetPrimitiveTopologyEXT plumeVolk_vkCmdSetPrimitiveTopologyEXT -+#define vkCmdSetProvokingVertexModeEXT plumeVolk_vkCmdSetProvokingVertexModeEXT -+#define vkCmdSetRasterizationSamplesEXT plumeVolk_vkCmdSetRasterizationSamplesEXT -+#define vkCmdSetRasterizationStreamEXT plumeVolk_vkCmdSetRasterizationStreamEXT -+#define vkCmdSetRasterizerDiscardEnable plumeVolk_vkCmdSetRasterizerDiscardEnable -+#define vkCmdSetRasterizerDiscardEnableEXT plumeVolk_vkCmdSetRasterizerDiscardEnableEXT -+#define vkCmdSetRayTracingPipelineStackSizeKHR plumeVolk_vkCmdSetRayTracingPipelineStackSizeKHR -+#define vkCmdSetRenderingAttachmentLocations plumeVolk_vkCmdSetRenderingAttachmentLocations -+#define vkCmdSetRenderingAttachmentLocationsKHR plumeVolk_vkCmdSetRenderingAttachmentLocationsKHR -+#define vkCmdSetRenderingInputAttachmentIndices plumeVolk_vkCmdSetRenderingInputAttachmentIndices -+#define vkCmdSetRenderingInputAttachmentIndicesKHR plumeVolk_vkCmdSetRenderingInputAttachmentIndicesKHR -+#define vkCmdSetRepresentativeFragmentTestEnableNV plumeVolk_vkCmdSetRepresentativeFragmentTestEnableNV -+#define vkCmdSetSampleLocationsEXT plumeVolk_vkCmdSetSampleLocationsEXT -+#define vkCmdSetSampleLocationsEnableEXT plumeVolk_vkCmdSetSampleLocationsEnableEXT -+#define vkCmdSetSampleMaskEXT plumeVolk_vkCmdSetSampleMaskEXT -+#define vkCmdSetScissor plumeVolk_vkCmdSetScissor -+#define vkCmdSetScissorWithCount plumeVolk_vkCmdSetScissorWithCount -+#define vkCmdSetScissorWithCountEXT plumeVolk_vkCmdSetScissorWithCountEXT -+#define vkCmdSetShadingRateImageEnableNV plumeVolk_vkCmdSetShadingRateImageEnableNV -+#define vkCmdSetStencilCompareMask plumeVolk_vkCmdSetStencilCompareMask -+#define vkCmdSetStencilOp plumeVolk_vkCmdSetStencilOp -+#define vkCmdSetStencilOpEXT plumeVolk_vkCmdSetStencilOpEXT -+#define vkCmdSetStencilReference plumeVolk_vkCmdSetStencilReference -+#define vkCmdSetStencilTestEnable plumeVolk_vkCmdSetStencilTestEnable -+#define vkCmdSetStencilTestEnableEXT plumeVolk_vkCmdSetStencilTestEnableEXT -+#define vkCmdSetStencilWriteMask plumeVolk_vkCmdSetStencilWriteMask -+#define vkCmdSetTessellationDomainOriginEXT plumeVolk_vkCmdSetTessellationDomainOriginEXT -+#define vkCmdSetVertexInputEXT plumeVolk_vkCmdSetVertexInputEXT -+#define vkCmdSetViewport plumeVolk_vkCmdSetViewport -+#define vkCmdSetViewportShadingRatePaletteNV plumeVolk_vkCmdSetViewportShadingRatePaletteNV -+#define vkCmdSetViewportSwizzleNV plumeVolk_vkCmdSetViewportSwizzleNV -+#define vkCmdSetViewportWScalingEnableNV plumeVolk_vkCmdSetViewportWScalingEnableNV -+#define vkCmdSetViewportWScalingNV plumeVolk_vkCmdSetViewportWScalingNV -+#define vkCmdSetViewportWithCount plumeVolk_vkCmdSetViewportWithCount -+#define vkCmdSetViewportWithCountEXT plumeVolk_vkCmdSetViewportWithCountEXT -+#define vkCmdSubpassShadingHUAWEI plumeVolk_vkCmdSubpassShadingHUAWEI -+#define vkCmdTraceRaysIndirect2KHR plumeVolk_vkCmdTraceRaysIndirect2KHR -+#define vkCmdTraceRaysIndirectKHR plumeVolk_vkCmdTraceRaysIndirectKHR -+#define vkCmdTraceRaysKHR plumeVolk_vkCmdTraceRaysKHR -+#define vkCmdTraceRaysNV plumeVolk_vkCmdTraceRaysNV -+#define vkCmdUpdateBuffer plumeVolk_vkCmdUpdateBuffer -+#define vkCmdUpdatePipelineIndirectBufferNV plumeVolk_vkCmdUpdatePipelineIndirectBufferNV -+#define vkCmdWaitEvents plumeVolk_vkCmdWaitEvents -+#define vkCmdWaitEvents2 plumeVolk_vkCmdWaitEvents2 -+#define vkCmdWaitEvents2KHR plumeVolk_vkCmdWaitEvents2KHR -+#define vkCmdWriteAccelerationStructuresPropertiesKHR plumeVolk_vkCmdWriteAccelerationStructuresPropertiesKHR -+#define vkCmdWriteAccelerationStructuresPropertiesNV plumeVolk_vkCmdWriteAccelerationStructuresPropertiesNV -+#define vkCmdWriteBufferMarker2AMD plumeVolk_vkCmdWriteBufferMarker2AMD -+#define vkCmdWriteBufferMarkerAMD plumeVolk_vkCmdWriteBufferMarkerAMD -+#define vkCmdWriteMicromapsPropertiesEXT plumeVolk_vkCmdWriteMicromapsPropertiesEXT -+#define vkCmdWriteTimestamp plumeVolk_vkCmdWriteTimestamp -+#define vkCmdWriteTimestamp2 plumeVolk_vkCmdWriteTimestamp2 -+#define vkCmdWriteTimestamp2KHR plumeVolk_vkCmdWriteTimestamp2KHR -+#define vkCompileDeferredNV plumeVolk_vkCompileDeferredNV -+#define vkConvertCooperativeVectorMatrixNV plumeVolk_vkConvertCooperativeVectorMatrixNV -+#define vkCopyAccelerationStructureKHR plumeVolk_vkCopyAccelerationStructureKHR -+#define vkCopyAccelerationStructureToMemoryKHR plumeVolk_vkCopyAccelerationStructureToMemoryKHR -+#define vkCopyImageToImage plumeVolk_vkCopyImageToImage -+#define vkCopyImageToImageEXT plumeVolk_vkCopyImageToImageEXT -+#define vkCopyImageToMemory plumeVolk_vkCopyImageToMemory -+#define vkCopyImageToMemoryEXT plumeVolk_vkCopyImageToMemoryEXT -+#define vkCopyMemoryToAccelerationStructureKHR plumeVolk_vkCopyMemoryToAccelerationStructureKHR -+#define vkCopyMemoryToImage plumeVolk_vkCopyMemoryToImage -+#define vkCopyMemoryToImageEXT plumeVolk_vkCopyMemoryToImageEXT -+#define vkCopyMemoryToMicromapEXT plumeVolk_vkCopyMemoryToMicromapEXT -+#define vkCopyMicromapEXT plumeVolk_vkCopyMicromapEXT -+#define vkCopyMicromapToMemoryEXT plumeVolk_vkCopyMicromapToMemoryEXT -+#define vkCreateAccelerationStructureKHR plumeVolk_vkCreateAccelerationStructureKHR -+#define vkCreateAccelerationStructureNV plumeVolk_vkCreateAccelerationStructureNV -+#define vkCreateAndroidSurfaceKHR plumeVolk_vkCreateAndroidSurfaceKHR -+#define vkCreateBuffer plumeVolk_vkCreateBuffer -+#define vkCreateBufferCollectionFUCHSIA plumeVolk_vkCreateBufferCollectionFUCHSIA -+#define vkCreateBufferView plumeVolk_vkCreateBufferView -+#define vkCreateCommandPool plumeVolk_vkCreateCommandPool -+#define vkCreateComputePipelines plumeVolk_vkCreateComputePipelines -+#define vkCreateCuFunctionNVX plumeVolk_vkCreateCuFunctionNVX -+#define vkCreateCuModuleNVX plumeVolk_vkCreateCuModuleNVX -+#define vkCreateCudaFunctionNV plumeVolk_vkCreateCudaFunctionNV -+#define vkCreateCudaModuleNV plumeVolk_vkCreateCudaModuleNV -+#define vkCreateDataGraphPipelineSessionARM plumeVolk_vkCreateDataGraphPipelineSessionARM -+#define vkCreateDataGraphPipelinesARM plumeVolk_vkCreateDataGraphPipelinesARM -+#define vkCreateDebugReportCallbackEXT plumeVolk_vkCreateDebugReportCallbackEXT -+#define vkCreateDebugUtilsMessengerEXT plumeVolk_vkCreateDebugUtilsMessengerEXT -+#define vkCreateDeferredOperationKHR plumeVolk_vkCreateDeferredOperationKHR -+#define vkCreateDescriptorPool plumeVolk_vkCreateDescriptorPool -+#define vkCreateDescriptorSetLayout plumeVolk_vkCreateDescriptorSetLayout -+#define vkCreateDescriptorUpdateTemplate plumeVolk_vkCreateDescriptorUpdateTemplate -+#define vkCreateDescriptorUpdateTemplateKHR plumeVolk_vkCreateDescriptorUpdateTemplateKHR -+#define vkCreateDevice plumeVolk_vkCreateDevice -+#define vkCreateDirectFBSurfaceEXT plumeVolk_vkCreateDirectFBSurfaceEXT -+#define vkCreateDisplayModeKHR plumeVolk_vkCreateDisplayModeKHR -+#define vkCreateDisplayPlaneSurfaceKHR plumeVolk_vkCreateDisplayPlaneSurfaceKHR -+#define vkCreateEvent plumeVolk_vkCreateEvent -+#define vkCreateExecutionGraphPipelinesAMDX plumeVolk_vkCreateExecutionGraphPipelinesAMDX -+#define vkCreateExternalComputeQueueNV plumeVolk_vkCreateExternalComputeQueueNV -+#define vkCreateFence plumeVolk_vkCreateFence -+#define vkCreateFramebuffer plumeVolk_vkCreateFramebuffer -+#define vkCreateGraphicsPipelines plumeVolk_vkCreateGraphicsPipelines -+#define vkCreateHeadlessSurfaceEXT plumeVolk_vkCreateHeadlessSurfaceEXT -+#define vkCreateIOSSurfaceMVK plumeVolk_vkCreateIOSSurfaceMVK -+#define vkCreateImage plumeVolk_vkCreateImage -+#define vkCreateImagePipeSurfaceFUCHSIA plumeVolk_vkCreateImagePipeSurfaceFUCHSIA -+#define vkCreateImageView plumeVolk_vkCreateImageView -+#define vkCreateIndirectCommandsLayoutEXT plumeVolk_vkCreateIndirectCommandsLayoutEXT -+#define vkCreateIndirectCommandsLayoutNV plumeVolk_vkCreateIndirectCommandsLayoutNV -+#define vkCreateIndirectExecutionSetEXT plumeVolk_vkCreateIndirectExecutionSetEXT -+#define vkCreateInstance plumeVolk_vkCreateInstance -+#define vkCreateMacOSSurfaceMVK plumeVolk_vkCreateMacOSSurfaceMVK -+#define vkCreateMetalSurfaceEXT plumeVolk_vkCreateMetalSurfaceEXT -+#define vkCreateMicromapEXT plumeVolk_vkCreateMicromapEXT -+#define vkCreateOpticalFlowSessionNV plumeVolk_vkCreateOpticalFlowSessionNV -+#define vkCreatePipelineBinariesKHR plumeVolk_vkCreatePipelineBinariesKHR -+#define vkCreatePipelineCache plumeVolk_vkCreatePipelineCache -+#define vkCreatePipelineLayout plumeVolk_vkCreatePipelineLayout -+#define vkCreatePrivateDataSlot plumeVolk_vkCreatePrivateDataSlot -+#define vkCreatePrivateDataSlotEXT plumeVolk_vkCreatePrivateDataSlotEXT -+#define vkCreateQueryPool plumeVolk_vkCreateQueryPool -+#define vkCreateRayTracingPipelinesKHR plumeVolk_vkCreateRayTracingPipelinesKHR -+#define vkCreateRayTracingPipelinesNV plumeVolk_vkCreateRayTracingPipelinesNV -+#define vkCreateRenderPass plumeVolk_vkCreateRenderPass -+#define vkCreateRenderPass2 plumeVolk_vkCreateRenderPass2 -+#define vkCreateRenderPass2KHR plumeVolk_vkCreateRenderPass2KHR -+#define vkCreateSampler plumeVolk_vkCreateSampler -+#define vkCreateSamplerYcbcrConversion plumeVolk_vkCreateSamplerYcbcrConversion -+#define vkCreateSamplerYcbcrConversionKHR plumeVolk_vkCreateSamplerYcbcrConversionKHR -+#define vkCreateScreenSurfaceQNX plumeVolk_vkCreateScreenSurfaceQNX -+#define vkCreateSemaphore plumeVolk_vkCreateSemaphore -+#define vkCreateShaderModule plumeVolk_vkCreateShaderModule -+#define vkCreateShadersEXT plumeVolk_vkCreateShadersEXT -+#define vkCreateSharedSwapchainsKHR plumeVolk_vkCreateSharedSwapchainsKHR -+#define vkCreateStreamDescriptorSurfaceGGP plumeVolk_vkCreateStreamDescriptorSurfaceGGP -+#define vkCreateSurfaceOHOS plumeVolk_vkCreateSurfaceOHOS -+#define vkCreateSwapchainKHR plumeVolk_vkCreateSwapchainKHR -+#define vkCreateTensorARM plumeVolk_vkCreateTensorARM -+#define vkCreateTensorViewARM plumeVolk_vkCreateTensorViewARM -+#define vkCreateValidationCacheEXT plumeVolk_vkCreateValidationCacheEXT -+#define vkCreateViSurfaceNN plumeVolk_vkCreateViSurfaceNN -+#define vkCreateVideoSessionKHR plumeVolk_vkCreateVideoSessionKHR -+#define vkCreateVideoSessionParametersKHR plumeVolk_vkCreateVideoSessionParametersKHR -+#define vkCreateWaylandSurfaceKHR plumeVolk_vkCreateWaylandSurfaceKHR -+#define vkCreateWin32SurfaceKHR plumeVolk_vkCreateWin32SurfaceKHR -+#define vkCreateXcbSurfaceKHR plumeVolk_vkCreateXcbSurfaceKHR -+#define vkCreateXlibSurfaceKHR plumeVolk_vkCreateXlibSurfaceKHR -+#define vkDebugMarkerSetObjectNameEXT plumeVolk_vkDebugMarkerSetObjectNameEXT -+#define vkDebugMarkerSetObjectTagEXT plumeVolk_vkDebugMarkerSetObjectTagEXT -+#define vkDebugReportMessageEXT plumeVolk_vkDebugReportMessageEXT -+#define vkDeferredOperationJoinKHR plumeVolk_vkDeferredOperationJoinKHR -+#define vkDestroyAccelerationStructureKHR plumeVolk_vkDestroyAccelerationStructureKHR -+#define vkDestroyAccelerationStructureNV plumeVolk_vkDestroyAccelerationStructureNV -+#define vkDestroyBuffer plumeVolk_vkDestroyBuffer -+#define vkDestroyBufferCollectionFUCHSIA plumeVolk_vkDestroyBufferCollectionFUCHSIA -+#define vkDestroyBufferView plumeVolk_vkDestroyBufferView -+#define vkDestroyCommandPool plumeVolk_vkDestroyCommandPool -+#define vkDestroyCuFunctionNVX plumeVolk_vkDestroyCuFunctionNVX -+#define vkDestroyCuModuleNVX plumeVolk_vkDestroyCuModuleNVX -+#define vkDestroyCudaFunctionNV plumeVolk_vkDestroyCudaFunctionNV -+#define vkDestroyCudaModuleNV plumeVolk_vkDestroyCudaModuleNV -+#define vkDestroyDataGraphPipelineSessionARM plumeVolk_vkDestroyDataGraphPipelineSessionARM -+#define vkDestroyDebugReportCallbackEXT plumeVolk_vkDestroyDebugReportCallbackEXT -+#define vkDestroyDebugUtilsMessengerEXT plumeVolk_vkDestroyDebugUtilsMessengerEXT -+#define vkDestroyDeferredOperationKHR plumeVolk_vkDestroyDeferredOperationKHR -+#define vkDestroyDescriptorPool plumeVolk_vkDestroyDescriptorPool -+#define vkDestroyDescriptorSetLayout plumeVolk_vkDestroyDescriptorSetLayout -+#define vkDestroyDescriptorUpdateTemplate plumeVolk_vkDestroyDescriptorUpdateTemplate -+#define vkDestroyDescriptorUpdateTemplateKHR plumeVolk_vkDestroyDescriptorUpdateTemplateKHR -+#define vkDestroyDevice plumeVolk_vkDestroyDevice -+#define vkDestroyEvent plumeVolk_vkDestroyEvent -+#define vkDestroyExternalComputeQueueNV plumeVolk_vkDestroyExternalComputeQueueNV -+#define vkDestroyFence plumeVolk_vkDestroyFence -+#define vkDestroyFramebuffer plumeVolk_vkDestroyFramebuffer -+#define vkDestroyImage plumeVolk_vkDestroyImage -+#define vkDestroyImageView plumeVolk_vkDestroyImageView -+#define vkDestroyIndirectCommandsLayoutEXT plumeVolk_vkDestroyIndirectCommandsLayoutEXT -+#define vkDestroyIndirectCommandsLayoutNV plumeVolk_vkDestroyIndirectCommandsLayoutNV -+#define vkDestroyIndirectExecutionSetEXT plumeVolk_vkDestroyIndirectExecutionSetEXT -+#define vkDestroyInstance plumeVolk_vkDestroyInstance -+#define vkDestroyMicromapEXT plumeVolk_vkDestroyMicromapEXT -+#define vkDestroyOpticalFlowSessionNV plumeVolk_vkDestroyOpticalFlowSessionNV -+#define vkDestroyPipeline plumeVolk_vkDestroyPipeline -+#define vkDestroyPipelineBinaryKHR plumeVolk_vkDestroyPipelineBinaryKHR -+#define vkDestroyPipelineCache plumeVolk_vkDestroyPipelineCache -+#define vkDestroyPipelineLayout plumeVolk_vkDestroyPipelineLayout -+#define vkDestroyPrivateDataSlot plumeVolk_vkDestroyPrivateDataSlot -+#define vkDestroyPrivateDataSlotEXT plumeVolk_vkDestroyPrivateDataSlotEXT -+#define vkDestroyQueryPool plumeVolk_vkDestroyQueryPool -+#define vkDestroyRenderPass plumeVolk_vkDestroyRenderPass -+#define vkDestroySampler plumeVolk_vkDestroySampler -+#define vkDestroySamplerYcbcrConversion plumeVolk_vkDestroySamplerYcbcrConversion -+#define vkDestroySamplerYcbcrConversionKHR plumeVolk_vkDestroySamplerYcbcrConversionKHR -+#define vkDestroySemaphore plumeVolk_vkDestroySemaphore -+#define vkDestroyShaderEXT plumeVolk_vkDestroyShaderEXT -+#define vkDestroyShaderModule plumeVolk_vkDestroyShaderModule -+#define vkDestroySurfaceKHR plumeVolk_vkDestroySurfaceKHR -+#define vkDestroySwapchainKHR plumeVolk_vkDestroySwapchainKHR -+#define vkDestroyTensorARM plumeVolk_vkDestroyTensorARM -+#define vkDestroyTensorViewARM plumeVolk_vkDestroyTensorViewARM -+#define vkDestroyValidationCacheEXT plumeVolk_vkDestroyValidationCacheEXT -+#define vkDestroyVideoSessionKHR plumeVolk_vkDestroyVideoSessionKHR -+#define vkDestroyVideoSessionParametersKHR plumeVolk_vkDestroyVideoSessionParametersKHR -+#define vkDeviceWaitIdle plumeVolk_vkDeviceWaitIdle -+#define vkDisplayPowerControlEXT plumeVolk_vkDisplayPowerControlEXT -+#define vkEndCommandBuffer plumeVolk_vkEndCommandBuffer -+#define vkEnumerateDeviceExtensionProperties plumeVolk_vkEnumerateDeviceExtensionProperties -+#define vkEnumerateDeviceLayerProperties plumeVolk_vkEnumerateDeviceLayerProperties -+#define vkEnumerateInstanceExtensionProperties plumeVolk_vkEnumerateInstanceExtensionProperties -+#define vkEnumerateInstanceLayerProperties plumeVolk_vkEnumerateInstanceLayerProperties -+#define vkEnumerateInstanceVersion plumeVolk_vkEnumerateInstanceVersion -+#define vkEnumeratePhysicalDeviceGroups plumeVolk_vkEnumeratePhysicalDeviceGroups -+#define vkEnumeratePhysicalDeviceGroupsKHR plumeVolk_vkEnumeratePhysicalDeviceGroupsKHR -+#define vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR plumeVolk_vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR -+#define vkEnumeratePhysicalDevices plumeVolk_vkEnumeratePhysicalDevices -+#define vkExportMetalObjectsEXT plumeVolk_vkExportMetalObjectsEXT -+#define vkFlushMappedMemoryRanges plumeVolk_vkFlushMappedMemoryRanges -+#define vkFreeCommandBuffers plumeVolk_vkFreeCommandBuffers -+#define vkFreeDescriptorSets plumeVolk_vkFreeDescriptorSets -+#define vkFreeMemory plumeVolk_vkFreeMemory -+#define vkGetAccelerationStructureBuildSizesKHR plumeVolk_vkGetAccelerationStructureBuildSizesKHR -+#define vkGetAccelerationStructureDeviceAddressKHR plumeVolk_vkGetAccelerationStructureDeviceAddressKHR -+#define vkGetAccelerationStructureHandleNV plumeVolk_vkGetAccelerationStructureHandleNV -+#define vkGetAccelerationStructureMemoryRequirementsNV plumeVolk_vkGetAccelerationStructureMemoryRequirementsNV -+#define vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT plumeVolk_vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT -+#define vkGetAndroidHardwareBufferPropertiesANDROID plumeVolk_vkGetAndroidHardwareBufferPropertiesANDROID -+#define vkGetBufferCollectionPropertiesFUCHSIA plumeVolk_vkGetBufferCollectionPropertiesFUCHSIA -+#define vkGetBufferDeviceAddress plumeVolk_vkGetBufferDeviceAddress -+#define vkGetBufferDeviceAddressEXT plumeVolk_vkGetBufferDeviceAddressEXT -+#define vkGetBufferDeviceAddressKHR plumeVolk_vkGetBufferDeviceAddressKHR -+#define vkGetBufferMemoryRequirements plumeVolk_vkGetBufferMemoryRequirements -+#define vkGetBufferMemoryRequirements2 plumeVolk_vkGetBufferMemoryRequirements2 -+#define vkGetBufferMemoryRequirements2KHR plumeVolk_vkGetBufferMemoryRequirements2KHR -+#define vkGetBufferOpaqueCaptureAddress plumeVolk_vkGetBufferOpaqueCaptureAddress -+#define vkGetBufferOpaqueCaptureAddressKHR plumeVolk_vkGetBufferOpaqueCaptureAddressKHR -+#define vkGetBufferOpaqueCaptureDescriptorDataEXT plumeVolk_vkGetBufferOpaqueCaptureDescriptorDataEXT -+#define vkGetCalibratedTimestampsEXT plumeVolk_vkGetCalibratedTimestampsEXT -+#define vkGetCalibratedTimestampsKHR plumeVolk_vkGetCalibratedTimestampsKHR -+#define vkGetClusterAccelerationStructureBuildSizesNV plumeVolk_vkGetClusterAccelerationStructureBuildSizesNV -+#define vkGetCudaModuleCacheNV plumeVolk_vkGetCudaModuleCacheNV -+#define vkGetDataGraphPipelineAvailablePropertiesARM plumeVolk_vkGetDataGraphPipelineAvailablePropertiesARM -+#define vkGetDataGraphPipelinePropertiesARM plumeVolk_vkGetDataGraphPipelinePropertiesARM -+#define vkGetDataGraphPipelineSessionBindPointRequirementsARM plumeVolk_vkGetDataGraphPipelineSessionBindPointRequirementsARM -+#define vkGetDataGraphPipelineSessionMemoryRequirementsARM plumeVolk_vkGetDataGraphPipelineSessionMemoryRequirementsARM -+#define vkGetDeferredOperationMaxConcurrencyKHR plumeVolk_vkGetDeferredOperationMaxConcurrencyKHR -+#define vkGetDeferredOperationResultKHR plumeVolk_vkGetDeferredOperationResultKHR -+#define vkGetDescriptorEXT plumeVolk_vkGetDescriptorEXT -+#define vkGetDescriptorSetHostMappingVALVE plumeVolk_vkGetDescriptorSetHostMappingVALVE -+#define vkGetDescriptorSetLayoutBindingOffsetEXT plumeVolk_vkGetDescriptorSetLayoutBindingOffsetEXT -+#define vkGetDescriptorSetLayoutHostMappingInfoVALVE plumeVolk_vkGetDescriptorSetLayoutHostMappingInfoVALVE -+#define vkGetDescriptorSetLayoutSizeEXT plumeVolk_vkGetDescriptorSetLayoutSizeEXT -+#define vkGetDescriptorSetLayoutSupport plumeVolk_vkGetDescriptorSetLayoutSupport -+#define vkGetDescriptorSetLayoutSupportKHR plumeVolk_vkGetDescriptorSetLayoutSupportKHR -+#define vkGetDeviceAccelerationStructureCompatibilityKHR plumeVolk_vkGetDeviceAccelerationStructureCompatibilityKHR -+#define vkGetDeviceBufferMemoryRequirements plumeVolk_vkGetDeviceBufferMemoryRequirements -+#define vkGetDeviceBufferMemoryRequirementsKHR plumeVolk_vkGetDeviceBufferMemoryRequirementsKHR -+#define vkGetDeviceFaultInfoEXT plumeVolk_vkGetDeviceFaultInfoEXT -+#define vkGetDeviceGroupPeerMemoryFeatures plumeVolk_vkGetDeviceGroupPeerMemoryFeatures -+#define vkGetDeviceGroupPeerMemoryFeaturesKHR plumeVolk_vkGetDeviceGroupPeerMemoryFeaturesKHR -+#define vkGetDeviceGroupPresentCapabilitiesKHR plumeVolk_vkGetDeviceGroupPresentCapabilitiesKHR -+#define vkGetDeviceGroupSurfacePresentModes2EXT plumeVolk_vkGetDeviceGroupSurfacePresentModes2EXT -+#define vkGetDeviceGroupSurfacePresentModesKHR plumeVolk_vkGetDeviceGroupSurfacePresentModesKHR -+#define vkGetDeviceImageMemoryRequirements plumeVolk_vkGetDeviceImageMemoryRequirements -+#define vkGetDeviceImageMemoryRequirementsKHR plumeVolk_vkGetDeviceImageMemoryRequirementsKHR -+#define vkGetDeviceImageSparseMemoryRequirements plumeVolk_vkGetDeviceImageSparseMemoryRequirements -+#define vkGetDeviceImageSparseMemoryRequirementsKHR plumeVolk_vkGetDeviceImageSparseMemoryRequirementsKHR -+#define vkGetDeviceImageSubresourceLayout plumeVolk_vkGetDeviceImageSubresourceLayout -+#define vkGetDeviceImageSubresourceLayoutKHR plumeVolk_vkGetDeviceImageSubresourceLayoutKHR -+#define vkGetDeviceMemoryCommitment plumeVolk_vkGetDeviceMemoryCommitment -+#define vkGetDeviceMemoryOpaqueCaptureAddress plumeVolk_vkGetDeviceMemoryOpaqueCaptureAddress -+#define vkGetDeviceMemoryOpaqueCaptureAddressKHR plumeVolk_vkGetDeviceMemoryOpaqueCaptureAddressKHR -+#define vkGetDeviceMicromapCompatibilityEXT plumeVolk_vkGetDeviceMicromapCompatibilityEXT -+#define vkGetDeviceProcAddr plumeVolk_vkGetDeviceProcAddr -+#define vkGetDeviceQueue plumeVolk_vkGetDeviceQueue -+#define vkGetDeviceQueue2 plumeVolk_vkGetDeviceQueue2 -+#define vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI plumeVolk_vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI -+#define vkGetDeviceTensorMemoryRequirementsARM plumeVolk_vkGetDeviceTensorMemoryRequirementsARM -+#define vkGetDisplayModeProperties2KHR plumeVolk_vkGetDisplayModeProperties2KHR -+#define vkGetDisplayModePropertiesKHR plumeVolk_vkGetDisplayModePropertiesKHR -+#define vkGetDisplayPlaneCapabilities2KHR plumeVolk_vkGetDisplayPlaneCapabilities2KHR -+#define vkGetDisplayPlaneCapabilitiesKHR plumeVolk_vkGetDisplayPlaneCapabilitiesKHR -+#define vkGetDisplayPlaneSupportedDisplaysKHR plumeVolk_vkGetDisplayPlaneSupportedDisplaysKHR -+#define vkGetDrmDisplayEXT plumeVolk_vkGetDrmDisplayEXT -+#define vkGetDynamicRenderingTilePropertiesQCOM plumeVolk_vkGetDynamicRenderingTilePropertiesQCOM -+#define vkGetEncodedVideoSessionParametersKHR plumeVolk_vkGetEncodedVideoSessionParametersKHR -+#define vkGetEventStatus plumeVolk_vkGetEventStatus -+#define vkGetExecutionGraphPipelineNodeIndexAMDX plumeVolk_vkGetExecutionGraphPipelineNodeIndexAMDX -+#define vkGetExecutionGraphPipelineScratchSizeAMDX plumeVolk_vkGetExecutionGraphPipelineScratchSizeAMDX -+#define vkGetExternalComputeQueueDataNV plumeVolk_vkGetExternalComputeQueueDataNV -+#define vkGetFenceFdKHR plumeVolk_vkGetFenceFdKHR -+#define vkGetFenceStatus plumeVolk_vkGetFenceStatus -+#define vkGetFenceWin32HandleKHR plumeVolk_vkGetFenceWin32HandleKHR -+#define vkGetFramebufferTilePropertiesQCOM plumeVolk_vkGetFramebufferTilePropertiesQCOM -+#define vkGetGeneratedCommandsMemoryRequirementsEXT plumeVolk_vkGetGeneratedCommandsMemoryRequirementsEXT -+#define vkGetGeneratedCommandsMemoryRequirementsNV plumeVolk_vkGetGeneratedCommandsMemoryRequirementsNV -+#define vkGetImageDrmFormatModifierPropertiesEXT plumeVolk_vkGetImageDrmFormatModifierPropertiesEXT -+#define vkGetImageMemoryRequirements plumeVolk_vkGetImageMemoryRequirements -+#define vkGetImageMemoryRequirements2 plumeVolk_vkGetImageMemoryRequirements2 -+#define vkGetImageMemoryRequirements2KHR plumeVolk_vkGetImageMemoryRequirements2KHR -+#define vkGetImageOpaqueCaptureDescriptorDataEXT plumeVolk_vkGetImageOpaqueCaptureDescriptorDataEXT -+#define vkGetImageSparseMemoryRequirements plumeVolk_vkGetImageSparseMemoryRequirements -+#define vkGetImageSparseMemoryRequirements2 plumeVolk_vkGetImageSparseMemoryRequirements2 -+#define vkGetImageSparseMemoryRequirements2KHR plumeVolk_vkGetImageSparseMemoryRequirements2KHR -+#define vkGetImageSubresourceLayout plumeVolk_vkGetImageSubresourceLayout -+#define vkGetImageSubresourceLayout2 plumeVolk_vkGetImageSubresourceLayout2 -+#define vkGetImageSubresourceLayout2EXT plumeVolk_vkGetImageSubresourceLayout2EXT -+#define vkGetImageSubresourceLayout2KHR plumeVolk_vkGetImageSubresourceLayout2KHR -+#define vkGetImageViewAddressNVX plumeVolk_vkGetImageViewAddressNVX -+#define vkGetImageViewHandle64NVX plumeVolk_vkGetImageViewHandle64NVX -+#define vkGetImageViewHandleNVX plumeVolk_vkGetImageViewHandleNVX -+#define vkGetImageViewOpaqueCaptureDescriptorDataEXT plumeVolk_vkGetImageViewOpaqueCaptureDescriptorDataEXT -+#define vkGetInstanceProcAddr plumeVolk_vkGetInstanceProcAddr -+#define vkGetLatencyTimingsNV plumeVolk_vkGetLatencyTimingsNV -+#define vkGetMemoryAndroidHardwareBufferANDROID plumeVolk_vkGetMemoryAndroidHardwareBufferANDROID -+#define vkGetMemoryFdKHR plumeVolk_vkGetMemoryFdKHR -+#define vkGetMemoryFdPropertiesKHR plumeVolk_vkGetMemoryFdPropertiesKHR -+#define vkGetMemoryHostPointerPropertiesEXT plumeVolk_vkGetMemoryHostPointerPropertiesEXT -+#define vkGetMemoryMetalHandleEXT plumeVolk_vkGetMemoryMetalHandleEXT -+#define vkGetMemoryMetalHandlePropertiesEXT plumeVolk_vkGetMemoryMetalHandlePropertiesEXT -+#define vkGetMemoryRemoteAddressNV plumeVolk_vkGetMemoryRemoteAddressNV -+#define vkGetMemoryWin32HandleKHR plumeVolk_vkGetMemoryWin32HandleKHR -+#define vkGetMemoryWin32HandleNV plumeVolk_vkGetMemoryWin32HandleNV -+#define vkGetMemoryWin32HandlePropertiesKHR plumeVolk_vkGetMemoryWin32HandlePropertiesKHR -+#define vkGetMemoryZirconHandleFUCHSIA plumeVolk_vkGetMemoryZirconHandleFUCHSIA -+#define vkGetMemoryZirconHandlePropertiesFUCHSIA plumeVolk_vkGetMemoryZirconHandlePropertiesFUCHSIA -+#define vkGetMicromapBuildSizesEXT plumeVolk_vkGetMicromapBuildSizesEXT -+#define vkGetPartitionedAccelerationStructuresBuildSizesNV plumeVolk_vkGetPartitionedAccelerationStructuresBuildSizesNV -+#define vkGetPastPresentationTimingGOOGLE plumeVolk_vkGetPastPresentationTimingGOOGLE -+#define vkGetPerformanceParameterINTEL plumeVolk_vkGetPerformanceParameterINTEL -+#define vkGetPhysicalDeviceCalibrateableTimeDomainsEXT plumeVolk_vkGetPhysicalDeviceCalibrateableTimeDomainsEXT -+#define vkGetPhysicalDeviceCalibrateableTimeDomainsKHR plumeVolk_vkGetPhysicalDeviceCalibrateableTimeDomainsKHR -+#define vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV plumeVolk_vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV -+#define vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR plumeVolk_vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR -+#define vkGetPhysicalDeviceCooperativeMatrixPropertiesNV plumeVolk_vkGetPhysicalDeviceCooperativeMatrixPropertiesNV -+#define vkGetPhysicalDeviceCooperativeVectorPropertiesNV plumeVolk_vkGetPhysicalDeviceCooperativeVectorPropertiesNV -+#define vkGetPhysicalDeviceDirectFBPresentationSupportEXT plumeVolk_vkGetPhysicalDeviceDirectFBPresentationSupportEXT -+#define vkGetPhysicalDeviceDisplayPlaneProperties2KHR plumeVolk_vkGetPhysicalDeviceDisplayPlaneProperties2KHR -+#define vkGetPhysicalDeviceDisplayPlanePropertiesKHR plumeVolk_vkGetPhysicalDeviceDisplayPlanePropertiesKHR -+#define vkGetPhysicalDeviceDisplayProperties2KHR plumeVolk_vkGetPhysicalDeviceDisplayProperties2KHR -+#define vkGetPhysicalDeviceDisplayPropertiesKHR plumeVolk_vkGetPhysicalDeviceDisplayPropertiesKHR -+#define vkGetPhysicalDeviceExternalBufferProperties plumeVolk_vkGetPhysicalDeviceExternalBufferProperties -+#define vkGetPhysicalDeviceExternalBufferPropertiesKHR plumeVolk_vkGetPhysicalDeviceExternalBufferPropertiesKHR -+#define vkGetPhysicalDeviceExternalFenceProperties plumeVolk_vkGetPhysicalDeviceExternalFenceProperties -+#define vkGetPhysicalDeviceExternalFencePropertiesKHR plumeVolk_vkGetPhysicalDeviceExternalFencePropertiesKHR -+#define vkGetPhysicalDeviceExternalImageFormatPropertiesNV plumeVolk_vkGetPhysicalDeviceExternalImageFormatPropertiesNV -+#define vkGetPhysicalDeviceExternalSemaphoreProperties plumeVolk_vkGetPhysicalDeviceExternalSemaphoreProperties -+#define vkGetPhysicalDeviceExternalSemaphorePropertiesKHR plumeVolk_vkGetPhysicalDeviceExternalSemaphorePropertiesKHR -+#define vkGetPhysicalDeviceExternalTensorPropertiesARM plumeVolk_vkGetPhysicalDeviceExternalTensorPropertiesARM -+#define vkGetPhysicalDeviceFeatures plumeVolk_vkGetPhysicalDeviceFeatures -+#define vkGetPhysicalDeviceFeatures2 plumeVolk_vkGetPhysicalDeviceFeatures2 -+#define vkGetPhysicalDeviceFeatures2KHR plumeVolk_vkGetPhysicalDeviceFeatures2KHR -+#define vkGetPhysicalDeviceFormatProperties plumeVolk_vkGetPhysicalDeviceFormatProperties -+#define vkGetPhysicalDeviceFormatProperties2 plumeVolk_vkGetPhysicalDeviceFormatProperties2 -+#define vkGetPhysicalDeviceFormatProperties2KHR plumeVolk_vkGetPhysicalDeviceFormatProperties2KHR -+#define vkGetPhysicalDeviceFragmentShadingRatesKHR plumeVolk_vkGetPhysicalDeviceFragmentShadingRatesKHR -+#define vkGetPhysicalDeviceImageFormatProperties plumeVolk_vkGetPhysicalDeviceImageFormatProperties -+#define vkGetPhysicalDeviceImageFormatProperties2 plumeVolk_vkGetPhysicalDeviceImageFormatProperties2 -+#define vkGetPhysicalDeviceImageFormatProperties2KHR plumeVolk_vkGetPhysicalDeviceImageFormatProperties2KHR -+#define vkGetPhysicalDeviceMemoryProperties plumeVolk_vkGetPhysicalDeviceMemoryProperties -+#define vkGetPhysicalDeviceMemoryProperties2 plumeVolk_vkGetPhysicalDeviceMemoryProperties2 -+#define vkGetPhysicalDeviceMemoryProperties2KHR plumeVolk_vkGetPhysicalDeviceMemoryProperties2KHR -+#define vkGetPhysicalDeviceMultisamplePropertiesEXT plumeVolk_vkGetPhysicalDeviceMultisamplePropertiesEXT -+#define vkGetPhysicalDeviceOpticalFlowImageFormatsNV plumeVolk_vkGetPhysicalDeviceOpticalFlowImageFormatsNV -+#define vkGetPhysicalDevicePresentRectanglesKHR plumeVolk_vkGetPhysicalDevicePresentRectanglesKHR -+#define vkGetPhysicalDeviceProperties plumeVolk_vkGetPhysicalDeviceProperties -+#define vkGetPhysicalDeviceProperties2 plumeVolk_vkGetPhysicalDeviceProperties2 -+#define vkGetPhysicalDeviceProperties2KHR plumeVolk_vkGetPhysicalDeviceProperties2KHR -+#define vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM plumeVolk_vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM -+#define vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM plumeVolk_vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM -+#define vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR plumeVolk_vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR -+#define vkGetPhysicalDeviceQueueFamilyProperties plumeVolk_vkGetPhysicalDeviceQueueFamilyProperties -+#define vkGetPhysicalDeviceQueueFamilyProperties2 plumeVolk_vkGetPhysicalDeviceQueueFamilyProperties2 -+#define vkGetPhysicalDeviceQueueFamilyProperties2KHR plumeVolk_vkGetPhysicalDeviceQueueFamilyProperties2KHR -+#define vkGetPhysicalDeviceScreenPresentationSupportQNX plumeVolk_vkGetPhysicalDeviceScreenPresentationSupportQNX -+#define vkGetPhysicalDeviceSparseImageFormatProperties plumeVolk_vkGetPhysicalDeviceSparseImageFormatProperties -+#define vkGetPhysicalDeviceSparseImageFormatProperties2 plumeVolk_vkGetPhysicalDeviceSparseImageFormatProperties2 -+#define vkGetPhysicalDeviceSparseImageFormatProperties2KHR plumeVolk_vkGetPhysicalDeviceSparseImageFormatProperties2KHR -+#define vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV plumeVolk_vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV -+#define vkGetPhysicalDeviceSurfaceCapabilities2EXT plumeVolk_vkGetPhysicalDeviceSurfaceCapabilities2EXT -+#define vkGetPhysicalDeviceSurfaceCapabilities2KHR plumeVolk_vkGetPhysicalDeviceSurfaceCapabilities2KHR -+#define vkGetPhysicalDeviceSurfaceCapabilitiesKHR plumeVolk_vkGetPhysicalDeviceSurfaceCapabilitiesKHR -+#define vkGetPhysicalDeviceSurfaceFormats2KHR plumeVolk_vkGetPhysicalDeviceSurfaceFormats2KHR -+#define vkGetPhysicalDeviceSurfaceFormatsKHR plumeVolk_vkGetPhysicalDeviceSurfaceFormatsKHR -+#define vkGetPhysicalDeviceSurfacePresentModes2EXT plumeVolk_vkGetPhysicalDeviceSurfacePresentModes2EXT -+#define vkGetPhysicalDeviceSurfacePresentModesKHR plumeVolk_vkGetPhysicalDeviceSurfacePresentModesKHR -+#define vkGetPhysicalDeviceSurfaceSupportKHR plumeVolk_vkGetPhysicalDeviceSurfaceSupportKHR -+#define vkGetPhysicalDeviceToolProperties plumeVolk_vkGetPhysicalDeviceToolProperties -+#define vkGetPhysicalDeviceToolPropertiesEXT plumeVolk_vkGetPhysicalDeviceToolPropertiesEXT -+#define vkGetPhysicalDeviceVideoCapabilitiesKHR plumeVolk_vkGetPhysicalDeviceVideoCapabilitiesKHR -+#define vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR plumeVolk_vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR -+#define vkGetPhysicalDeviceVideoFormatPropertiesKHR plumeVolk_vkGetPhysicalDeviceVideoFormatPropertiesKHR -+#define vkGetPhysicalDeviceWaylandPresentationSupportKHR plumeVolk_vkGetPhysicalDeviceWaylandPresentationSupportKHR -+#define vkGetPhysicalDeviceWin32PresentationSupportKHR plumeVolk_vkGetPhysicalDeviceWin32PresentationSupportKHR -+#define vkGetPhysicalDeviceXcbPresentationSupportKHR plumeVolk_vkGetPhysicalDeviceXcbPresentationSupportKHR -+#define vkGetPhysicalDeviceXlibPresentationSupportKHR plumeVolk_vkGetPhysicalDeviceXlibPresentationSupportKHR -+#define vkGetPipelineBinaryDataKHR plumeVolk_vkGetPipelineBinaryDataKHR -+#define vkGetPipelineCacheData plumeVolk_vkGetPipelineCacheData -+#define vkGetPipelineExecutableInternalRepresentationsKHR plumeVolk_vkGetPipelineExecutableInternalRepresentationsKHR -+#define vkGetPipelineExecutablePropertiesKHR plumeVolk_vkGetPipelineExecutablePropertiesKHR -+#define vkGetPipelineExecutableStatisticsKHR plumeVolk_vkGetPipelineExecutableStatisticsKHR -+#define vkGetPipelineIndirectDeviceAddressNV plumeVolk_vkGetPipelineIndirectDeviceAddressNV -+#define vkGetPipelineIndirectMemoryRequirementsNV plumeVolk_vkGetPipelineIndirectMemoryRequirementsNV -+#define vkGetPipelineKeyKHR plumeVolk_vkGetPipelineKeyKHR -+#define vkGetPipelinePropertiesEXT plumeVolk_vkGetPipelinePropertiesEXT -+#define vkGetPrivateData plumeVolk_vkGetPrivateData -+#define vkGetPrivateDataEXT plumeVolk_vkGetPrivateDataEXT -+#define vkGetQueryPoolResults plumeVolk_vkGetQueryPoolResults -+#define vkGetQueueCheckpointData2NV plumeVolk_vkGetQueueCheckpointData2NV -+#define vkGetQueueCheckpointDataNV plumeVolk_vkGetQueueCheckpointDataNV -+#define vkGetRandROutputDisplayEXT plumeVolk_vkGetRandROutputDisplayEXT -+#define vkGetRayTracingCaptureReplayShaderGroupHandlesKHR plumeVolk_vkGetRayTracingCaptureReplayShaderGroupHandlesKHR -+#define vkGetRayTracingShaderGroupHandlesKHR plumeVolk_vkGetRayTracingShaderGroupHandlesKHR -+#define vkGetRayTracingShaderGroupHandlesNV plumeVolk_vkGetRayTracingShaderGroupHandlesNV -+#define vkGetRayTracingShaderGroupStackSizeKHR plumeVolk_vkGetRayTracingShaderGroupStackSizeKHR -+#define vkGetRefreshCycleDurationGOOGLE plumeVolk_vkGetRefreshCycleDurationGOOGLE -+#define vkGetRenderAreaGranularity plumeVolk_vkGetRenderAreaGranularity -+#define vkGetRenderingAreaGranularity plumeVolk_vkGetRenderingAreaGranularity -+#define vkGetRenderingAreaGranularityKHR plumeVolk_vkGetRenderingAreaGranularityKHR -+#define vkGetSamplerOpaqueCaptureDescriptorDataEXT plumeVolk_vkGetSamplerOpaqueCaptureDescriptorDataEXT -+#define vkGetScreenBufferPropertiesQNX plumeVolk_vkGetScreenBufferPropertiesQNX -+#define vkGetSemaphoreCounterValue plumeVolk_vkGetSemaphoreCounterValue -+#define vkGetSemaphoreCounterValueKHR plumeVolk_vkGetSemaphoreCounterValueKHR -+#define vkGetSemaphoreFdKHR plumeVolk_vkGetSemaphoreFdKHR -+#define vkGetSemaphoreWin32HandleKHR plumeVolk_vkGetSemaphoreWin32HandleKHR -+#define vkGetSemaphoreZirconHandleFUCHSIA plumeVolk_vkGetSemaphoreZirconHandleFUCHSIA -+#define vkGetShaderBinaryDataEXT plumeVolk_vkGetShaderBinaryDataEXT -+#define vkGetShaderInfoAMD plumeVolk_vkGetShaderInfoAMD -+#define vkGetShaderModuleCreateInfoIdentifierEXT plumeVolk_vkGetShaderModuleCreateInfoIdentifierEXT -+#define vkGetShaderModuleIdentifierEXT plumeVolk_vkGetShaderModuleIdentifierEXT -+#define vkGetSwapchainCounterEXT plumeVolk_vkGetSwapchainCounterEXT -+#define vkGetSwapchainImagesKHR plumeVolk_vkGetSwapchainImagesKHR -+#define vkGetSwapchainStatusKHR plumeVolk_vkGetSwapchainStatusKHR -+#define vkGetTensorMemoryRequirementsARM plumeVolk_vkGetTensorMemoryRequirementsARM -+#define vkGetTensorOpaqueCaptureDescriptorDataARM plumeVolk_vkGetTensorOpaqueCaptureDescriptorDataARM -+#define vkGetTensorViewOpaqueCaptureDescriptorDataARM plumeVolk_vkGetTensorViewOpaqueCaptureDescriptorDataARM -+#define vkGetValidationCacheDataEXT plumeVolk_vkGetValidationCacheDataEXT -+#define vkGetVideoSessionMemoryRequirementsKHR plumeVolk_vkGetVideoSessionMemoryRequirementsKHR -+#define vkGetWinrtDisplayNV plumeVolk_vkGetWinrtDisplayNV -+#define vkImportFenceFdKHR plumeVolk_vkImportFenceFdKHR -+#define vkImportFenceWin32HandleKHR plumeVolk_vkImportFenceWin32HandleKHR -+#define vkImportSemaphoreFdKHR plumeVolk_vkImportSemaphoreFdKHR -+#define vkImportSemaphoreWin32HandleKHR plumeVolk_vkImportSemaphoreWin32HandleKHR -+#define vkImportSemaphoreZirconHandleFUCHSIA plumeVolk_vkImportSemaphoreZirconHandleFUCHSIA -+#define vkInitializePerformanceApiINTEL plumeVolk_vkInitializePerformanceApiINTEL -+#define vkInvalidateMappedMemoryRanges plumeVolk_vkInvalidateMappedMemoryRanges -+#define vkLatencySleepNV plumeVolk_vkLatencySleepNV -+#define vkMapMemory plumeVolk_vkMapMemory -+#define vkMapMemory2 plumeVolk_vkMapMemory2 -+#define vkMapMemory2KHR plumeVolk_vkMapMemory2KHR -+#define vkMergePipelineCaches plumeVolk_vkMergePipelineCaches -+#define vkMergeValidationCachesEXT plumeVolk_vkMergeValidationCachesEXT -+#define vkQueueBeginDebugUtilsLabelEXT plumeVolk_vkQueueBeginDebugUtilsLabelEXT -+#define vkQueueBindSparse plumeVolk_vkQueueBindSparse -+#define vkQueueEndDebugUtilsLabelEXT plumeVolk_vkQueueEndDebugUtilsLabelEXT -+#define vkQueueInsertDebugUtilsLabelEXT plumeVolk_vkQueueInsertDebugUtilsLabelEXT -+#define vkQueueNotifyOutOfBandNV plumeVolk_vkQueueNotifyOutOfBandNV -+#define vkQueuePresentKHR plumeVolk_vkQueuePresentKHR -+#define vkQueueSetPerformanceConfigurationINTEL plumeVolk_vkQueueSetPerformanceConfigurationINTEL -+#define vkQueueSubmit plumeVolk_vkQueueSubmit -+#define vkQueueSubmit2 plumeVolk_vkQueueSubmit2 -+#define vkQueueSubmit2KHR plumeVolk_vkQueueSubmit2KHR -+#define vkQueueWaitIdle plumeVolk_vkQueueWaitIdle -+#define vkRegisterDeviceEventEXT plumeVolk_vkRegisterDeviceEventEXT -+#define vkRegisterDisplayEventEXT plumeVolk_vkRegisterDisplayEventEXT -+#define vkReleaseCapturedPipelineDataKHR plumeVolk_vkReleaseCapturedPipelineDataKHR -+#define vkReleaseDisplayEXT plumeVolk_vkReleaseDisplayEXT -+#define vkReleaseFullScreenExclusiveModeEXT plumeVolk_vkReleaseFullScreenExclusiveModeEXT -+#define vkReleasePerformanceConfigurationINTEL plumeVolk_vkReleasePerformanceConfigurationINTEL -+#define vkReleaseProfilingLockKHR plumeVolk_vkReleaseProfilingLockKHR -+#define vkReleaseSwapchainImagesEXT plumeVolk_vkReleaseSwapchainImagesEXT -+#define vkReleaseSwapchainImagesKHR plumeVolk_vkReleaseSwapchainImagesKHR -+#define vkResetCommandBuffer plumeVolk_vkResetCommandBuffer -+#define vkResetCommandPool plumeVolk_vkResetCommandPool -+#define vkResetDescriptorPool plumeVolk_vkResetDescriptorPool -+#define vkResetEvent plumeVolk_vkResetEvent -+#define vkResetFences plumeVolk_vkResetFences -+#define vkResetQueryPool plumeVolk_vkResetQueryPool -+#define vkResetQueryPoolEXT plumeVolk_vkResetQueryPoolEXT -+#define vkSetBufferCollectionBufferConstraintsFUCHSIA plumeVolk_vkSetBufferCollectionBufferConstraintsFUCHSIA -+#define vkSetBufferCollectionImageConstraintsFUCHSIA plumeVolk_vkSetBufferCollectionImageConstraintsFUCHSIA -+#define vkSetDebugUtilsObjectNameEXT plumeVolk_vkSetDebugUtilsObjectNameEXT -+#define vkSetDebugUtilsObjectTagEXT plumeVolk_vkSetDebugUtilsObjectTagEXT -+#define vkSetDeviceMemoryPriorityEXT plumeVolk_vkSetDeviceMemoryPriorityEXT -+#define vkSetEvent plumeVolk_vkSetEvent -+#define vkSetHdrMetadataEXT plumeVolk_vkSetHdrMetadataEXT -+#define vkSetLatencyMarkerNV plumeVolk_vkSetLatencyMarkerNV -+#define vkSetLatencySleepModeNV plumeVolk_vkSetLatencySleepModeNV -+#define vkSetLocalDimmingAMD plumeVolk_vkSetLocalDimmingAMD -+#define vkSetPrivateData plumeVolk_vkSetPrivateData -+#define vkSetPrivateDataEXT plumeVolk_vkSetPrivateDataEXT -+#define vkSignalSemaphore plumeVolk_vkSignalSemaphore -+#define vkSignalSemaphoreKHR plumeVolk_vkSignalSemaphoreKHR -+#define vkSubmitDebugUtilsMessageEXT plumeVolk_vkSubmitDebugUtilsMessageEXT -+#define vkTransitionImageLayout plumeVolk_vkTransitionImageLayout -+#define vkTransitionImageLayoutEXT plumeVolk_vkTransitionImageLayoutEXT -+#define vkTrimCommandPool plumeVolk_vkTrimCommandPool -+#define vkTrimCommandPoolKHR plumeVolk_vkTrimCommandPoolKHR -+#define vkUninitializePerformanceApiINTEL plumeVolk_vkUninitializePerformanceApiINTEL -+#define vkUnmapMemory plumeVolk_vkUnmapMemory -+#define vkUnmapMemory2 plumeVolk_vkUnmapMemory2 -+#define vkUnmapMemory2KHR plumeVolk_vkUnmapMemory2KHR -+#define vkUpdateDescriptorSetWithTemplate plumeVolk_vkUpdateDescriptorSetWithTemplate -+#define vkUpdateDescriptorSetWithTemplateKHR plumeVolk_vkUpdateDescriptorSetWithTemplateKHR -+#define vkUpdateDescriptorSets plumeVolk_vkUpdateDescriptorSets -+#define vkUpdateIndirectExecutionSetPipelineEXT plumeVolk_vkUpdateIndirectExecutionSetPipelineEXT -+#define vkUpdateIndirectExecutionSetShaderEXT plumeVolk_vkUpdateIndirectExecutionSetShaderEXT -+#define vkUpdateVideoSessionParametersKHR plumeVolk_vkUpdateVideoSessionParametersKHR -+#define vkWaitForFences plumeVolk_vkWaitForFences -+#define vkWaitForPresent2KHR plumeVolk_vkWaitForPresent2KHR -+#define vkWaitForPresentKHR plumeVolk_vkWaitForPresentKHR -+#define vkWaitSemaphores plumeVolk_vkWaitSemaphores -+#define vkWaitSemaphoresKHR plumeVolk_vkWaitSemaphoresKHR -+#define vkWriteAccelerationStructuresPropertiesKHR plumeVolk_vkWriteAccelerationStructuresPropertiesKHR -+#define vkWriteMicromapsPropertiesEXT plumeVolk_vkWriteMicromapsPropertiesEXT diff --git a/tools/patches/xenonrecomp-ios-streaming-memory-map.patch b/tools/patches/xenonrecomp-ios-streaming-memory-map.patch new file mode 100644 index 00000000..926533bb --- /dev/null +++ b/tools/patches/xenonrecomp-ios-streaming-memory-map.patch @@ -0,0 +1,185 @@ +diff --git a/XenonUtils/memory_mapped_file.cpp b/XenonUtils/memory_mapped_file.cpp +index ba3c5d8..530321d 100644 +--- a/XenonUtils/memory_mapped_file.cpp ++++ b/XenonUtils/memory_mapped_file.cpp +@@ -1,5 +1,7 @@ + #include "memory_mapped_file.h" + ++#include ++ + #if !defined(_WIN32) + # include + # include +@@ -34,14 +36,19 @@ MemoryMappedFile::MemoryMappedFile(MemoryMappedFile &&other) + other.fileMappingHandle = nullptr; + other.fileView = nullptr; + other.fileSize.QuadPart = 0; ++ other.streamingMode = false; + #else + fileHandle = other.fileHandle; + fileView = other.fileView; + fileSize = other.fileSize; ++ mappedLength = other.mappedLength; ++ streamingMode = other.streamingMode; + + other.fileHandle = -1; + other.fileView = MAP_FAILED; + other.fileSize = 0; ++ other.mappedLength = 0; ++ other.streamingMode = false; + #endif + } + +@@ -103,14 +110,23 @@ bool MemoryMappedFile::open(const std::filesystem::path &path) + } + + fileView = mmap(nullptr, fileSize, PROT_READ, MAP_PRIVATE, fileHandle, 0); +- if (fileView == MAP_FAILED) ++ if (fileView != MAP_FAILED) + { +- fprintf(stderr, "mmap failed with error %s.\n", strerror(errno)); +- ::close(fileHandle); +- fileHandle = -1; +- return false; ++ mappedLength = fileSize; ++ return true; + } + ++ static constexpr size_t PartialMapSize = 128 * 1024 * 1024; ++ const size_t partialMapSize = std::min(static_cast(fileSize), PartialMapSize); ++ fileView = mmap(nullptr, partialMapSize, PROT_READ, MAP_PRIVATE, fileHandle, 0); ++ if (fileView != MAP_FAILED) ++ { ++ mappedLength = static_cast(partialMapSize); ++ return true; ++ } ++ ++ fprintf(stderr, "mmap failed with error %s, falling back to streaming I/O.\n", strerror(errno)); ++ streamingMode = true; + return true; + #endif + } +@@ -135,7 +151,7 @@ void MemoryMappedFile::close() + #else + if (fileView != MAP_FAILED) + { +- munmap(fileView, fileSize); ++ munmap(fileView, mappedLength); + } + + if (fileHandle != -1) +@@ -148,14 +164,86 @@ void MemoryMappedFile::close() + bool MemoryMappedFile::isOpen() const + { + #if defined(_WIN32) +- return (fileView != nullptr); ++ return (fileView != nullptr) || (streamingMode && fileHandle != nullptr); ++#else ++ return (fileView != MAP_FAILED) || (streamingMode && fileHandle != -1); ++#endif ++} ++ ++bool MemoryMappedFile::readAt(size_t offset, void *buffer, size_t size) const ++{ ++ if (!isOpen() || buffer == nullptr) ++ return false; ++ ++ if (static_cast(offset) < 0 || static_cast(offset + size) > fileSize) ++ return false; ++ ++#if defined(_WIN32) ++ if (fileView != nullptr) ++ { ++ memcpy(buffer, reinterpret_cast(fileView) + offset, size); ++ return true; ++ } ++ ++ if (!streamingMode || fileHandle == nullptr) ++ return false; ++ ++ OVERLAPPED overlapped = {}; ++ overlapped.Offset = static_cast(offset & 0xFFFFFFFF); ++ overlapped.OffsetHigh = static_cast(offset >> 32); ++ DWORD bytesRead = 0; ++ if (!ReadFile(fileHandle, buffer, static_cast(size), &bytesRead, &overlapped) || bytesRead != size) ++ return false; ++ ++ return true; + #else +- return (fileView != MAP_FAILED); ++ if (fileView != MAP_FAILED) ++ { ++ const size_t mappedEnd = static_cast(mappedLength); ++ if (offset + size <= mappedEnd) ++ { ++ memcpy(buffer, reinterpret_cast(fileView) + offset, size); ++ return true; ++ } ++ ++ if (offset >= mappedEnd) ++ { ++ return pread(fileHandle, buffer, size, static_cast(offset)) == static_cast(size); ++ } ++ ++ const size_t mappedBytes = mappedEnd - offset; ++ memcpy(buffer, reinterpret_cast(fileView) + offset, mappedBytes); ++ const size_t remainingBytes = size - mappedBytes; ++ return pread(fileHandle, static_cast(buffer) + mappedBytes, remainingBytes, static_cast(mappedEnd)) == static_cast(remainingBytes); ++ } ++ ++ if (!streamingMode || fileHandle == -1) ++ return false; ++ ++ size_t bytesRead = 0; ++ while (bytesRead < size) ++ { ++ const ssize_t result = pread(fileHandle, static_cast(buffer) + bytesRead, size - bytesRead, static_cast(offset + bytesRead)); ++ if (result <= 0) ++ return false; ++ ++ bytesRead += static_cast(result); ++ } ++ ++ return true; + #endif + } + + uint8_t *MemoryMappedFile::data() const + { ++#if defined(_WIN32) ++ if (fileView == nullptr) ++ return nullptr; ++#else ++ if (fileView == MAP_FAILED) ++ return nullptr; ++#endif ++ + return reinterpret_cast(fileView); + } + +diff --git a/XenonUtils/memory_mapped_file.h b/XenonUtils/memory_mapped_file.h +index a3de88b..640cc42 100644 +--- a/XenonUtils/memory_mapped_file.h ++++ b/XenonUtils/memory_mapped_file.h +@@ -14,10 +14,13 @@ struct MemoryMappedFile { + HANDLE fileMappingHandle = nullptr; + LPVOID fileView = nullptr; + LARGE_INTEGER fileSize = {}; ++ bool streamingMode = false; + #else + int fileHandle = -1; + void *fileView = MAP_FAILED; + off_t fileSize = 0; ++ off_t mappedLength = 0; ++ bool streamingMode = false; + #endif + + MemoryMappedFile(); +@@ -27,6 +30,7 @@ struct MemoryMappedFile { + bool open(const std::filesystem::path &path); + void close(); + bool isOpen() const; ++ bool readAt(size_t offset, void *buffer, size_t size) const; + uint8_t *data() const; + size_t size() const; + };