Improve iOS touch controls and IPA runtime

This commit is contained in:
aperezro 2026-06-07 18:05:30 -06:00
parent 7996b86141
commit ecf0763f13
27 changed files with 1621 additions and 1018 deletions

View file

@ -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} "$<TARGET_FILE:${TARGET_NAME}>" 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} "$<TARGET_FILE:${TARGET_NAME}>" 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}"
"$<TARGET_BUNDLE_DIR:UnleashedRecomp>"
)
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}"
"$<TARGET_BUNDLE_DIR:UnleashedRecomp>"
)
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}

View file

@ -27,6 +27,8 @@
#include <ui/options_menu.h>
#include <ui/game_window.h>
#include <ui/black_bar.h>
#include <ui/touch_controls.h>
#include <ui/input_coords.h>
#include <patches/aspect_ratio_patches.h>
#include <user/config.h>
#include <sdl_listener.h>
@ -1645,6 +1647,39 @@ static void ApplyLowEndDefault(ConfigDef<T> &configDef, T newDefault, bool &chan
configDef.DefaultValue = newDefault;
}
#ifdef UNLEASHED_RECOMP_IOS
template<typename T, bool isHidden>
static void ApplyIOSDefault(ConfigDef<T, isHidden>& 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();

View file

@ -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

View file

@ -4,6 +4,7 @@
#include <hid/hid.h>
#include <os/logger.h>
#include <ui/game_window.h>
#include <ui/touch_controls.h>
#include <kernel/xdm.h>
#include <app.h>
@ -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;

View file

@ -1,5 +1,7 @@
#include "hid.h"
#include <ui/game_window.h>
#include <ui/installer_wizard.h>
#include <ui/message_window.h>
#include <user/config.h>
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;
}

View file

@ -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<char *>(fileData), size);
return !fileStream.fail() && static_cast<size_t>(fileStream.gcount()) == size;
}
size_t getSize(const std::string &path) const override
{
std::error_code ec;

View file

@ -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<uint8_t> &fileData, Journal &journal, const std::function<bool()> &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<bool()> &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<uint8_t> 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<const char *>(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<const FilePair> filePairs, const uint64_t *f
uint32_t validationHashIndex = 0;
uint32_t hashIndex = 0;
uint32_t hashCount = 0;
std::vector<uint8_t> fileData;
for (FilePair pair : filePairs)
{
hashIndex = hashCount;
@ -460,7 +487,7 @@ bool Installer::copyFiles(std::span<const FilePair> 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<const FilePair> 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<bool()> &progressCallback)
bool Installer::install(Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function<bool()> &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;

View file

@ -81,7 +81,7 @@ struct Installer
static bool copyFiles(std::span<const FilePair> filePairs, const uint64_t *fileHashes, VirtualFileSystem &sourceVfs, const std::filesystem::path &targetDirectory, const std::string &validationFile, bool skipHashChecks, Journal &journal, const std::function<bool()> &progressCallback);
static bool parseContent(const std::filesystem::path &sourcePath, std::unique_ptr<VirtualFileSystem> &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<bool()> &progressCallback);
static bool install(Sources &sources, const std::filesystem::path &targetDirectory, bool skipHashChecks, Journal &journal, std::chrono::seconds endWaitTime, const std::function<bool()> &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.

View file

@ -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, &sector, 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);

View file

@ -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;

View file

@ -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;

View file

@ -13,6 +13,7 @@
#include "xcontent_file_system.h"
#include <bit>
#include <cstddef>
#include <fstream>
#include <set>
#include <stack>
@ -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<const XContentContainerHeader *>(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<IterationStep> 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<MemoryMappedFile> &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;

View file

@ -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;

View file

@ -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

View file

@ -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.");

View file

@ -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()

View file

@ -0,0 +1,61 @@
#include "input_coords.h"
#include <gpu/video.h>
#include <ui/game_window.h>
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;
}

View file

@ -0,0 +1,8 @@
#pragma once
#include <imgui.h>
#include <SDL.h>
ImVec2 TransformWindowPointToViewport(float x, float y);
ImVec2 GetViewportPointFromSDLEvent(const SDL_Event* event);
bool IsPointInRect(const ImVec2& point, const ImVec2& min, const ImVec2& max);

View file

@ -15,6 +15,7 @@
#include <ui/game_window.h>
#include <decompressor.h>
#include <exports.h>
#include <ui/input_coords.h>
#include <sdl_listener.h>
#include <res/images/common/hedge-dev.dds.h>
@ -124,6 +125,14 @@ static std::atomic<bool> g_installerHalted = false;
static std::atomic<bool> g_installerCancelled = false;
static bool g_installerFailed = false;
static std::string g_installerErrorMessage;
static std::atomic<bool> g_parseSourcesActive = false;
static std::atomic<bool> g_parseSourcesFinished = false;
static std::atomic<bool> g_parseSourcesSuccess = false;
static std::string g_parseSourcesErrorMessage;
static std::unique_ptr<std::thread> 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 &currentRect = 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<std::thread>(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::thread>([]()
{
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();

View file

@ -0,0 +1,583 @@
#include "touch_controls.h"
#include <stdafx.h>
#include <app.h>
#include <gpu/video.h>
#include <hid/hid.h>
#include <patches/aspect_ratio_patches.h>
#include <ui/game_window.h>
#include <ui/imgui_utils.h>
#include <ui/input_coords.h>
#include <ui/installer_wizard.h>
#include <user/config.h>
#include <sdl_listener.h>
#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<VirtualButton> 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

View file

@ -0,0 +1,12 @@
#pragma once
#include <xbox.h>
namespace TouchControls
{
void Init();
void Draw();
bool IsActive();
bool IsEnabled();
XAMINPUT_GAMEPAD GetState();
}

View file

@ -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);

View file

@ -1,9 +1,27 @@
#include "paths.h"
#include <os/process.h>
#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");

View file

@ -10,6 +10,8 @@
extern std::filesystem::path g_executableRoot;
void InitPaths();
bool CheckPortable();
std::filesystem::path BuildUserPath();
const std::filesystem::path& GetUserPath();

View file

@ -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

View file

@ -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<std::string> getRequiredDeviceExtensions(uint32_t apiVersion) {
+ std::unordered_set<std::string> 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<std::string> requiredDeviceExtensions = getRequiredDeviceExtensions(selectedDeviceProperties.apiVersion);
+
// Check for extensions.
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr);
@@ -3761,7 +3791,7 @@ namespace plume {
std::vector<VkExtensionProperties> availableExtensions(extensionCount);
vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, availableExtensions.data());
- std::unordered_set<std::string> missingRequiredExtensions = RequiredDeviceExtensions;
+ std::unordered_set<std::string> missingRequiredExtensions = requiredDeviceExtensions;
std::unordered_set<std::string> supportedOptionalExtensions;
# if DLSS_ENABLED
const std::unordered_set<std::string> dlssExtensions = DLSS::getRequiredDeviceExtensionsVulkan(this);
@@ -3969,7 +3999,7 @@ namespace plume {
}
std::vector<const char *> 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<CocoaWindow> 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

View file

@ -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 <algorithm>
+
#if !defined(_WIN32)
# include <cstring>
# include <cstdio>
@@ -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<size_t>(fileSize), PartialMapSize);
+ fileView = mmap(nullptr, partialMapSize, PROT_READ, MAP_PRIVATE, fileHandle, 0);
+ if (fileView != MAP_FAILED)
+ {
+ mappedLength = static_cast<off_t>(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<off_t>(offset) < 0 || static_cast<off_t>(offset + size) > fileSize)
+ return false;
+
+#if defined(_WIN32)
+ if (fileView != nullptr)
+ {
+ memcpy(buffer, reinterpret_cast<const uint8_t *>(fileView) + offset, size);
+ return true;
+ }
+
+ if (!streamingMode || fileHandle == nullptr)
+ return false;
+
+ OVERLAPPED overlapped = {};
+ overlapped.Offset = static_cast<DWORD>(offset & 0xFFFFFFFF);
+ overlapped.OffsetHigh = static_cast<DWORD>(offset >> 32);
+ DWORD bytesRead = 0;
+ if (!ReadFile(fileHandle, buffer, static_cast<DWORD>(size), &bytesRead, &overlapped) || bytesRead != size)
+ return false;
+
+ return true;
#else
- return (fileView != MAP_FAILED);
+ if (fileView != MAP_FAILED)
+ {
+ const size_t mappedEnd = static_cast<size_t>(mappedLength);
+ if (offset + size <= mappedEnd)
+ {
+ memcpy(buffer, reinterpret_cast<const uint8_t *>(fileView) + offset, size);
+ return true;
+ }
+
+ if (offset >= mappedEnd)
+ {
+ return pread(fileHandle, buffer, size, static_cast<off_t>(offset)) == static_cast<ssize_t>(size);
+ }
+
+ const size_t mappedBytes = mappedEnd - offset;
+ memcpy(buffer, reinterpret_cast<const uint8_t *>(fileView) + offset, mappedBytes);
+ const size_t remainingBytes = size - mappedBytes;
+ return pread(fileHandle, static_cast<uint8_t *>(buffer) + mappedBytes, remainingBytes, static_cast<off_t>(mappedEnd)) == static_cast<ssize_t>(remainingBytes);
+ }
+
+ if (!streamingMode || fileHandle == -1)
+ return false;
+
+ size_t bytesRead = 0;
+ while (bytesRead < size)
+ {
+ const ssize_t result = pread(fileHandle, static_cast<uint8_t *>(buffer) + bytesRead, size - bytesRead, static_cast<off_t>(offset + bytesRead));
+ if (result <= 0)
+ return false;
+
+ bytesRead += static_cast<size_t>(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<uint8_t *>(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;
};