diff --git a/CMakeLists.txt b/CMakeLists.txt index f3346293..f9024689 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,7 +212,7 @@ else() if(WOWEE_ENABLE_AMD_FSR3_FRAMEGEN) if(EXISTS ${WOWEE_AMD_FFX_SDK_KITS_FG_HEADER}) message(STATUS "FidelityFX-SDK Kits layout detected at ${WOWEE_AMD_FFX_SDK_KITS_DIR}, " - "but legacy sdk/include headers required by WoWee FSR3 probe/wrapper are not present. " + "but legacy sdk/include headers required by WoWee FSR3 probe/runtime are not present. " "FSR3 framegen interface probe disabled.") else() message(WARNING "AMD FidelityFX-SDK framegen headers not found at ${WOWEE_AMD_FFX_SDK_DIR}; " diff --git a/README.md b/README.md index 24b5ff2b..ab2ba60a 100644 --- a/README.md +++ b/README.md @@ -200,37 +200,12 @@ make -j$(nproc) - `WOWEE_ENABLE_AMD_FSR3_FRAMEGEN=ON` enables a compile-probe target (`wowee_fsr3_framegen_amd_vk_probe`) that validates SDK FI/OF/FSR3/Vulkan interface headers at build time. - Runtime toggle: - In settings, `AMD FSR3 Frame Generation (Experimental)` persists to config. - - Runtime library auto-probe checks for `libffx_fsr3_vk`/`ffx_fsr3_vk` in default loader paths. - - Override runtime library path with: - - `WOWEE_FFX_SDK_RUNTIME_LIB=/absolute/path/to/libffx_fsr3_vk.so` (platform extension varies). - - Wrapper override path: - - `WOWEE_FFX_SDK_RUNTIME_WRAPPER_LIB=/absolute/path/to/libffx_fsr3_vk_wrapper.so` (platform extension varies). - - In-tree wrapper build: - - `wowee_fsr3_vk_wrapper` now builds automatically when FSR3 SDK headers are present and outputs to `build/bin/libffx_fsr3_vk_wrapper.*`. - - Wrapper backend override (what the wrapper loads underneath): `WOWEE_FSR3_WRAPPER_BACKEND_LIB=/absolute/path/to/libffx_fsr3_vk.so`. - - Wrapper backend mode: - - `WOWEE_FSR3_WRAPPER_BACKEND=vulkan_runtime` (default on all platforms) - - `WOWEE_FSR3_WRAPPER_BACKEND=dx12_bridge` (opt-in) - - If backend mode is not explicitly set and Vulkan-runtime backend loading fails, wrapper now auto-falls back to `dx12_bridge` on Windows and Linux. - - DX12 runtime override (for `dx12_bridge`): - - `WOWEE_FSR3_DX12_RUNTIME_LIB=C:\\path\\to\\amd_fidelityfx_framegeneration_dx12.dll` - - DX12 device validation probe (default on): - - `WOWEE_FSR3_WRAPPER_DX12_VALIDATE_DEVICE=1` - - Set to `0` to skip adapter/device preflight. - - Windows `dx12_bridge` preflight checks Vulkan Win32 interop funcs/extensions before enabling DX12 path. - - Linux `dx12_bridge` is enabled for wrapper runtime compatibility mode and uses Vulkan dispatch symbols in this build. - - Linux `dx12_bridge` preflight validates Vulkan FD interop funcs/extensions: - - `vkGetMemoryFdKHR`, `vkGetSemaphoreFdKHR` - - `VK_KHR_external_memory`, `VK_KHR_external_memory_fd`, `VK_KHR_external_semaphore`, `VK_KHR_external_semaphore_fd` - - Path B wrapper libraries must export the clean wrapper ABI (`include/rendering/amd_fsr3_wrapper_abi.h`): - - ABI version is currently `3` (dispatch includes external-memory/semaphore handles plus acquire/release fence values for bridge sync). - - `wowee_fsr3_wrapper_get_abi_version` - - `wowee_fsr3_wrapper_get_backend` - - `wowee_fsr3_wrapper_initialize` - - `wowee_fsr3_wrapper_dispatch_upscale` - - `wowee_fsr3_wrapper_shutdown` - - Optional FG hook: `wowee_fsr3_wrapper_dispatch_framegen` - - Optional diagnostics: `wowee_fsr3_wrapper_get_last_error`, `wowee_fsr3_wrapper_get_capabilities` + - Runtime library loader is Path A only (official AMD runtime). + - Auto-probe checks common names (for example `amd_fidelityfx_vk` / `ffx_fsr3_vk`) in loader paths. + - Override runtime path with: + - `WOWEE_FFX_SDK_RUNTIME_LIB=/absolute/path/to/` + - If runtime is missing, FG is cleanly unavailable (Path C). + ### Current FSR Defaults diff --git a/docs/AMD_FSR2_INTEGRATION.md b/docs/AMD_FSR2_INTEGRATION.md index 695a64ca..9f37ef9c 100644 --- a/docs/AMD_FSR2_INTEGRATION.md +++ b/docs/AMD_FSR2_INTEGRATION.md @@ -40,50 +40,12 @@ Detection expects: Runtime note: -- Renderer/UI now expose a persisted experimental framegen toggle. -- Runtime loader now supports: - - Path A: AMD SDK runtime binaries (`ffx_fsr3_vk`). - - Path B: wrapper runtime libraries implementing WoWee's wrapper ABI. +- Renderer/UI expose a persisted experimental framegen toggle. +- Runtime loader is Path A only (official AMD runtime library). - You can point to an explicit runtime binary with: - `WOWEE_FFX_SDK_RUNTIME_LIB=/absolute/path/to/libffx_fsr3_vk.so` (or `.dll` / `.dylib`). -- You can point to an explicit wrapper binary with: - - `WOWEE_FFX_SDK_RUNTIME_WRAPPER_LIB=/absolute/path/to/libffx_fsr3_vk_wrapper.so` (or `.dll` / `.dylib`). -- WoWee now ships an in-tree wrapper target: - - `wowee_fsr3_vk_wrapper` (output in `build/bin`). -- Wrapper backend runtime override: - - `WOWEE_FSR3_WRAPPER_BACKEND_LIB=/absolute/path/to/libffx_fsr3_vk.so` (or `.dll` / `.dylib`). -- Wrapper backend mode selection: - - `WOWEE_FSR3_WRAPPER_BACKEND=vulkan_runtime` - - `WOWEE_FSR3_WRAPPER_BACKEND=dx12_bridge` -- Default is `vulkan_runtime` on all platforms. -- If backend mode is not explicitly set and Vulkan-runtime backend loading fails, wrapper auto-falls back to `dx12_bridge` on Windows and Linux. -- `dx12_bridge` is opt-in. -- On Windows: `dx12_bridge` performs DX12/Vulkan preflight, then loads the first runtime library exposing the required FSR3 dispatch exports. -- On Linux: `dx12_bridge` is enabled for wrapper runtime compatibility mode and uses Vulkan dispatch symbols in this build. -- Linux bridge preflight validates Vulkan FD interop support: - - required device functions: `vkGetMemoryFdKHR`, `vkGetSemaphoreFdKHR` - - required device extensions: `VK_KHR_external_memory`, `VK_KHR_external_memory_fd`, `VK_KHR_external_semaphore`, `VK_KHR_external_semaphore_fd` -- DX12 bridge runtime override: - - `WOWEE_FSR3_DX12_RUNTIME_LIB=` -- DX12 bridge device preflight toggle: - - `WOWEE_FSR3_WRAPPER_DX12_VALIDATE_DEVICE=1` (default) - - `WOWEE_FSR3_WRAPPER_DX12_VALIDATE_DEVICE=0` to skip DXGI/D3D12 device creation probe -- DX12 bridge preflight also validates Vulkan Win32 interop support: - - required device functions: `vkGetMemoryWin32HandleKHR`, `vkImportSemaphoreWin32HandleKHR`, `vkGetSemaphoreWin32HandleKHR` - - required device extensions: `VK_KHR_external_memory`, `VK_KHR_external_memory_win32`, `VK_KHR_external_semaphore`, `VK_KHR_external_semaphore_win32` -- Path B wrapper ABI contract is declared in: - - `include/rendering/amd_fsr3_wrapper_abi.h` -- Current wrapper ABI version: `3` (dispatch payload carries external memory/semaphore handles and acquire/release fence values for bridge synchronization). -- Required wrapper exports: - - `wowee_fsr3_wrapper_get_abi_version` - - `wowee_fsr3_wrapper_get_backend` - - `wowee_fsr3_wrapper_initialize` - - `wowee_fsr3_wrapper_dispatch_upscale` - - `wowee_fsr3_wrapper_shutdown` -- Optional wrapper export: - - `wowee_fsr3_wrapper_dispatch_framegen` - - `wowee_fsr3_wrapper_get_last_error` - - `wowee_fsr3_wrapper_get_capabilities` +- If no official runtime is found, frame generation is disabled cleanly (Path C). + ## Current Status diff --git a/include/rendering/amd_fsr3_runtime.hpp b/include/rendering/amd_fsr3_runtime.hpp index 44bd20b3..c2b379d7 100644 --- a/include/rendering/amd_fsr3_runtime.hpp +++ b/include/rendering/amd_fsr3_runtime.hpp @@ -44,24 +44,13 @@ struct AmdFsr3RuntimeDispatchDesc { float cameraFar = 1000.0f; float cameraFovYRadians = 1.0f; bool reset = false; - uint32_t externalFlags = 0; - uint64_t colorMemoryHandle = 0; - uint64_t depthMemoryHandle = 0; - uint64_t motionVectorMemoryHandle = 0; - uint64_t outputMemoryHandle = 0; - uint64_t frameGenOutputMemoryHandle = 0; - uint64_t acquireSemaphoreHandle = 0; - uint64_t releaseSemaphoreHandle = 0; - uint64_t acquireSemaphoreValue = 0; - uint64_t releaseSemaphoreValue = 0; }; class AmdFsr3Runtime { public: enum class LoadPathKind { None, - Official, - Wrapper + Official }; AmdFsr3Runtime(); @@ -76,18 +65,9 @@ public: bool isFrameGenerationReady() const { return frameGenerationReady_; } const std::string& loadedLibraryPath() const { return loadedLibraryPath_; } LoadPathKind loadPathKind() const { return loadPathKind_; } - const std::string& wrapperBackendName() const { return wrapperBackendName_; } - uint32_t wrapperCapabilities() const { return wrapperCapabilities_; } - bool hasWrapperExternalInterop() const; const std::string& lastError() const { return lastError_; } private: - enum class RuntimeBackend { - None, - Official, - Wrapper - }; - void* libHandle_ = nullptr; std::string loadedLibraryPath_; void* scratchBuffer_ = nullptr; @@ -95,15 +75,11 @@ private: bool ready_ = false; bool frameGenerationReady_ = false; LoadPathKind loadPathKind_ = LoadPathKind::None; - std::string wrapperBackendName_; - uint32_t wrapperCapabilities_ = 0; std::string lastError_; struct RuntimeFns; RuntimeFns* fns_ = nullptr; void* contextStorage_ = nullptr; - void* wrapperContext_ = nullptr; - RuntimeBackend backend_ = RuntimeBackend::None; }; } // namespace wowee::rendering diff --git a/include/rendering/amd_fsr3_wrapper_abi.h b/include/rendering/amd_fsr3_wrapper_abi.h deleted file mode 100644 index 7cf94201..00000000 --- a/include/rendering/amd_fsr3_wrapper_abi.h +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define WOWEE_FSR3_WRAPPER_ABI_VERSION 3u - -typedef void* WoweeFsr3WrapperContext; - -typedef struct WoweeFsr3WrapperInitDesc { - uint32_t structSize; - uint32_t abiVersion; - VkPhysicalDevice physicalDevice; - VkDevice device; - PFN_vkGetDeviceProcAddr getDeviceProcAddr; - uint32_t maxRenderWidth; - uint32_t maxRenderHeight; - uint32_t displayWidth; - uint32_t displayHeight; - VkFormat colorFormat; - uint32_t enableFlags; -} WoweeFsr3WrapperInitDesc; - -typedef struct WoweeFsr3WrapperDispatchDesc { - uint32_t structSize; - VkCommandBuffer commandBuffer; - VkImage colorImage; - VkImage depthImage; - VkImage motionVectorImage; - VkImage outputImage; - VkImage frameGenOutputImage; - uint32_t renderWidth; - uint32_t renderHeight; - uint32_t outputWidth; - uint32_t outputHeight; - VkFormat colorFormat; - VkFormat depthFormat; - VkFormat motionVectorFormat; - VkFormat outputFormat; - float jitterX; - float jitterY; - float motionScaleX; - float motionScaleY; - float frameTimeDeltaMs; - float cameraNear; - float cameraFar; - float cameraFovYRadians; - uint32_t reset; - uint32_t externalFlags; - uint64_t colorMemoryHandle; - uint64_t depthMemoryHandle; - uint64_t motionVectorMemoryHandle; - uint64_t outputMemoryHandle; - uint64_t frameGenOutputMemoryHandle; - uint64_t acquireSemaphoreHandle; - uint64_t releaseSemaphoreHandle; - uint64_t acquireSemaphoreValue; - uint64_t releaseSemaphoreValue; -} WoweeFsr3WrapperDispatchDesc; - -enum { - WOWEE_FSR3_WRAPPER_ENABLE_HDR_INPUT = 1u << 0, - WOWEE_FSR3_WRAPPER_ENABLE_DEPTH_INVERTED = 1u << 1, - WOWEE_FSR3_WRAPPER_ENABLE_FRAME_GENERATION = 1u << 2 -}; - -enum { - WOWEE_FSR3_WRAPPER_EXTERNAL_COLOR_MEMORY = 1u << 0, - WOWEE_FSR3_WRAPPER_EXTERNAL_DEPTH_MEMORY = 1u << 1, - WOWEE_FSR3_WRAPPER_EXTERNAL_MOTION_MEMORY = 1u << 2, - WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY = 1u << 3, - WOWEE_FSR3_WRAPPER_EXTERNAL_FRAMEGEN_OUTPUT_MEMORY = 1u << 4, - WOWEE_FSR3_WRAPPER_EXTERNAL_ACQUIRE_SEMAPHORE = 1u << 5, - WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE = 1u << 6 -}; - -enum { - WOWEE_FSR3_WRAPPER_CAP_UPSCALE = 1u << 0, - WOWEE_FSR3_WRAPPER_CAP_FRAME_GENERATION = 1u << 1, - WOWEE_FSR3_WRAPPER_CAP_EXTERNAL_INTEROP = 1u << 2 -}; - -uint32_t wowee_fsr3_wrapper_get_abi_version(void); -const char* wowee_fsr3_wrapper_get_name(void); -const char* wowee_fsr3_wrapper_get_backend(WoweeFsr3WrapperContext context); -uint32_t wowee_fsr3_wrapper_get_capabilities(WoweeFsr3WrapperContext context); -int32_t wowee_fsr3_wrapper_initialize(const WoweeFsr3WrapperInitDesc* initDesc, - WoweeFsr3WrapperContext* outContext, - char* outErrorText, - uint32_t outErrorTextCapacity); -int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3WrapperContext context, - const WoweeFsr3WrapperDispatchDesc* dispatchDesc); -int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3WrapperContext context, - const WoweeFsr3WrapperDispatchDesc* dispatchDesc); -void wowee_fsr3_wrapper_shutdown(WoweeFsr3WrapperContext context); -const char* wowee_fsr3_wrapper_get_last_error(WoweeFsr3WrapperContext context); - -#ifdef __cplusplus -} -#endif diff --git a/src/rendering/amd_fsr3_runtime.cpp b/src/rendering/amd_fsr3_runtime.cpp index 3e03436b..dd2499ca 100644 --- a/src/rendering/amd_fsr3_runtime.cpp +++ b/src/rendering/amd_fsr3_runtime.cpp @@ -1,5 +1,4 @@ #include "rendering/amd_fsr3_runtime.hpp" -#include "rendering/amd_fsr3_wrapper_abi.h" #include #include @@ -30,16 +29,6 @@ namespace wowee::rendering { #if WOWEE_HAS_AMD_FSR3_FRAMEGEN struct AmdFsr3Runtime::RuntimeFns { - uint32_t (*wrapperGetAbiVersion)() = nullptr; - const char* (*wrapperGetName)() = nullptr; - const char* (*wrapperGetBackend)(WoweeFsr3WrapperContext) = nullptr; - uint32_t (*wrapperGetCapabilities)(WoweeFsr3WrapperContext) = nullptr; - int32_t (*wrapperInitialize)(const WoweeFsr3WrapperInitDesc*, WoweeFsr3WrapperContext*, char*, uint32_t) = nullptr; - int32_t (*wrapperDispatchUpscale)(WoweeFsr3WrapperContext, const WoweeFsr3WrapperDispatchDesc*) = nullptr; - int32_t (*wrapperDispatchFramegen)(WoweeFsr3WrapperContext, const WoweeFsr3WrapperDispatchDesc*) = nullptr; - void (*wrapperShutdown)(WoweeFsr3WrapperContext) = nullptr; - const char* (*wrapperGetLastError)(WoweeFsr3WrapperContext) = nullptr; - decltype(&ffxGetScratchMemorySizeVK) getScratchMemorySizeVK = nullptr; decltype(&ffxGetDeviceVK) getDeviceVK = nullptr; decltype(&ffxGetInterfaceVK) getInterfaceVK = nullptr; @@ -61,8 +50,6 @@ AmdFsr3Runtime::~AmdFsr3Runtime() { shutdown(); } -bool AmdFsr3Runtime::hasWrapperExternalInterop() const { return false; } - #if WOWEE_HAS_AMD_FSR3_FRAMEGEN namespace { FfxErrorCode vkSwapchainConfigureNoop(const FfxFrameGenerationConfig*) { @@ -166,9 +153,6 @@ bool AmdFsr3Runtime::initialize(const AmdFsr3RuntimeInitDesc& desc) { shutdown(); lastError_.clear(); loadPathKind_ = LoadPathKind::None; - wrapperBackendName_.clear(); - wrapperCapabilities_ = 0; - backend_ = RuntimeBackend::None; #if !WOWEE_HAS_AMD_FSR3_FRAMEGEN (void)desc; @@ -184,44 +168,42 @@ bool AmdFsr3Runtime::initialize(const AmdFsr3RuntimeInitDesc& desc) { return false; } - struct Candidate { - std::string path; - LoadPathKind kind = LoadPathKind::Official; - }; - std::vector candidates; + std::vector candidates; if (const char* envPath = std::getenv("WOWEE_FFX_SDK_RUNTIME_LIB")) { - if (*envPath) candidates.push_back({envPath, LoadPathKind::Official}); + if (*envPath) candidates.emplace_back(envPath); } #if defined(_WIN32) - candidates.push_back({"amd_fidelityfx_vk.dll", LoadPathKind::Official}); - candidates.push_back({"libamd_fidelityfx_vk.dll", LoadPathKind::Official}); - candidates.push_back({"ffx_fsr3_vk.dll", LoadPathKind::Official}); - candidates.push_back({"ffx_fsr3.dll", LoadPathKind::Official}); + candidates.emplace_back("amd_fidelityfx_vk.dll"); + candidates.emplace_back("libamd_fidelityfx_vk.dll"); + candidates.emplace_back("ffx_fsr3_vk.dll"); + candidates.emplace_back("ffx_fsr3.dll"); #elif defined(__APPLE__) - candidates.push_back({"libamd_fidelityfx_vk.dylib", LoadPathKind::Official}); - candidates.push_back({"libffx_fsr3_vk.dylib", LoadPathKind::Official}); - candidates.push_back({"libffx_fsr3.dylib", LoadPathKind::Official}); + candidates.emplace_back("libamd_fidelityfx_vk.dylib"); + candidates.emplace_back("libffx_fsr3_vk.dylib"); + candidates.emplace_back("libffx_fsr3.dylib"); #else - candidates.push_back({"./libamd_fidelityfx_vk.so", LoadPathKind::Official}); - candidates.push_back({"libamd_fidelityfx_vk.so", LoadPathKind::Official}); - candidates.push_back({"./libffx_fsr3_vk.so", LoadPathKind::Official}); - candidates.push_back({"libffx_fsr3_vk.so", LoadPathKind::Official}); - candidates.push_back({"libffx_fsr3.so", LoadPathKind::Official}); + candidates.emplace_back("./libamd_fidelityfx_vk.so"); + candidates.emplace_back("libamd_fidelityfx_vk.so"); + candidates.emplace_back("./libffx_fsr3_vk.so"); + candidates.emplace_back("libffx_fsr3_vk.so"); + candidates.emplace_back("libffx_fsr3.so"); #endif - for (const Candidate& candidate : candidates) { + + for (const std::string& path : candidates) { #if defined(_WIN32) - HMODULE h = LoadLibraryA(candidate.path.c_str()); + HMODULE h = LoadLibraryA(path.c_str()); if (!h) continue; libHandle_ = reinterpret_cast(h); #else - void* h = dlopen(candidate.path.c_str(), RTLD_NOW | RTLD_LOCAL); + void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); if (!h) continue; libHandle_ = h; #endif - loadedLibraryPath_ = candidate.path; - loadPathKind_ = candidate.kind; + loadedLibraryPath_ = path; + loadPathKind_ = LoadPathKind::Official; break; } + if (!libHandle_) { lastError_ = "no official runtime (Path A) found"; return false; @@ -236,98 +218,6 @@ bool AmdFsr3Runtime::initialize(const AmdFsr3RuntimeInitDesc& desc) { }; fns_ = new RuntimeFns{}; - if (loadPathKind_ == LoadPathKind::Wrapper) { - fns_->wrapperGetAbiVersion = reinterpret_castwrapperGetAbiVersion)>(resolveSym("wowee_fsr3_wrapper_get_abi_version")); - fns_->wrapperGetName = reinterpret_castwrapperGetName)>(resolveSym("wowee_fsr3_wrapper_get_name")); - fns_->wrapperGetBackend = reinterpret_castwrapperGetBackend)>(resolveSym("wowee_fsr3_wrapper_get_backend")); - fns_->wrapperGetCapabilities = reinterpret_castwrapperGetCapabilities)>(resolveSym("wowee_fsr3_wrapper_get_capabilities")); - fns_->wrapperInitialize = reinterpret_castwrapperInitialize)>(resolveSym("wowee_fsr3_wrapper_initialize")); - fns_->wrapperDispatchUpscale = reinterpret_castwrapperDispatchUpscale)>(resolveSym("wowee_fsr3_wrapper_dispatch_upscale")); - fns_->wrapperDispatchFramegen = reinterpret_castwrapperDispatchFramegen)>(resolveSym("wowee_fsr3_wrapper_dispatch_framegen")); - fns_->wrapperShutdown = reinterpret_castwrapperShutdown)>(resolveSym("wowee_fsr3_wrapper_shutdown")); - fns_->wrapperGetLastError = reinterpret_castwrapperGetLastError)>(resolveSym("wowee_fsr3_wrapper_get_last_error")); - - if (!fns_->wrapperGetAbiVersion || !fns_->wrapperInitialize || - !fns_->wrapperDispatchUpscale || !fns_->wrapperShutdown) { - LOG_WARNING("FSR3 runtime: required wrapper ABI symbols not found in ", loadedLibraryPath_); - lastError_ = "missing required wowee_fsr3_wrapper_* symbols"; - shutdown(); - return false; - } - - const uint32_t abiVersion = fns_->wrapperGetAbiVersion(); - if (abiVersion != WOWEE_FSR3_WRAPPER_ABI_VERSION) { - LOG_WARNING("FSR3 runtime: wrapper ABI mismatch. expected=", WOWEE_FSR3_WRAPPER_ABI_VERSION, - " got=", abiVersion); - lastError_ = "wrapper ABI version mismatch"; - shutdown(); - return false; - } - if (desc.enableFrameGeneration && !fns_->wrapperDispatchFramegen) { - LOG_WARNING("FSR3 runtime: wrapper runtime missing framegen dispatch symbol."); - lastError_ = "wrapper missing frame generation entry points"; - shutdown(); - return false; - } - - WoweeFsr3WrapperInitDesc wrapperInit{}; - wrapperInit.structSize = sizeof(wrapperInit); - wrapperInit.abiVersion = WOWEE_FSR3_WRAPPER_ABI_VERSION; - wrapperInit.physicalDevice = desc.physicalDevice; - wrapperInit.device = desc.device; - wrapperInit.getDeviceProcAddr = desc.getDeviceProcAddr; - wrapperInit.maxRenderWidth = desc.maxRenderWidth; - wrapperInit.maxRenderHeight = desc.maxRenderHeight; - wrapperInit.displayWidth = desc.displayWidth; - wrapperInit.displayHeight = desc.displayHeight; - wrapperInit.colorFormat = desc.colorFormat; - wrapperInit.enableFlags = 0; - if (desc.hdrInput) wrapperInit.enableFlags |= WOWEE_FSR3_WRAPPER_ENABLE_HDR_INPUT; - if (desc.depthInverted) wrapperInit.enableFlags |= WOWEE_FSR3_WRAPPER_ENABLE_DEPTH_INVERTED; - if (desc.enableFrameGeneration) wrapperInit.enableFlags |= WOWEE_FSR3_WRAPPER_ENABLE_FRAME_GENERATION; - - char errorText[256] = {}; - WoweeFsr3WrapperContext wrapperCtx = nullptr; - if (fns_->wrapperInitialize(&wrapperInit, &wrapperCtx, errorText, static_cast(sizeof(errorText))) != 0 || !wrapperCtx) { - LOG_WARNING("FSR3 runtime: wrapper initialization failed: ", errorText[0] ? errorText : "unknown error"); - lastError_ = errorText[0] ? errorText : "wrapper initialization failed"; - shutdown(); - return false; - } - - wrapperContext_ = wrapperCtx; - frameGenerationReady_ = false; - ready_ = true; - backend_ = RuntimeBackend::Wrapper; - uint32_t wrapperCaps = 0; - if (fns_->wrapperGetCapabilities) { - wrapperCaps = fns_->wrapperGetCapabilities(wrapperCtx); - } else { - wrapperCaps = WOWEE_FSR3_WRAPPER_CAP_UPSCALE; - if (fns_->wrapperDispatchFramegen) { - wrapperCaps |= WOWEE_FSR3_WRAPPER_CAP_FRAME_GENERATION; - } - } - wrapperCapabilities_ = wrapperCaps; - frameGenerationReady_ = desc.enableFrameGeneration && - ((wrapperCaps & WOWEE_FSR3_WRAPPER_CAP_FRAME_GENERATION) != 0u); - if (fns_->wrapperGetBackend) { - const char* backendName = fns_->wrapperGetBackend(wrapperCtx); - if (backendName && *backendName) wrapperBackendName_ = backendName; - } - if (fns_->wrapperGetName) { - const char* wrapperName = fns_->wrapperGetName(); - if (wrapperName && *wrapperName) { - LOG_INFO("FSR3 runtime: wrapper active: ", wrapperName, - " backend=", wrapperBackendName_.empty() ? "unknown" : wrapperBackendName_, - " caps=0x", static_cast(wrapperCaps)); - } - } - LOG_INFO("FSR3 runtime: loaded wrapper library ", loadedLibraryPath_, - " framegenReady=", frameGenerationReady_ ? "yes" : "no"); - return true; - } - fns_->getScratchMemorySizeVK = reinterpret_castgetScratchMemorySizeVK)>(resolveSym("ffxGetScratchMemorySizeVK")); fns_->getDeviceVK = reinterpret_castgetDeviceVK)>(resolveSym("ffxGetDeviceVK")); fns_->getInterfaceVK = reinterpret_castgetInterfaceVK)>(resolveSym("ffxGetInterfaceVK")); @@ -359,6 +249,7 @@ bool AmdFsr3Runtime::initialize(const AmdFsr3RuntimeInitDesc& desc) { shutdown(); return false; } + scratchBuffer_ = std::malloc(scratchBufferSize_); if (!scratchBuffer_) { LOG_WARNING("FSR3 runtime: failed to allocate scratch buffer."); @@ -376,6 +267,7 @@ bool AmdFsr3Runtime::initialize(const AmdFsr3RuntimeInitDesc& desc) { vkDevCtx.vkDeviceProcAddr = desc.getDeviceProcAddr; FfxDevice ffxDevice = fns_->getDeviceVK(&vkDevCtx); #endif + FfxInterface backendShared{}; #if WOWEE_AMD_FFX_SDK_KITS FfxErrorCode ifaceErr = fns_->getInterfaceVK( @@ -454,7 +346,6 @@ bool AmdFsr3Runtime::initialize(const AmdFsr3RuntimeInitDesc& desc) { } ready_ = true; - backend_ = RuntimeBackend::Official; LOG_INFO("FSR3 runtime: loaded official library ", loadedLibraryPath_, " framegenReady=", frameGenerationReady_ ? "yes" : "no"); return true; @@ -475,60 +366,6 @@ bool AmdFsr3Runtime::dispatchUpscale(const AmdFsr3RuntimeDispatchDesc& desc) { lastError_ = "invalid upscale dispatch resources"; return false; } - if (backend_ == RuntimeBackend::Wrapper) { - if (!wrapperContext_ || !fns_->wrapperDispatchUpscale) { - lastError_ = "wrapper upscale entry points unavailable"; - return false; - } - WoweeFsr3WrapperDispatchDesc wrapperDesc{}; - wrapperDesc.structSize = sizeof(wrapperDesc); - wrapperDesc.commandBuffer = desc.commandBuffer; - wrapperDesc.colorImage = desc.colorImage; - wrapperDesc.depthImage = desc.depthImage; - wrapperDesc.motionVectorImage = desc.motionVectorImage; - wrapperDesc.outputImage = desc.outputImage; - wrapperDesc.frameGenOutputImage = desc.frameGenOutputImage; - wrapperDesc.renderWidth = desc.renderWidth; - wrapperDesc.renderHeight = desc.renderHeight; - wrapperDesc.outputWidth = desc.outputWidth; - wrapperDesc.outputHeight = desc.outputHeight; - wrapperDesc.colorFormat = desc.colorFormat; - wrapperDesc.depthFormat = desc.depthFormat; - wrapperDesc.motionVectorFormat = desc.motionVectorFormat; - wrapperDesc.outputFormat = desc.outputFormat; - wrapperDesc.jitterX = desc.jitterX; - wrapperDesc.jitterY = desc.jitterY; - wrapperDesc.motionScaleX = desc.motionScaleX; - wrapperDesc.motionScaleY = desc.motionScaleY; - wrapperDesc.frameTimeDeltaMs = desc.frameTimeDeltaMs; - wrapperDesc.cameraNear = desc.cameraNear; - wrapperDesc.cameraFar = desc.cameraFar; - wrapperDesc.cameraFovYRadians = desc.cameraFovYRadians; - wrapperDesc.reset = desc.reset ? 1u : 0u; - wrapperDesc.externalFlags = desc.externalFlags; - wrapperDesc.colorMemoryHandle = desc.colorMemoryHandle; - wrapperDesc.depthMemoryHandle = desc.depthMemoryHandle; - wrapperDesc.motionVectorMemoryHandle = desc.motionVectorMemoryHandle; - wrapperDesc.outputMemoryHandle = desc.outputMemoryHandle; - wrapperDesc.frameGenOutputMemoryHandle = desc.frameGenOutputMemoryHandle; - wrapperDesc.acquireSemaphoreHandle = desc.acquireSemaphoreHandle; - wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle; - wrapperDesc.acquireSemaphoreValue = desc.acquireSemaphoreValue; - wrapperDesc.releaseSemaphoreValue = desc.releaseSemaphoreValue; - const bool ok = fns_->wrapperDispatchUpscale(static_cast(wrapperContext_), &wrapperDesc) == 0; - if (!ok) { - if (fns_->wrapperGetLastError) { - const char* err = fns_->wrapperGetLastError(static_cast(wrapperContext_)); - lastError_ = (err && *err) ? err : "wrapper upscale dispatch failed"; - } else { - lastError_ = "wrapper upscale dispatch failed"; - } - } else { - lastError_.clear(); - } - return ok; - } - if (!contextStorage_ || !fns_->fsr3ContextDispatchUpscale) { lastError_ = "official runtime upscale context unavailable"; return false; @@ -549,23 +386,23 @@ bool AmdFsr3Runtime::dispatchUpscale(const AmdFsr3RuntimeDispatchDesc& desc) { static wchar_t kDepthName[] = L"FSR3_Depth"; static wchar_t kMotionName[] = L"FSR3_MotionVectors"; static wchar_t kOutputName[] = L"FSR3_Output"; - #if WOWEE_AMD_FFX_SDK_KITS +#if WOWEE_AMD_FFX_SDK_KITS dispatch.color = fns_->getResourceVK(desc.colorImage, colorDesc, kColorName, FFX_RESOURCE_STATE_COMPUTE_READ); dispatch.depth = fns_->getResourceVK(desc.depthImage, depthDesc, kDepthName, FFX_RESOURCE_STATE_COMPUTE_READ); dispatch.motionVectors = fns_->getResourceVK(desc.motionVectorImage, mvDesc, kMotionName, FFX_RESOURCE_STATE_COMPUTE_READ); - #else +#else dispatch.color = fns_->getResourceVK(reinterpret_cast(desc.colorImage), colorDesc, kColorName, FFX_RESOURCE_STATE_COMPUTE_READ); dispatch.depth = fns_->getResourceVK(reinterpret_cast(desc.depthImage), depthDesc, kDepthName, FFX_RESOURCE_STATE_COMPUTE_READ); dispatch.motionVectors = fns_->getResourceVK(reinterpret_cast(desc.motionVectorImage), mvDesc, kMotionName, FFX_RESOURCE_STATE_COMPUTE_READ); - #endif +#endif dispatch.exposure = FfxResource{}; dispatch.reactive = FfxResource{}; dispatch.transparencyAndComposition = FfxResource{}; - #if WOWEE_AMD_FFX_SDK_KITS +#if WOWEE_AMD_FFX_SDK_KITS dispatch.upscaleOutput = fns_->getResourceVK(desc.outputImage, outDesc, kOutputName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - #else +#else dispatch.upscaleOutput = fns_->getResourceVK(reinterpret_cast(desc.outputImage), outDesc, kOutputName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - #endif +#endif dispatch.jitterOffset.x = desc.jitterX; dispatch.jitterOffset.y = desc.jitterY; dispatch.motionVectorScale.x = desc.motionScaleX; @@ -608,60 +445,6 @@ bool AmdFsr3Runtime::dispatchFrameGeneration(const AmdFsr3RuntimeDispatchDesc& d lastError_ = "invalid frame generation dispatch resources"; return false; } - if (backend_ == RuntimeBackend::Wrapper) { - if (!wrapperContext_ || !fns_->wrapperDispatchFramegen) { - lastError_ = "wrapper frame generation entry points unavailable"; - return false; - } - WoweeFsr3WrapperDispatchDesc wrapperDesc{}; - wrapperDesc.structSize = sizeof(wrapperDesc); - wrapperDesc.commandBuffer = desc.commandBuffer; - wrapperDesc.colorImage = desc.colorImage; - wrapperDesc.depthImage = desc.depthImage; - wrapperDesc.motionVectorImage = desc.motionVectorImage; - wrapperDesc.outputImage = desc.outputImage; - wrapperDesc.frameGenOutputImage = desc.frameGenOutputImage; - wrapperDesc.renderWidth = desc.renderWidth; - wrapperDesc.renderHeight = desc.renderHeight; - wrapperDesc.outputWidth = desc.outputWidth; - wrapperDesc.outputHeight = desc.outputHeight; - wrapperDesc.colorFormat = desc.colorFormat; - wrapperDesc.depthFormat = desc.depthFormat; - wrapperDesc.motionVectorFormat = desc.motionVectorFormat; - wrapperDesc.outputFormat = desc.outputFormat; - wrapperDesc.jitterX = desc.jitterX; - wrapperDesc.jitterY = desc.jitterY; - wrapperDesc.motionScaleX = desc.motionScaleX; - wrapperDesc.motionScaleY = desc.motionScaleY; - wrapperDesc.frameTimeDeltaMs = desc.frameTimeDeltaMs; - wrapperDesc.cameraNear = desc.cameraNear; - wrapperDesc.cameraFar = desc.cameraFar; - wrapperDesc.cameraFovYRadians = desc.cameraFovYRadians; - wrapperDesc.reset = desc.reset ? 1u : 0u; - wrapperDesc.externalFlags = desc.externalFlags; - wrapperDesc.colorMemoryHandle = desc.colorMemoryHandle; - wrapperDesc.depthMemoryHandle = desc.depthMemoryHandle; - wrapperDesc.motionVectorMemoryHandle = desc.motionVectorMemoryHandle; - wrapperDesc.outputMemoryHandle = desc.outputMemoryHandle; - wrapperDesc.frameGenOutputMemoryHandle = desc.frameGenOutputMemoryHandle; - wrapperDesc.acquireSemaphoreHandle = desc.acquireSemaphoreHandle; - wrapperDesc.releaseSemaphoreHandle = desc.releaseSemaphoreHandle; - wrapperDesc.acquireSemaphoreValue = desc.acquireSemaphoreValue; - wrapperDesc.releaseSemaphoreValue = desc.releaseSemaphoreValue; - const bool ok = fns_->wrapperDispatchFramegen(static_cast(wrapperContext_), &wrapperDesc) == 0; - if (!ok) { - if (fns_->wrapperGetLastError) { - const char* err = fns_->wrapperGetLastError(static_cast(wrapperContext_)); - lastError_ = (err && *err) ? err : "wrapper frame generation dispatch failed"; - } else { - lastError_ = "wrapper frame generation dispatch failed"; - } - } else { - lastError_.clear(); - } - return ok; - } - if (!contextStorage_ || !fns_->fsr3DispatchFrameGeneration) { lastError_ = "official runtime frame generation context unavailable"; return false; @@ -676,17 +459,17 @@ bool AmdFsr3Runtime::dispatchFrameGeneration(const AmdFsr3RuntimeDispatchDesc& d static wchar_t kInterpolatedName[] = L"FSR3_InterpolatedOutput"; FfxFrameGenerationDispatchDescription fgDispatch{}; fgDispatch.commandList = fns_->getCommandListVK(desc.commandBuffer); - #if WOWEE_AMD_FFX_SDK_KITS +#if WOWEE_AMD_FFX_SDK_KITS fgDispatch.presentColor = fns_->getResourceVK( desc.outputImage, presentDesc, kPresentName, FFX_RESOURCE_STATE_COMPUTE_READ); fgDispatch.outputs[0] = fns_->getResourceVK( desc.frameGenOutputImage, fgOutDesc, kInterpolatedName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - #else +#else fgDispatch.presentColor = fns_->getResourceVK( reinterpret_cast(desc.outputImage), presentDesc, kPresentName, FFX_RESOURCE_STATE_COMPUTE_READ); fgDispatch.outputs[0] = fns_->getResourceVK( reinterpret_cast(desc.frameGenOutputImage), fgOutDesc, kInterpolatedName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); - #endif +#endif fgDispatch.numInterpolatedFrames = 1; fgDispatch.reset = desc.reset; fgDispatch.backBufferTransferFunction = FFX_BACKBUFFER_TRANSFER_FUNCTION_SRGB; @@ -705,10 +488,6 @@ bool AmdFsr3Runtime::dispatchFrameGeneration(const AmdFsr3RuntimeDispatchDesc& d void AmdFsr3Runtime::shutdown() { #if WOWEE_HAS_AMD_FSR3_FRAMEGEN - if (wrapperContext_ && fns_ && fns_->wrapperShutdown) { - fns_->wrapperShutdown(static_cast(wrapperContext_)); - } - wrapperContext_ = nullptr; if (contextStorage_ && fns_ && fns_->fsr3ContextDestroy) { fns_->fsr3ContextDestroy(reinterpret_cast(contextStorage_)); } @@ -736,9 +515,6 @@ void AmdFsr3Runtime::shutdown() { libHandle_ = nullptr; loadedLibraryPath_.clear(); loadPathKind_ = LoadPathKind::None; - wrapperBackendName_.clear(); - wrapperCapabilities_ = 0; - backend_ = RuntimeBackend::None; } } // namespace wowee::rendering diff --git a/src/rendering/amd_fsr3_wrapper_impl.cpp b/src/rendering/amd_fsr3_wrapper_impl.cpp deleted file mode 100644 index fd30c976..00000000 --- a/src/rendering/amd_fsr3_wrapper_impl.cpp +++ /dev/null @@ -1,1393 +0,0 @@ -#include "rendering/amd_fsr3_wrapper_abi.h" - -#if WOWEE_HAS_AMD_FSR3_FRAMEGEN -#if WOWEE_AMD_FFX_SDK_KITS -#include "third_party/ffx_fsr3_legacy_compat.h" -#include -#if defined(_WIN32) -#include -#endif -#else -#include -#if defined(_WIN32) -#include -#endif -#include -#endif -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) -#include -#include -#include -#else -#include -#endif - -#if defined(_WIN32) -#define WOWEE_FSR3_WRAPPER_EXPORT extern "C" __declspec(dllexport) -#else -#define WOWEE_FSR3_WRAPPER_EXPORT extern "C" __attribute__((visibility("default"))) -#endif - -namespace { - -void writeError(char* outErrorText, uint32_t outErrorTextCapacity, const char* message) { - if (!outErrorText || outErrorTextCapacity == 0) return; - if (!message) message = "unknown error"; - std::strncpy(outErrorText, message, static_cast(outErrorTextCapacity - 1)); - outErrorText[outErrorTextCapacity - 1] = '\0'; -} - -#if WOWEE_HAS_AMD_FSR3_FRAMEGEN -#if defined(_WIN32) -bool envEnabled(const char* key, bool defaultValue) { - const char* val = std::getenv(key); - if (!val || !*val) return defaultValue; - std::string s(val); - std::transform(s.begin(), s.end(), s.begin(), - [](unsigned char c) { return static_cast(std::tolower(c)); }); - return !(s == "0" || s == "false" || s == "off" || s == "no"); -} - -bool hasExtension(const std::vector& extensions, const char* name) { - for (const VkExtensionProperties& ext : extensions) { - if (std::strcmp(ext.extensionName, name) == 0) return true; - } - return false; -} - -bool hasExternalImageInteropSupport(VkPhysicalDevice physicalDevice, VkFormat format) { - if (!physicalDevice || format == VK_FORMAT_UNDEFINED) return false; - - VkPhysicalDeviceExternalImageFormatInfo externalInfo{}; - externalInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO; - externalInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; - - VkPhysicalDeviceImageFormatInfo2 imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2; - imageInfo.format = format; - imageInfo.type = VK_IMAGE_TYPE_2D; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - imageInfo.flags = 0; - imageInfo.pNext = &externalInfo; - - VkExternalImageFormatProperties externalProps{}; - externalProps.sType = VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES; - - VkImageFormatProperties2 imageProps{}; - imageProps.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2; - imageProps.pNext = &externalProps; - - const VkResult res = vkGetPhysicalDeviceImageFormatProperties2(physicalDevice, &imageInfo, &imageProps); - if (res != VK_SUCCESS) return false; - - const VkExternalMemoryFeatureFlags features = externalProps.externalMemoryProperties.externalMemoryFeatures; - const bool exportable = (features & VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT) != 0; - const bool importable = (features & VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT) != 0; - return exportable && importable; -} -#endif - -#if defined(__linux__) -bool hasExtensionLinux(const std::vector& extensions, const char* name) { - for (const VkExtensionProperties& ext : extensions) { - if (std::strcmp(ext.extensionName, name) == 0) return true; - } - return false; -} - -bool runLinuxBridgePreflight(const WoweeFsr3WrapperInitDesc* initDesc, std::string& errorMessage) { - std::vector missing; - if (!initDesc || !initDesc->device || !initDesc->getDeviceProcAddr || !initDesc->physicalDevice) { - missing.emplace_back("valid Vulkan device/getDeviceProcAddr"); - } else { - const char* requiredVkInteropFns[] = { - "vkGetMemoryFdKHR", - "vkGetSemaphoreFdKHR" - }; - for (const char* fn : requiredVkInteropFns) { - PFN_vkVoidFunction fp = initDesc->getDeviceProcAddr(initDesc->device, fn); - if (!fp) missing.emplace_back(fn); - } - - uint32_t extCount = 0; - VkResult extErr = vkEnumerateDeviceExtensionProperties(initDesc->physicalDevice, nullptr, &extCount, nullptr); - if (extErr != VK_SUCCESS || extCount == 0) { - missing.emplace_back("vkEnumerateDeviceExtensionProperties"); - } else { - std::vector extensions(extCount); - extErr = vkEnumerateDeviceExtensionProperties( - initDesc->physicalDevice, nullptr, &extCount, extensions.data()); - if (extErr != VK_SUCCESS) { - missing.emplace_back("vkEnumerateDeviceExtensionProperties(data)"); - } else { - const char* requiredVkExtensions[] = { - VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, - VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME - }; - for (const char* extName : requiredVkExtensions) { - if (!hasExtensionLinux(extensions, extName)) { - missing.emplace_back(extName); - } - } - } - } - } - - if (missing.empty()) return true; - std::ostringstream oss; - oss << "dx12_bridge preflight failed (linux), missing: "; - for (size_t i = 0; i < missing.size(); ++i) { - if (i) oss << ", "; - oss << missing[i]; - } - errorMessage = oss.str(); - return false; -} -#endif - -enum class WrapperBackend { - VulkanRuntime, - Dx12Bridge -}; - -WrapperBackend selectBackend() { - if (const char* envBackend = std::getenv("WOWEE_FSR3_WRAPPER_BACKEND")) { - if (envBackend && *envBackend) { - std::string mode(envBackend); - std::transform(mode.begin(), mode.end(), mode.begin(), - [](unsigned char c) { return static_cast(std::tolower(c)); }); - if (mode == "dx12" || mode == "dx12_bridge" || mode == "d3d12") { - return WrapperBackend::Dx12Bridge; - } - if (mode == "vulkan" || mode == "vk" || mode == "vulkan_runtime") { - return WrapperBackend::VulkanRuntime; - } - } - } - return WrapperBackend::VulkanRuntime; -} - -const char* backendName(WrapperBackend backend) { - switch (backend) { - case WrapperBackend::Dx12Bridge: - return "dx12_bridge"; - case WrapperBackend::VulkanRuntime: - return "vulkan_runtime"; - default: - return "unknown"; - } -} - -FfxErrorCode vkSwapchainConfigureNoop(const FfxFrameGenerationConfig*) { - return FFX_OK; -} - -template -struct HasUpscaleOutputSize : std::false_type {}; - -template -struct HasUpscaleOutputSize().upscaleOutputSize)>> : std::true_type {}; - -template -inline void setUpscaleOutputSizeIfPresent(T& ctxDesc, uint32_t width, uint32_t height) { - if constexpr (HasUpscaleOutputSize::value) { - ctxDesc.upscaleOutputSize.width = width; - ctxDesc.upscaleOutputSize.height = height; - } else { - (void)ctxDesc; - (void)width; - (void)height; - } -} - -FfxSurfaceFormat mapVkFormatToFfxSurfaceFormat(VkFormat format, bool isDepth) { - if (isDepth) { - switch (format) { - case VK_FORMAT_D32_SFLOAT: - return FFX_SURFACE_FORMAT_R32_FLOAT; - case VK_FORMAT_D16_UNORM: - return FFX_SURFACE_FORMAT_R16_UNORM; - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - return FFX_SURFACE_FORMAT_R32_FLOAT; - default: - return FFX_SURFACE_FORMAT_R32_FLOAT; - } - } - - switch (format) { - case VK_FORMAT_R16G16B16A16_SFLOAT: - return FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT; - case VK_FORMAT_R8G8B8A8_UNORM: - case VK_FORMAT_B8G8R8A8_UNORM: - return FFX_SURFACE_FORMAT_R8G8B8A8_UNORM; - case VK_FORMAT_R8G8B8A8_SRGB: - case VK_FORMAT_B8G8R8A8_SRGB: - return FFX_SURFACE_FORMAT_R8G8B8A8_SRGB; - case VK_FORMAT_A2R10G10B10_UNORM_PACK32: - case VK_FORMAT_A2B10G10R10_UNORM_PACK32: - return FFX_SURFACE_FORMAT_R10G10B10A2_UNORM; - case VK_FORMAT_B10G11R11_UFLOAT_PACK32: - return FFX_SURFACE_FORMAT_R11G11B10_FLOAT; - case VK_FORMAT_R16G16_SFLOAT: - return FFX_SURFACE_FORMAT_R16G16_FLOAT; - case VK_FORMAT_R16G16_UINT: - return FFX_SURFACE_FORMAT_R16G16_UINT; - case VK_FORMAT_R16_SFLOAT: - return FFX_SURFACE_FORMAT_R16_FLOAT; - case VK_FORMAT_R16_UINT: - return FFX_SURFACE_FORMAT_R16_UINT; - case VK_FORMAT_R16_UNORM: - return FFX_SURFACE_FORMAT_R16_UNORM; - case VK_FORMAT_R16_SNORM: - return FFX_SURFACE_FORMAT_R16_SNORM; - case VK_FORMAT_R8_UNORM: - return FFX_SURFACE_FORMAT_R8_UNORM; - case VK_FORMAT_R8_UINT: - return FFX_SURFACE_FORMAT_R8_UINT; - case VK_FORMAT_R8G8_UNORM: - return FFX_SURFACE_FORMAT_R8G8_UNORM; - case VK_FORMAT_R32_SFLOAT: - return FFX_SURFACE_FORMAT_R32_FLOAT; - case VK_FORMAT_R32_UINT: - return FFX_SURFACE_FORMAT_R32_UINT; - default: - return FFX_SURFACE_FORMAT_UNKNOWN; - } -} - -FfxResourceDescription makeResourceDescription(VkFormat format, - uint32_t width, - uint32_t height, - FfxResourceUsage usage, - bool isDepth = false) { - FfxResourceDescription description{}; - description.type = FFX_RESOURCE_TYPE_TEXTURE2D; - description.format = mapVkFormatToFfxSurfaceFormat(format, isDepth); - description.width = width; - description.height = height; - description.depth = 1; - description.mipCount = 1; - description.flags = FFX_RESOURCE_FLAGS_NONE; - description.usage = usage; - return description; -} - -bool hasKnownSurfaceFormat(const FfxResourceDescription& description) { - return description.format != FFX_SURFACE_FORMAT_UNKNOWN; -} - -struct RuntimeFns { - decltype(&ffxGetScratchMemorySizeVK) getScratchMemorySizeVK = nullptr; - decltype(&ffxGetDeviceVK) getDeviceVK = nullptr; - decltype(&ffxGetInterfaceVK) getInterfaceVK = nullptr; - decltype(&ffxGetCommandListVK) getCommandListVK = nullptr; - decltype(&ffxGetResourceVK) getResourceVK = nullptr; - decltype(&ffxFsr3ContextCreate) fsr3ContextCreate = nullptr; - decltype(&ffxFsr3ContextDispatchUpscale) fsr3ContextDispatchUpscale = nullptr; - decltype(&ffxFsr3ConfigureFrameGeneration) fsr3ConfigureFrameGeneration = nullptr; - decltype(&ffxFsr3DispatchFrameGeneration) fsr3DispatchFrameGeneration = nullptr; - decltype(&ffxFsr3ContextDestroy) fsr3ContextDestroy = nullptr; -#if defined(_WIN32) - decltype(&ffxGetScratchMemorySizeDX12) getScratchMemorySizeDX12 = nullptr; - decltype(&ffxGetDeviceDX12) getDeviceDX12 = nullptr; - decltype(&ffxGetInterfaceDX12) getInterfaceDX12 = nullptr; - decltype(&ffxGetCommandListDX12) getCommandListDX12 = nullptr; - decltype(&ffxGetResourceDX12) getResourceDX12 = nullptr; -#endif -}; - -struct WrapperContext { - WrapperBackend backend = WrapperBackend::VulkanRuntime; - void* backendLibHandle = nullptr; - RuntimeFns fns{}; - void* scratchBuffer = nullptr; - size_t scratchBufferSize = 0; - void* fsr3ContextStorage = nullptr; - bool frameGenerationReady = false; - bool hdrInput = false; - std::string lastError{}; -#if defined(_WIN32) - ID3D12Device* dx12Device = nullptr; - ID3D12CommandQueue* dx12Queue = nullptr; - ID3D12CommandAllocator* dx12CommandAllocator = nullptr; - ID3D12GraphicsCommandList* dx12CommandList = nullptr; - ID3D12Fence* dx12Fence = nullptr; - HANDLE dx12FenceEvent = nullptr; - uint64_t dx12FenceValue = 0; -#endif -}; - -void setContextError(WrapperContext* ctx, const char* message) { - if (!ctx) return; - ctx->lastError = (message && *message) ? message : "unknown wrapper error"; -} - -void closeLibrary(void* handle) { - if (!handle) return; -#if defined(_WIN32) - FreeLibrary(reinterpret_cast(handle)); -#else - dlclose(handle); -#endif -} - -void* openLibrary(const char* path) { - if (!path || !*path) return nullptr; -#if defined(_WIN32) - return reinterpret_cast(LoadLibraryA(path)); -#else - return dlopen(path, RTLD_NOW | RTLD_LOCAL); -#endif -} - -void* resolveSymbol(void* handle, const char* symbol) { - if (!handle || !symbol) return nullptr; -#if defined(_WIN32) - return reinterpret_cast(GetProcAddress(reinterpret_cast(handle), symbol)); -#else - return dlsym(handle, symbol); -#endif -} - -bool bindVulkanRuntimeFns(void* libHandle, RuntimeFns& outFns) { - outFns = RuntimeFns{}; - outFns.getScratchMemorySizeVK = reinterpret_cast(resolveSymbol(libHandle, "ffxGetScratchMemorySizeVK")); - outFns.getDeviceVK = reinterpret_cast(resolveSymbol(libHandle, "ffxGetDeviceVK")); - outFns.getInterfaceVK = reinterpret_cast(resolveSymbol(libHandle, "ffxGetInterfaceVK")); - outFns.getCommandListVK = reinterpret_cast(resolveSymbol(libHandle, "ffxGetCommandListVK")); - outFns.getResourceVK = reinterpret_cast(resolveSymbol(libHandle, "ffxGetResourceVK")); - outFns.fsr3ContextCreate = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3ContextCreate")); - outFns.fsr3ContextDispatchUpscale = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3ContextDispatchUpscale")); - outFns.fsr3ConfigureFrameGeneration = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3ConfigureFrameGeneration")); - outFns.fsr3DispatchFrameGeneration = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3DispatchFrameGeneration")); - outFns.fsr3ContextDestroy = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3ContextDestroy")); - - return outFns.getScratchMemorySizeVK && outFns.getDeviceVK && outFns.getInterfaceVK && - outFns.getCommandListVK && outFns.getResourceVK && outFns.fsr3ContextCreate && - outFns.fsr3ContextDispatchUpscale && outFns.fsr3ContextDestroy; -} - -#if defined(_WIN32) -bool bindDx12RuntimeFns(void* libHandle, RuntimeFns& outFns) { - outFns = RuntimeFns{}; - outFns.getScratchMemorySizeDX12 = reinterpret_cast(resolveSymbol(libHandle, "ffxGetScratchMemorySizeDX12")); - outFns.getDeviceDX12 = reinterpret_cast(resolveSymbol(libHandle, "ffxGetDeviceDX12")); - outFns.getInterfaceDX12 = reinterpret_cast(resolveSymbol(libHandle, "ffxGetInterfaceDX12")); - outFns.getCommandListDX12 = reinterpret_cast(resolveSymbol(libHandle, "ffxGetCommandListDX12")); - outFns.getResourceDX12 = reinterpret_cast(resolveSymbol(libHandle, "ffxGetResourceDX12")); - outFns.fsr3ContextCreate = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3ContextCreate")); - outFns.fsr3ContextDispatchUpscale = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3ContextDispatchUpscale")); - outFns.fsr3ConfigureFrameGeneration = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3ConfigureFrameGeneration")); - outFns.fsr3DispatchFrameGeneration = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3DispatchFrameGeneration")); - outFns.fsr3ContextDestroy = reinterpret_cast(resolveSymbol(libHandle, "ffxFsr3ContextDestroy")); - return outFns.getScratchMemorySizeDX12 && outFns.getDeviceDX12 && outFns.getInterfaceDX12 && - outFns.getCommandListDX12 && outFns.getResourceDX12 && outFns.fsr3ContextCreate && - outFns.fsr3ContextDispatchUpscale && outFns.fsr3ContextDestroy; -} -#endif - -void destroyContext(WrapperContext* ctx) { - if (!ctx) return; -#if defined(_WIN32) - if (ctx->dx12FenceEvent) { - CloseHandle(ctx->dx12FenceEvent); - ctx->dx12FenceEvent = nullptr; - } - if (ctx->dx12Fence) { - ctx->dx12Fence->Release(); - ctx->dx12Fence = nullptr; - } - if (ctx->dx12CommandList) { - ctx->dx12CommandList->Release(); - ctx->dx12CommandList = nullptr; - } - if (ctx->dx12CommandAllocator) { - ctx->dx12CommandAllocator->Release(); - ctx->dx12CommandAllocator = nullptr; - } - if (ctx->dx12Queue) { - ctx->dx12Queue->Release(); - ctx->dx12Queue = nullptr; - } - if (ctx->dx12Device) { - ctx->dx12Device->Release(); - ctx->dx12Device = nullptr; - } -#endif - if (ctx->fsr3ContextStorage && ctx->fns.fsr3ContextDestroy) { - ctx->fns.fsr3ContextDestroy(reinterpret_cast(ctx->fsr3ContextStorage)); - } - if (ctx->fsr3ContextStorage) { - std::free(ctx->fsr3ContextStorage); - ctx->fsr3ContextStorage = nullptr; - } - if (ctx->scratchBuffer) { - std::free(ctx->scratchBuffer); - ctx->scratchBuffer = nullptr; - } - ctx->scratchBufferSize = 0; - closeLibrary(ctx->backendLibHandle); - ctx->backendLibHandle = nullptr; - delete ctx; -} - -#if defined(_WIN32) -bool openSharedResourceHandle(ID3D12Device* device, uint64_t handleValue, const char* name, std::string& outError) { - if (!device || handleValue == 0) { - outError = std::string("invalid shared resource handle for ") + (name ? name : "unknown"); - return false; - } - ID3D12Resource* res = nullptr; - const HRESULT hr = device->OpenSharedHandle(reinterpret_cast(handleValue), IID_PPV_ARGS(&res)); - if (FAILED(hr) || !res) { - outError = std::string("failed to import shared resource handle for ") + (name ? name : "unknown"); - return false; - } - res->Release(); - return true; -} - -bool openSharedFenceHandle(ID3D12Device* device, uint64_t handleValue, const char* name, std::string& outError) { - if (!device || handleValue == 0) { - outError = std::string("invalid shared fence handle for ") + (name ? name : "unknown"); - return false; - } - ID3D12Fence* fence = nullptr; - const HRESULT hr = device->OpenSharedHandle(reinterpret_cast(handleValue), IID_PPV_ARGS(&fence)); - if (FAILED(hr) || !fence) { - outError = std::string("failed to import shared fence handle for ") + (name ? name : "unknown"); - return false; - } - fence->Release(); - return true; -} - -template -void safeRelease(T*& obj) { - if (obj) { - obj->Release(); - obj = nullptr; - } -} - -bool runDx12BridgePreflight(const WoweeFsr3WrapperInitDesc* initDesc, std::string& errorMessage) { - std::vector missing; - - HMODULE d3d12 = LoadLibraryA("d3d12.dll"); - if (!d3d12) { - missing.emplace_back("d3d12.dll"); - } - - HMODULE dxgi = LoadLibraryA("dxgi.dll"); - if (!dxgi) { - missing.emplace_back("dxgi.dll"); - } - - using PFN_D3D12CreateDeviceLocal = HRESULT(WINAPI*)(IUnknown*, D3D_FEATURE_LEVEL, REFIID, void**); - using PFN_CreateDXGIFactory2Local = HRESULT(WINAPI*)(UINT, REFIID, void**); - PFN_D3D12CreateDeviceLocal pD3D12CreateDevice = nullptr; - PFN_CreateDXGIFactory2Local pCreateDXGIFactory2 = nullptr; - if (d3d12) { - pD3D12CreateDevice = reinterpret_cast(GetProcAddress(d3d12, "D3D12CreateDevice")); - if (!pD3D12CreateDevice) { - missing.emplace_back("D3D12CreateDevice"); - } - } - if (dxgi) { - pCreateDXGIFactory2 = reinterpret_cast(GetProcAddress(dxgi, "CreateDXGIFactory2")); - if (!pCreateDXGIFactory2) { - missing.emplace_back("CreateDXGIFactory2"); - } - } - - if (!initDesc || !initDesc->device || !initDesc->getDeviceProcAddr || !initDesc->physicalDevice) { - missing.emplace_back("valid Vulkan device/getDeviceProcAddr"); - } else { - const char* requiredVkInteropFns[] = { - "vkGetMemoryWin32HandleKHR", - "vkImportSemaphoreWin32HandleKHR", - "vkGetSemaphoreWin32HandleKHR" - }; - for (const char* fn : requiredVkInteropFns) { - PFN_vkVoidFunction fp = initDesc->getDeviceProcAddr(initDesc->device, fn); - if (!fp) { - missing.emplace_back(fn); - } - } - - uint32_t extCount = 0; - VkResult extErr = vkEnumerateDeviceExtensionProperties(initDesc->physicalDevice, nullptr, &extCount, nullptr); - if (extErr != VK_SUCCESS || extCount == 0) { - missing.emplace_back("vkEnumerateDeviceExtensionProperties"); - } else { - std::vector extensions(extCount); - extErr = vkEnumerateDeviceExtensionProperties( - initDesc->physicalDevice, nullptr, &extCount, extensions.data()); - if (extErr != VK_SUCCESS) { - missing.emplace_back("vkEnumerateDeviceExtensionProperties(data)"); - } else { - const char* requiredVkExtensions[] = { - VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, - VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, - VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME - }; - for (const char* extName : requiredVkExtensions) { - if (!hasExtension(extensions, extName)) { - missing.emplace_back(extName); - } - } - if (!hasExternalImageInteropSupport(initDesc->physicalDevice, initDesc->colorFormat)) { - missing.emplace_back("external memory export/import support for swap/upscale format"); - } - } - } - } - - std::vector runtimeCandidates; - if (const char* explicitRuntime = std::getenv("WOWEE_FSR3_DX12_RUNTIME_LIB")) { - if (explicitRuntime && *explicitRuntime) runtimeCandidates.emplace_back(explicitRuntime); - } - runtimeCandidates.emplace_back("amd_fidelityfx_framegeneration_dx12.dll"); - runtimeCandidates.emplace_back("ffx_framegeneration_dx12.dll"); - - bool foundRuntime = false; - bool foundRequiredApiSymbols = false; - for (const std::string& candidate : runtimeCandidates) { - HMODULE runtime = LoadLibraryA(candidate.c_str()); - if (runtime) { - const bool hasCreate = GetProcAddress(runtime, "ffxCreateContext") != nullptr; - const bool hasDestroy = GetProcAddress(runtime, "ffxDestroyContext") != nullptr; - const bool hasConfigure = GetProcAddress(runtime, "ffxConfigure") != nullptr; - const bool hasDispatch = GetProcAddress(runtime, "ffxDispatch") != nullptr; - if (hasCreate && hasDestroy && hasConfigure && hasDispatch) { - foundRequiredApiSymbols = true; - } - FreeLibrary(runtime); - foundRuntime = true; - if (foundRequiredApiSymbols) break; - } - } - if (!foundRuntime) { - missing.emplace_back("amd_fidelityfx_framegeneration_dx12.dll"); - } else if (!foundRequiredApiSymbols) { - missing.emplace_back("ffxCreateContext/ffxConfigure/ffxDispatch exports"); - } - - // Optional strict probe: attempt creating a DXGI factory and D3D12 device. - if (missing.empty() && envEnabled("WOWEE_FSR3_WRAPPER_DX12_VALIDATE_DEVICE", true) && - pCreateDXGIFactory2 && pD3D12CreateDevice) { - IDXGIFactory6* factory = nullptr; - HRESULT hrFactory = pCreateDXGIFactory2(0, IID_PPV_ARGS(&factory)); - if (FAILED(hrFactory) || !factory) { - missing.emplace_back("DXGI factory creation"); - } else { - IDXGIAdapter1* adapter = nullptr; - bool hasHardwareAdapter = false; - for (UINT adapterIndex = 0; factory->EnumAdapters1(adapterIndex, &adapter) != DXGI_ERROR_NOT_FOUND; ++adapterIndex) { - DXGI_ADAPTER_DESC1 desc{}; - if (SUCCEEDED(adapter->GetDesc1(&desc)) && !(desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE)) { - hasHardwareAdapter = true; - break; - } - adapter->Release(); - adapter = nullptr; - } - if (!hasHardwareAdapter || !adapter) { - missing.emplace_back("hardware DXGI adapter"); - } else { - ID3D12Device* d3d12Device = nullptr; - HRESULT hrDevice = pD3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&d3d12Device)); - if (FAILED(hrDevice) || !d3d12Device) { - missing.emplace_back("D3D12 device creation (feature level 12_0)"); - } - if (d3d12Device) d3d12Device->Release(); - adapter->Release(); - } - factory->Release(); - } - } - - if (dxgi) FreeLibrary(dxgi); - if (d3d12) FreeLibrary(d3d12); - - if (missing.empty()) return true; - - std::ostringstream oss; - oss << "dx12_bridge preflight failed, missing: "; - for (size_t i = 0; i < missing.size(); ++i) { - if (i) oss << ", "; - oss << missing[i]; - } - errorMessage = oss.str(); - return false; -} -#endif -#endif - -} // namespace - -WOWEE_FSR3_WRAPPER_EXPORT uint32_t wowee_fsr3_wrapper_get_abi_version(void) { - return WOWEE_FSR3_WRAPPER_ABI_VERSION; -} - -WOWEE_FSR3_WRAPPER_EXPORT const char* wowee_fsr3_wrapper_get_name(void) { - return "WoWee FSR3 Wrapper"; -} - -WOWEE_FSR3_WRAPPER_EXPORT const char* wowee_fsr3_wrapper_get_backend(WoweeFsr3WrapperContext context) { -#if WOWEE_HAS_AMD_FSR3_FRAMEGEN - WrapperContext* ctx = reinterpret_cast(context); - if (!ctx) return "invalid"; - return backendName(ctx->backend); -#else - (void)context; - return "unavailable"; -#endif -} - -WOWEE_FSR3_WRAPPER_EXPORT uint32_t wowee_fsr3_wrapper_get_capabilities(WoweeFsr3WrapperContext context) { -#if WOWEE_HAS_AMD_FSR3_FRAMEGEN - WrapperContext* ctx = reinterpret_cast(context); - if (!ctx) return 0; - uint32_t caps = WOWEE_FSR3_WRAPPER_CAP_UPSCALE; - if (ctx->frameGenerationReady && ctx->fns.fsr3DispatchFrameGeneration) { - caps |= WOWEE_FSR3_WRAPPER_CAP_FRAME_GENERATION; - } -#if defined(_WIN32) - if (ctx->backend == WrapperBackend::Dx12Bridge) { - caps |= WOWEE_FSR3_WRAPPER_CAP_EXTERNAL_INTEROP; - } -#elif defined(__linux__) - if (ctx->backend == WrapperBackend::Dx12Bridge) { - caps |= WOWEE_FSR3_WRAPPER_CAP_EXTERNAL_INTEROP; - } -#endif - return caps; -#else - (void)context; - return 0; -#endif -} - -WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_initialize(const WoweeFsr3WrapperInitDesc* initDesc, - WoweeFsr3WrapperContext* outContext, - char* outErrorText, - uint32_t outErrorTextCapacity) { - if (outContext) *outContext = nullptr; -#if !WOWEE_HAS_AMD_FSR3_FRAMEGEN - (void)initDesc; - writeError(outErrorText, outErrorTextCapacity, "wrapper built without WOWEE_HAS_AMD_FSR3_FRAMEGEN"); - return -1; -#else - if (!initDesc || !outContext) { - writeError(outErrorText, outErrorTextCapacity, "invalid init args"); - return -1; - } - if (initDesc->structSize < sizeof(WoweeFsr3WrapperInitDesc) || - initDesc->abiVersion != WOWEE_FSR3_WRAPPER_ABI_VERSION) { - writeError(outErrorText, outErrorTextCapacity, "wrapper ABI/version mismatch"); - return -1; - } - if (!initDesc->physicalDevice || !initDesc->device || !initDesc->getDeviceProcAddr || - initDesc->maxRenderWidth == 0 || initDesc->maxRenderHeight == 0 || - initDesc->displayWidth == 0 || initDesc->displayHeight == 0 || - initDesc->colorFormat == VK_FORMAT_UNDEFINED) { - writeError(outErrorText, outErrorTextCapacity, "invalid init descriptor values"); - return -1; - } - - const char* backendEnvRaw = std::getenv("WOWEE_FSR3_WRAPPER_BACKEND"); - const bool backendExplicit = (backendEnvRaw && *backendEnvRaw); - const WrapperBackend selectedBackend = selectBackend(); - if (selectedBackend == WrapperBackend::Dx12Bridge) { -#if defined(_WIN32) - std::string preflightError; - if (!runDx12BridgePreflight(initDesc, preflightError)) { - writeError(outErrorText, outErrorTextCapacity, preflightError.c_str()); - return -1; - } -#elif defined(__linux__) - std::string preflightError; - if (!runLinuxBridgePreflight(initDesc, preflightError)) { - writeError(outErrorText, outErrorTextCapacity, preflightError.c_str()); - return -1; - } -#endif - } - - std::vector baseCandidates; - if (const char* backendEnv = std::getenv("WOWEE_FSR3_WRAPPER_BACKEND_LIB")) { - if (*backendEnv) baseCandidates.emplace_back(backendEnv); - } - if (const char* runtimeEnv = std::getenv("WOWEE_FFX_SDK_RUNTIME_LIB")) { - if (*runtimeEnv) baseCandidates.emplace_back(runtimeEnv); - } - - WrapperContext* ctx = new WrapperContext{}; - ctx->backend = selectedBackend; -#if defined(_WIN32) - auto initDx12BridgeState = [&](const WoweeFsr3WrapperInitDesc* desc) -> bool { - if (ctx->dx12Device) return true; - if (!runDx12BridgePreflight(desc, ctx->lastError)) return false; - if (D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&ctx->dx12Device)) != S_OK || !ctx->dx12Device) { - ctx->lastError = "dx12_bridge failed to create D3D12 device"; - return false; - } - - D3D12_COMMAND_QUEUE_DESC queueDesc{}; - queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; - if (ctx->dx12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&ctx->dx12Queue)) != S_OK || !ctx->dx12Queue) { - ctx->lastError = "dx12_bridge failed to create command queue"; - return false; - } - if (ctx->dx12Device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&ctx->dx12CommandAllocator)) != S_OK || - !ctx->dx12CommandAllocator) { - ctx->lastError = "dx12_bridge failed to create command allocator"; - return false; - } - if (ctx->dx12Device->CreateCommandList( - 0, D3D12_COMMAND_LIST_TYPE_DIRECT, ctx->dx12CommandAllocator, nullptr, - IID_PPV_ARGS(&ctx->dx12CommandList)) != S_OK || !ctx->dx12CommandList) { - ctx->lastError = "dx12_bridge failed to create command list"; - return false; - } - ctx->dx12CommandList->Close(); - if (ctx->dx12Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&ctx->dx12Fence)) != S_OK || !ctx->dx12Fence) { - ctx->lastError = "dx12_bridge failed to create fence"; - return false; - } - ctx->dx12FenceEvent = CreateEventA(nullptr, FALSE, FALSE, nullptr); - if (!ctx->dx12FenceEvent) { - ctx->lastError = "dx12_bridge failed to create fence event"; - return false; - } - ctx->dx12FenceValue = 1; - return true; - }; -#endif - - auto tryLoadForBackend = [&](WrapperBackend backend) -> bool { -#if defined(_WIN32) - if (backend == WrapperBackend::Dx12Bridge && !initDx12BridgeState(initDesc)) { - return false; - } -#elif defined(__linux__) - if (backend == WrapperBackend::Dx12Bridge && !runLinuxBridgePreflight(initDesc, ctx->lastError)) { - return false; - } -#endif - std::vector candidates = baseCandidates; -#if defined(_WIN32) - if (backend == WrapperBackend::Dx12Bridge) { - candidates.emplace_back("amd_fidelityfx_framegeneration_dx12.dll"); - candidates.emplace_back("ffx_framegeneration_dx12.dll"); - } - candidates.emplace_back("ffx_fsr3_vk.dll"); - candidates.emplace_back("ffx_fsr3.dll"); - candidates.emplace_back("ffx_fsr3_bridge.dll"); -#elif defined(__APPLE__) - candidates.emplace_back("libffx_fsr3_vk.dylib"); - candidates.emplace_back("libffx_fsr3.dylib"); - candidates.emplace_back("libffx_fsr3_bridge.dylib"); -#else - candidates.emplace_back("./libffx_fsr3_vk.so"); - candidates.emplace_back("libffx_fsr3_vk.so"); - candidates.emplace_back("libffx_fsr3.so"); - candidates.emplace_back("libffx_fsr3_bridge.so"); -#endif - - for (const std::string& path : candidates) { - void* candidateHandle = openLibrary(path.c_str()); - if (!candidateHandle) continue; - - RuntimeFns candidateFns{}; -#if defined(_WIN32) - const bool bound = (backend == WrapperBackend::Dx12Bridge) - ? bindDx12RuntimeFns(candidateHandle, candidateFns) - : bindVulkanRuntimeFns(candidateHandle, candidateFns); -#else - const bool bound = bindVulkanRuntimeFns(candidateHandle, candidateFns); -#endif - if (!bound) { - closeLibrary(candidateHandle); - continue; - } - - ctx->backend = backend; - ctx->backendLibHandle = candidateHandle; - ctx->fns = candidateFns; - return true; - } - return false; - }; - - bool loaded = tryLoadForBackend(selectedBackend); -#if defined(_WIN32) || defined(__linux__) - if (!loaded && !backendExplicit && selectedBackend == WrapperBackend::VulkanRuntime) { - loaded = tryLoadForBackend(WrapperBackend::Dx12Bridge); - } -#endif - if (!loaded) { - if (ctx->backendLibHandle) { - closeLibrary(ctx->backendLibHandle); - ctx->backendLibHandle = nullptr; - } - } - if (!ctx->backendLibHandle) { - const bool attemptedDx12 = - (selectedBackend == WrapperBackend::Dx12Bridge) -#if defined(_WIN32) || defined(__linux__) - || (!backendExplicit && selectedBackend == WrapperBackend::VulkanRuntime) -#endif - ; - const std::string err = ctx->lastError; - destroyContext(ctx); - if (attemptedDx12) { - writeError(outErrorText, outErrorTextCapacity, - err.empty() ? "dx12_bridge requested, but no dispatch-capable runtime exports were found" - : err.c_str()); - } else { - writeError(outErrorText, outErrorTextCapacity, "no FSR3 backend runtime found for wrapper"); - } - return -1; - } - - const bool enableFrameGeneration = (initDesc->enableFlags & WOWEE_FSR3_WRAPPER_ENABLE_FRAME_GENERATION) != 0u; - ctx->hdrInput = (initDesc->enableFlags & WOWEE_FSR3_WRAPPER_ENABLE_HDR_INPUT) != 0u; - if (enableFrameGeneration && (!ctx->fns.fsr3ConfigureFrameGeneration || !ctx->fns.fsr3DispatchFrameGeneration)) { - destroyContext(ctx); - writeError(outErrorText, outErrorTextCapacity, "backend missing frame generation symbols"); - return -1; - } - - if (ctx->backend == WrapperBackend::Dx12Bridge) { -#if defined(_WIN32) - ctx->scratchBufferSize = ctx->fns.getScratchMemorySizeDX12(FFX_FSR3_CONTEXT_COUNT); -#else - ctx->scratchBufferSize = 0; -#endif - } else { -#if WOWEE_AMD_FFX_SDK_KITS - ctx->scratchBufferSize = ctx->fns.getScratchMemorySizeVK(FFX_FSR3_CONTEXT_COUNT); -#else - ctx->scratchBufferSize = ctx->fns.getScratchMemorySizeVK(initDesc->physicalDevice, FFX_FSR3_CONTEXT_COUNT); -#endif - } - if (ctx->scratchBufferSize == 0) { - destroyContext(ctx); - writeError(outErrorText, outErrorTextCapacity, "scratch buffer size query returned 0"); - return -1; - } - ctx->scratchBuffer = std::malloc(ctx->scratchBufferSize); - if (!ctx->scratchBuffer) { - destroyContext(ctx); - writeError(outErrorText, outErrorTextCapacity, "scratch buffer allocation failed"); - return -1; - } - - FfxInterface backendShared{}; - FfxErrorCode ifaceErr = FFX_ERROR_INVALID_ARGUMENT; - if (ctx->backend == WrapperBackend::Dx12Bridge) { -#if defined(_WIN32) - FfxDevice ffxDevice = ctx->fns.getDeviceDX12(ctx->dx12Device); - ifaceErr = ctx->fns.getInterfaceDX12( - &backendShared, ffxDevice, ctx->scratchBuffer, ctx->scratchBufferSize, FFX_FSR3_CONTEXT_COUNT); -#endif - } else { -#if WOWEE_AMD_FFX_SDK_KITS - FfxDevice ffxDevice = ctx->fns.getDeviceVK(initDesc->device); - ifaceErr = ctx->fns.getInterfaceVK( - &backendShared, ffxDevice, initDesc->physicalDevice, ctx->scratchBuffer, ctx->scratchBufferSize, FFX_FSR3_CONTEXT_COUNT); -#else - VkDeviceContext vkDevCtx{}; - vkDevCtx.vkDevice = initDesc->device; - vkDevCtx.vkPhysicalDevice = initDesc->physicalDevice; - vkDevCtx.vkDeviceProcAddr = initDesc->getDeviceProcAddr; - FfxDevice ffxDevice = ctx->fns.getDeviceVK(&vkDevCtx); - ifaceErr = ctx->fns.getInterfaceVK( - &backendShared, ffxDevice, ctx->scratchBuffer, ctx->scratchBufferSize, FFX_FSR3_CONTEXT_COUNT); -#endif - } - if (ifaceErr != FFX_OK) { - const bool wasDx12Backend = (ctx->backend == WrapperBackend::Dx12Bridge); - destroyContext(ctx); - writeError(outErrorText, outErrorTextCapacity, - wasDx12Backend ? "ffxGetInterfaceDX12 failed" - : "ffxGetInterfaceVK failed"); - return -1; - } - - FfxFsr3ContextDescription fsr3Desc{}; - fsr3Desc.flags = FFX_FSR3_ENABLE_AUTO_EXPOSURE | FFX_FSR3_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION; - if (!enableFrameGeneration) fsr3Desc.flags |= FFX_FSR3_ENABLE_UPSCALING_ONLY; - if (initDesc->enableFlags & WOWEE_FSR3_WRAPPER_ENABLE_HDR_INPUT) fsr3Desc.flags |= FFX_FSR3_ENABLE_HIGH_DYNAMIC_RANGE; - if (initDesc->enableFlags & WOWEE_FSR3_WRAPPER_ENABLE_DEPTH_INVERTED) fsr3Desc.flags |= FFX_FSR3_ENABLE_DEPTH_INVERTED; - fsr3Desc.maxRenderSize.width = initDesc->maxRenderWidth; - fsr3Desc.maxRenderSize.height = initDesc->maxRenderHeight; - setUpscaleOutputSizeIfPresent(fsr3Desc, initDesc->displayWidth, initDesc->displayHeight); - fsr3Desc.displaySize.width = initDesc->displayWidth; - fsr3Desc.displaySize.height = initDesc->displayHeight; - if (!backendShared.fpSwapChainConfigureFrameGeneration) { - backendShared.fpSwapChainConfigureFrameGeneration = vkSwapchainConfigureNoop; - } - fsr3Desc.backendInterfaceSharedResources = backendShared; - fsr3Desc.backendInterfaceUpscaling = backendShared; - fsr3Desc.backendInterfaceFrameInterpolation = backendShared; - fsr3Desc.backBufferFormat = mapVkFormatToFfxSurfaceFormat(initDesc->colorFormat, false); - - ctx->fsr3ContextStorage = std::malloc(sizeof(FfxFsr3Context)); - if (!ctx->fsr3ContextStorage) { - destroyContext(ctx); - writeError(outErrorText, outErrorTextCapacity, "FSR3 context allocation failed"); - return -1; - } - std::memset(ctx->fsr3ContextStorage, 0, sizeof(FfxFsr3Context)); - - FfxErrorCode createErr = ctx->fns.fsr3ContextCreate(reinterpret_cast(ctx->fsr3ContextStorage), &fsr3Desc); - if (createErr != FFX_OK) { - destroyContext(ctx); - writeError(outErrorText, outErrorTextCapacity, "ffxFsr3ContextCreate failed"); - return -1; - } - - if (enableFrameGeneration) { - FfxFrameGenerationConfig fgCfg{}; - fgCfg.frameGenerationEnabled = true; - fgCfg.allowAsyncWorkloads = false; - fgCfg.flags = 0; - fgCfg.onlyPresentInterpolated = false; - FfxErrorCode cfgErr = ctx->fns.fsr3ConfigureFrameGeneration(reinterpret_cast(ctx->fsr3ContextStorage), &fgCfg); - if (cfgErr != FFX_OK) { - destroyContext(ctx); - writeError(outErrorText, outErrorTextCapacity, "ffxFsr3ConfigureFrameGeneration failed"); - return -1; - } - ctx->frameGenerationReady = true; - } - - *outContext = reinterpret_cast(ctx); - writeError(outErrorText, outErrorTextCapacity, ""); - return 0; -#endif -} - -WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_upscale(WoweeFsr3WrapperContext context, - const WoweeFsr3WrapperDispatchDesc* dispatchDesc) { -#if !WOWEE_HAS_AMD_FSR3_FRAMEGEN - (void)context; - (void)dispatchDesc; - return -1; -#else - if (!context || !dispatchDesc) return -1; - if (dispatchDesc->structSize < sizeof(WoweeFsr3WrapperDispatchDesc)) return -1; - if (!dispatchDesc->commandBuffer || !dispatchDesc->colorImage || !dispatchDesc->depthImage || - !dispatchDesc->motionVectorImage || !dispatchDesc->outputImage) { - setContextError(reinterpret_cast(context), "invalid dispatch resources for upscale"); - return -1; - } - WrapperContext* ctx = reinterpret_cast(context); -#if defined(_WIN32) - if (ctx->backend == WrapperBackend::Dx12Bridge) { - const uint32_t requiredMask = - WOWEE_FSR3_WRAPPER_EXTERNAL_COLOR_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_DEPTH_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_MOTION_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_ACQUIRE_SEMAPHORE | - WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE; - if ((dispatchDesc->externalFlags & requiredMask) != requiredMask || - dispatchDesc->colorMemoryHandle == 0 || dispatchDesc->depthMemoryHandle == 0 || - dispatchDesc->motionVectorMemoryHandle == 0 || dispatchDesc->outputMemoryHandle == 0 || - dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0 || - dispatchDesc->acquireSemaphoreValue == 0 || dispatchDesc->releaseSemaphoreValue == 0) { - setContextError(ctx, "dx12_bridge dispatch missing required external handles for upscale"); - return -1; - } - if (!ctx->dx12Device) { - setContextError(ctx, "dx12_bridge D3D12 device is unavailable"); - return -1; - } - std::string importError; - if (!openSharedResourceHandle(ctx->dx12Device, dispatchDesc->colorMemoryHandle, "color", importError) || - !openSharedResourceHandle(ctx->dx12Device, dispatchDesc->depthMemoryHandle, "depth", importError) || - !openSharedResourceHandle(ctx->dx12Device, dispatchDesc->motionVectorMemoryHandle, "motion vectors", importError) || - !openSharedResourceHandle(ctx->dx12Device, dispatchDesc->outputMemoryHandle, "upscale output", importError) || - !openSharedFenceHandle(ctx->dx12Device, dispatchDesc->acquireSemaphoreHandle, "acquire semaphore", importError) || - !openSharedFenceHandle(ctx->dx12Device, dispatchDesc->releaseSemaphoreHandle, "release semaphore", importError)) { - setContextError(ctx, importError.c_str()); - return -1; - } - } -#elif defined(__linux__) - if (ctx->backend == WrapperBackend::Dx12Bridge) { - const uint32_t requiredMask = - WOWEE_FSR3_WRAPPER_EXTERNAL_COLOR_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_DEPTH_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_MOTION_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_ACQUIRE_SEMAPHORE | - WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE; - if ((dispatchDesc->externalFlags & requiredMask) != requiredMask || - dispatchDesc->colorMemoryHandle == 0 || dispatchDesc->depthMemoryHandle == 0 || - dispatchDesc->motionVectorMemoryHandle == 0 || dispatchDesc->outputMemoryHandle == 0 || - dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0 || - dispatchDesc->acquireSemaphoreValue == 0 || dispatchDesc->releaseSemaphoreValue == 0) { - setContextError(ctx, "dx12_bridge dispatch missing required external FDs for upscale"); - return -1; - } - } -#endif - - FfxResourceDescription colorDesc = makeResourceDescription( - dispatchDesc->colorFormat, dispatchDesc->renderWidth, dispatchDesc->renderHeight, FFX_RESOURCE_USAGE_READ_ONLY); - FfxResourceDescription depthDesc = makeResourceDescription( - dispatchDesc->depthFormat, dispatchDesc->renderWidth, dispatchDesc->renderHeight, FFX_RESOURCE_USAGE_DEPTHTARGET, true); - FfxResourceDescription mvDesc = makeResourceDescription( - dispatchDesc->motionVectorFormat, dispatchDesc->renderWidth, dispatchDesc->renderHeight, FFX_RESOURCE_USAGE_READ_ONLY); - FfxResourceDescription outDesc = makeResourceDescription( - dispatchDesc->outputFormat, dispatchDesc->outputWidth, dispatchDesc->outputHeight, FFX_RESOURCE_USAGE_UAV); - if (dispatchDesc->renderWidth == 0 || dispatchDesc->renderHeight == 0 || - dispatchDesc->outputWidth == 0 || dispatchDesc->outputHeight == 0) { - setContextError(ctx, "invalid dispatch dimensions for upscale"); - return -1; - } - if (!hasKnownSurfaceFormat(colorDesc) || !hasKnownSurfaceFormat(depthDesc) || - !hasKnownSurfaceFormat(mvDesc) || !hasKnownSurfaceFormat(outDesc)) { - setContextError(ctx, "unsupported image format in upscale dispatch"); - return -1; - } - - static wchar_t kColorName[] = L"FSR3_Color"; - static wchar_t kDepthName[] = L"FSR3_Depth"; - static wchar_t kMotionName[] = L"FSR3_MotionVectors"; - static wchar_t kOutputName[] = L"FSR3_Output"; - FfxFsr3DispatchUpscaleDescription dispatch{}; - bool useDx12Interop = false; -#if defined(_WIN32) - useDx12Interop = (ctx->backend == WrapperBackend::Dx12Bridge); - ID3D12Resource* colorRes = nullptr; - ID3D12Resource* depthRes = nullptr; - ID3D12Resource* motionRes = nullptr; - ID3D12Resource* outputRes = nullptr; - ID3D12Fence* acquireFence = nullptr; - ID3D12Fence* releaseFence = nullptr; - auto cleanupDx12Imports = [&]() { - safeRelease(colorRes); - safeRelease(depthRes); - safeRelease(motionRes); - safeRelease(outputRes); - safeRelease(acquireFence); - safeRelease(releaseFence); - }; -#endif - if (useDx12Interop) { -#if defined(_WIN32) - if (ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->colorMemoryHandle), IID_PPV_ARGS(&colorRes)) != S_OK || - ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->depthMemoryHandle), IID_PPV_ARGS(&depthRes)) != S_OK || - ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->motionVectorMemoryHandle), IID_PPV_ARGS(&motionRes)) != S_OK || - ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->outputMemoryHandle), IID_PPV_ARGS(&outputRes)) != S_OK || - ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->acquireSemaphoreHandle), IID_PPV_ARGS(&acquireFence)) != S_OK || - ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->releaseSemaphoreHandle), IID_PPV_ARGS(&releaseFence)) != S_OK || - !colorRes || !depthRes || !motionRes || !outputRes) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to import one or more upscale resources"); - return -1; - } - if (ctx->dx12CommandAllocator->Reset() != S_OK || - ctx->dx12CommandList->Reset(ctx->dx12CommandAllocator, nullptr) != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to reset DX12 command objects for upscale dispatch"); - return -1; - } - dispatch.commandList = ctx->fns.getCommandListDX12(ctx->dx12CommandList); - dispatch.color = ctx->fns.getResourceDX12(colorRes, colorDesc, kColorName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.depth = ctx->fns.getResourceDX12(depthRes, depthDesc, kDepthName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.motionVectors = ctx->fns.getResourceDX12(motionRes, mvDesc, kMotionName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.upscaleOutput = ctx->fns.getResourceDX12(outputRes, outDesc, kOutputName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); -#endif - } else { - dispatch.commandList = ctx->fns.getCommandListVK(dispatchDesc->commandBuffer); -#if WOWEE_AMD_FFX_SDK_KITS - dispatch.color = ctx->fns.getResourceVK(dispatchDesc->colorImage, colorDesc, kColorName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.depth = ctx->fns.getResourceVK(dispatchDesc->depthImage, depthDesc, kDepthName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.motionVectors = ctx->fns.getResourceVK(dispatchDesc->motionVectorImage, mvDesc, kMotionName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.upscaleOutput = ctx->fns.getResourceVK(dispatchDesc->outputImage, outDesc, kOutputName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); -#else - dispatch.color = ctx->fns.getResourceVK(reinterpret_cast(dispatchDesc->colorImage), colorDesc, kColorName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.depth = ctx->fns.getResourceVK(reinterpret_cast(dispatchDesc->depthImage), depthDesc, kDepthName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.motionVectors = ctx->fns.getResourceVK(reinterpret_cast(dispatchDesc->motionVectorImage), mvDesc, kMotionName, FFX_RESOURCE_STATE_COMPUTE_READ); - dispatch.upscaleOutput = ctx->fns.getResourceVK(reinterpret_cast(dispatchDesc->outputImage), outDesc, kOutputName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); -#endif - } - dispatch.exposure = FfxResource{}; - dispatch.reactive = FfxResource{}; - dispatch.transparencyAndComposition = FfxResource{}; - dispatch.jitterOffset.x = dispatchDesc->jitterX; - dispatch.jitterOffset.y = dispatchDesc->jitterY; - dispatch.motionVectorScale.x = dispatchDesc->motionScaleX; - dispatch.motionVectorScale.y = dispatchDesc->motionScaleY; - dispatch.renderSize.width = dispatchDesc->renderWidth; - dispatch.renderSize.height = dispatchDesc->renderHeight; - dispatch.enableSharpening = false; - dispatch.sharpness = 0.0f; - dispatch.frameTimeDelta = std::max(0.001f, dispatchDesc->frameTimeDeltaMs); - dispatch.preExposure = 1.0f; - dispatch.reset = (dispatchDesc->reset != 0u); - dispatch.cameraNear = dispatchDesc->cameraNear; - dispatch.cameraFar = dispatchDesc->cameraFar; - dispatch.cameraFovAngleVertical = dispatchDesc->cameraFovYRadians; - dispatch.viewSpaceToMetersFactor = 1.0f; - - const bool ok = (ctx->fns.fsr3ContextDispatchUpscale(reinterpret_cast(ctx->fsr3ContextStorage), &dispatch) == FFX_OK); -#if defined(_WIN32) - if (useDx12Interop) { - if (ctx->dx12CommandList->Close() != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to close command list after upscale dispatch"); - return -1; - } - if (acquireFence && ctx->dx12Queue->Wait(acquireFence, dispatchDesc->acquireSemaphoreValue) != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to wait on shared acquire fence before upscale dispatch"); - return -1; - } - ID3D12CommandList* lists[] = {ctx->dx12CommandList}; - ctx->dx12Queue->ExecuteCommandLists(1, lists); - const uint64_t waitValue = ctx->dx12FenceValue++; - if (ctx->dx12Queue->Signal(ctx->dx12Fence, waitValue) != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to signal internal completion fence after upscale dispatch"); - return -1; - } - if (ctx->dx12Fence->GetCompletedValue() < waitValue) { - ctx->dx12Fence->SetEventOnCompletion(waitValue, ctx->dx12FenceEvent); - WaitForSingleObject(ctx->dx12FenceEvent, INFINITE); - } - if (releaseFence && ctx->dx12Queue->Signal(releaseFence, dispatchDesc->releaseSemaphoreValue) != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to signal shared release fence after upscale dispatch"); - return -1; - } - cleanupDx12Imports(); - } -#endif - if (!ok) { - setContextError(ctx, "ffxFsr3ContextDispatchUpscale failed"); - return -1; - } - ctx->lastError.clear(); - return 0; -#endif -} - -WOWEE_FSR3_WRAPPER_EXPORT int32_t wowee_fsr3_wrapper_dispatch_framegen(WoweeFsr3WrapperContext context, - const WoweeFsr3WrapperDispatchDesc* dispatchDesc) { -#if !WOWEE_HAS_AMD_FSR3_FRAMEGEN - (void)context; - (void)dispatchDesc; - return -1; -#else - if (!context || !dispatchDesc) return -1; - if (dispatchDesc->structSize < sizeof(WoweeFsr3WrapperDispatchDesc)) return -1; - if (!dispatchDesc->commandBuffer || !dispatchDesc->outputImage || !dispatchDesc->frameGenOutputImage) { - setContextError(reinterpret_cast(context), "invalid dispatch resources for frame generation"); - return -1; - } - WrapperContext* ctx = reinterpret_cast(context); - if (!ctx->frameGenerationReady || !ctx->fns.fsr3DispatchFrameGeneration) { - setContextError(ctx, "frame generation backend is not ready"); - return -1; - } -#if defined(_WIN32) - if (ctx->backend == WrapperBackend::Dx12Bridge) { - const uint32_t requiredMask = - WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_FRAMEGEN_OUTPUT_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_ACQUIRE_SEMAPHORE | - WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE; - if ((dispatchDesc->externalFlags & requiredMask) != requiredMask || - dispatchDesc->outputMemoryHandle == 0 || dispatchDesc->frameGenOutputMemoryHandle == 0 || - dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0 || - dispatchDesc->acquireSemaphoreValue == 0 || dispatchDesc->releaseSemaphoreValue == 0) { - setContextError(ctx, "dx12_bridge dispatch missing required external handles for frame generation"); - return -1; - } - if (!ctx->dx12Device) { - setContextError(ctx, "dx12_bridge D3D12 device is unavailable"); - return -1; - } - std::string importError; - if (!openSharedResourceHandle(ctx->dx12Device, dispatchDesc->outputMemoryHandle, "present output", importError) || - !openSharedResourceHandle(ctx->dx12Device, dispatchDesc->frameGenOutputMemoryHandle, "framegen output", importError) || - !openSharedFenceHandle(ctx->dx12Device, dispatchDesc->acquireSemaphoreHandle, "acquire semaphore", importError) || - !openSharedFenceHandle(ctx->dx12Device, dispatchDesc->releaseSemaphoreHandle, "release semaphore", importError)) { - setContextError(ctx, importError.c_str()); - return -1; - } - } -#elif defined(__linux__) - if (ctx->backend == WrapperBackend::Dx12Bridge) { - const uint32_t requiredMask = - WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_FRAMEGEN_OUTPUT_MEMORY | - WOWEE_FSR3_WRAPPER_EXTERNAL_ACQUIRE_SEMAPHORE | - WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE; - if ((dispatchDesc->externalFlags & requiredMask) != requiredMask || - dispatchDesc->outputMemoryHandle == 0 || dispatchDesc->frameGenOutputMemoryHandle == 0 || - dispatchDesc->acquireSemaphoreHandle == 0 || dispatchDesc->releaseSemaphoreHandle == 0 || - dispatchDesc->acquireSemaphoreValue == 0 || dispatchDesc->releaseSemaphoreValue == 0) { - setContextError(ctx, "dx12_bridge dispatch missing required external FDs for frame generation"); - return -1; - } - } -#endif - - FfxResourceDescription presentDesc = makeResourceDescription( - dispatchDesc->outputFormat, dispatchDesc->outputWidth, dispatchDesc->outputHeight, FFX_RESOURCE_USAGE_READ_ONLY); - FfxResourceDescription fgOutDesc = makeResourceDescription( - dispatchDesc->outputFormat, dispatchDesc->outputWidth, dispatchDesc->outputHeight, FFX_RESOURCE_USAGE_UAV); - if (dispatchDesc->outputWidth == 0 || dispatchDesc->outputHeight == 0) { - setContextError(ctx, "invalid dispatch dimensions for frame generation"); - return -1; - } - if (!hasKnownSurfaceFormat(presentDesc) || !hasKnownSurfaceFormat(fgOutDesc)) { - setContextError(ctx, "unsupported image format in frame generation dispatch"); - return -1; - } - - static wchar_t kPresentName[] = L"FSR3_PresentColor"; - static wchar_t kInterpolatedName[] = L"FSR3_InterpolatedOutput"; - FfxFrameGenerationDispatchDescription fgDispatch{}; - bool useDx12Interop = false; -#if defined(_WIN32) - useDx12Interop = (ctx->backend == WrapperBackend::Dx12Bridge); - ID3D12Resource* presentRes = nullptr; - ID3D12Resource* framegenRes = nullptr; - ID3D12Fence* acquireFence = nullptr; - ID3D12Fence* releaseFence = nullptr; - auto cleanupDx12Imports = [&]() { - safeRelease(presentRes); - safeRelease(framegenRes); - safeRelease(acquireFence); - safeRelease(releaseFence); - }; -#endif - if (useDx12Interop) { -#if defined(_WIN32) - if (ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->outputMemoryHandle), IID_PPV_ARGS(&presentRes)) != S_OK || - ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->frameGenOutputMemoryHandle), IID_PPV_ARGS(&framegenRes)) != S_OK || - ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->acquireSemaphoreHandle), IID_PPV_ARGS(&acquireFence)) != S_OK || - ctx->dx12Device->OpenSharedHandle(reinterpret_cast(dispatchDesc->releaseSemaphoreHandle), IID_PPV_ARGS(&releaseFence)) != S_OK || - !presentRes || !framegenRes) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to import frame generation resources"); - return -1; - } - if (ctx->dx12CommandAllocator->Reset() != S_OK || - ctx->dx12CommandList->Reset(ctx->dx12CommandAllocator, nullptr) != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to reset DX12 command objects for frame generation dispatch"); - return -1; - } - fgDispatch.commandList = ctx->fns.getCommandListDX12(ctx->dx12CommandList); - fgDispatch.presentColor = ctx->fns.getResourceDX12(presentRes, presentDesc, kPresentName, FFX_RESOURCE_STATE_COMPUTE_READ); - fgDispatch.outputs[0] = ctx->fns.getResourceDX12(framegenRes, fgOutDesc, kInterpolatedName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); -#endif - } else { - fgDispatch.commandList = ctx->fns.getCommandListVK(dispatchDesc->commandBuffer); -#if WOWEE_AMD_FFX_SDK_KITS - fgDispatch.presentColor = ctx->fns.getResourceVK(dispatchDesc->outputImage, presentDesc, kPresentName, FFX_RESOURCE_STATE_COMPUTE_READ); - fgDispatch.outputs[0] = ctx->fns.getResourceVK(dispatchDesc->frameGenOutputImage, fgOutDesc, kInterpolatedName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); -#else - fgDispatch.presentColor = ctx->fns.getResourceVK(reinterpret_cast(dispatchDesc->outputImage), presentDesc, kPresentName, FFX_RESOURCE_STATE_COMPUTE_READ); - fgDispatch.outputs[0] = ctx->fns.getResourceVK(reinterpret_cast(dispatchDesc->frameGenOutputImage), fgOutDesc, kInterpolatedName, FFX_RESOURCE_STATE_UNORDERED_ACCESS); -#endif - } - fgDispatch.numInterpolatedFrames = 1; - fgDispatch.reset = (dispatchDesc->reset != 0u); - fgDispatch.backBufferTransferFunction = ctx->hdrInput - ? FFX_BACKBUFFER_TRANSFER_FUNCTION_SCRGB - : FFX_BACKBUFFER_TRANSFER_FUNCTION_SRGB; - fgDispatch.minMaxLuminance[0] = 0.0f; - fgDispatch.minMaxLuminance[1] = 1.0f; - - const bool ok = (ctx->fns.fsr3DispatchFrameGeneration(&fgDispatch) == FFX_OK); -#if defined(_WIN32) - if (useDx12Interop) { - if (ctx->dx12CommandList->Close() != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to close command list after frame generation dispatch"); - return -1; - } - if (acquireFence && ctx->dx12Queue->Wait(acquireFence, dispatchDesc->acquireSemaphoreValue) != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to wait on shared acquire fence before frame generation dispatch"); - return -1; - } - ID3D12CommandList* lists[] = {ctx->dx12CommandList}; - ctx->dx12Queue->ExecuteCommandLists(1, lists); - const uint64_t waitValue = ctx->dx12FenceValue++; - if (ctx->dx12Queue->Signal(ctx->dx12Fence, waitValue) != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to signal internal completion fence after frame generation dispatch"); - return -1; - } - if (ctx->dx12Fence->GetCompletedValue() < waitValue) { - ctx->dx12Fence->SetEventOnCompletion(waitValue, ctx->dx12FenceEvent); - WaitForSingleObject(ctx->dx12FenceEvent, INFINITE); - } - if (releaseFence && ctx->dx12Queue->Signal(releaseFence, dispatchDesc->releaseSemaphoreValue) != S_OK) { - cleanupDx12Imports(); - setContextError(ctx, "dx12_bridge failed to signal shared release fence after frame generation dispatch"); - return -1; - } - cleanupDx12Imports(); - } -#endif - if (!ok) { - setContextError(ctx, "ffxFsr3DispatchFrameGeneration failed"); - return -1; - } - ctx->lastError.clear(); - return 0; -#endif -} - -WOWEE_FSR3_WRAPPER_EXPORT void wowee_fsr3_wrapper_shutdown(WoweeFsr3WrapperContext context) { -#if WOWEE_HAS_AMD_FSR3_FRAMEGEN - WrapperContext* ctx = reinterpret_cast(context); - destroyContext(ctx); -#else - (void)context; -#endif -} - -WOWEE_FSR3_WRAPPER_EXPORT const char* wowee_fsr3_wrapper_get_last_error(WoweeFsr3WrapperContext context) { -#if WOWEE_HAS_AMD_FSR3_FRAMEGEN - WrapperContext* ctx = reinterpret_cast(context); - if (!ctx) return "invalid wrapper context"; - return ctx->lastError.c_str(); -#else - (void)context; - return "wrapper built without WOWEE_HAS_AMD_FSR3_FRAMEGEN"; -#endif -} diff --git a/src/rendering/amd_fsr3_wrapper_runtime_smoke.cpp b/src/rendering/amd_fsr3_wrapper_runtime_smoke.cpp deleted file mode 100644 index 9b14e865..00000000 --- a/src/rendering/amd_fsr3_wrapper_runtime_smoke.cpp +++ /dev/null @@ -1,107 +0,0 @@ -#include "rendering/amd_fsr3_wrapper_abi.h" - -#include -#include -#include - -#if defined(_WIN32) -#include -using LibHandle = HMODULE; -static LibHandle openLibrary(const char* path) { return LoadLibraryA(path); } -static void* loadSymbol(LibHandle lib, const char* name) { - return lib ? reinterpret_cast(GetProcAddress(lib, name)) : nullptr; -} -static void closeLibrary(LibHandle lib) { - if (lib) FreeLibrary(lib); -} -#else -#include -using LibHandle = void*; -static LibHandle openLibrary(const char* path) { return dlopen(path, RTLD_NOW | RTLD_LOCAL); } -static void* loadSymbol(LibHandle lib, const char* name) { return lib ? dlsym(lib, name) : nullptr; } -static void closeLibrary(LibHandle lib) { - if (lib) dlclose(lib); -} -#endif - -int main(int argc, char** argv) { - const char* libPath = (argc > 1) ? argv[1] -#if defined(_WIN32) - : "ffx_fsr3_vk_wrapper.dll"; -#elif defined(__APPLE__) - : "libffx_fsr3_vk_wrapper.dylib"; -#else - : "./build/bin/libffx_fsr3_vk_wrapper.so"; -#endif - - LibHandle lib = openLibrary(libPath); - if (!lib) { - std::cerr << "smoke: failed to load wrapper library: " << libPath << "\n"; - return 2; - } - - auto getAbiVersion = reinterpret_cast( - loadSymbol(lib, "wowee_fsr3_wrapper_get_abi_version")); - auto getName = reinterpret_cast( - loadSymbol(lib, "wowee_fsr3_wrapper_get_name")); - auto getBackend = reinterpret_cast( - loadSymbol(lib, "wowee_fsr3_wrapper_get_backend")); - auto getCaps = reinterpret_cast( - loadSymbol(lib, "wowee_fsr3_wrapper_get_capabilities")); - auto initialize = reinterpret_cast( - loadSymbol(lib, "wowee_fsr3_wrapper_initialize")); - auto dispatchUpscale = reinterpret_cast( - loadSymbol(lib, "wowee_fsr3_wrapper_dispatch_upscale")); - auto shutdown = reinterpret_cast( - loadSymbol(lib, "wowee_fsr3_wrapper_shutdown")); - - if (!getAbiVersion || !getName || !getBackend || !getCaps || !initialize || !dispatchUpscale || !shutdown) { - std::cerr << "smoke: required wrapper ABI symbol(s) missing\n"; - closeLibrary(lib); - return 3; - } - - const uint32_t abi = getAbiVersion(); - if (abi != WOWEE_FSR3_WRAPPER_ABI_VERSION) { - std::cerr << "smoke: ABI mismatch: got " << abi - << ", expected " << WOWEE_FSR3_WRAPPER_ABI_VERSION << "\n"; - closeLibrary(lib); - return 4; - } - - const char* name = getName(); - if (!name || !*name) { - std::cerr << "smoke: wrapper name is empty\n"; - closeLibrary(lib); - return 5; - } - - const char* backendNull = getBackend(nullptr); - if (!backendNull || !*backendNull) { - std::cerr << "smoke: get_backend(null) returned empty\n"; - closeLibrary(lib); - return 6; - } - - const uint32_t capsNull = getCaps(nullptr); - if (capsNull != 0u) { - std::cerr << "smoke: expected get_capabilities(null)=0, got " << capsNull << "\n"; - closeLibrary(lib); - return 7; - } - - char errorBuf[128] = {}; - WoweeFsr3WrapperContext ctx = nullptr; - const int32_t initRes = initialize(nullptr, &ctx, errorBuf, static_cast(sizeof(errorBuf))); - if (initRes == 0) { - std::cerr << "smoke: initialize(nullptr, ...) unexpectedly succeeded\n"; - shutdown(ctx); - closeLibrary(lib); - return 8; - } - - std::cout << "smoke: OK abi=" << abi << " name=" << name - << " backend(null)=" << backendNull << "\n"; - closeLibrary(lib); - return 0; -} diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 7f9b6628..e53b261b 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -58,7 +58,6 @@ #include "rendering/vk_pipeline.hpp" #include "rendering/vk_utils.hpp" #include "rendering/amd_fsr3_runtime.hpp" -#include "rendering/amd_fsr3_wrapper_abi.h" #include #include #include @@ -116,115 +115,7 @@ static int envIntOrDefault(const char* key, int defaultValue) { return static_cast(n); } -#if defined(_WIN32) -static uint64_t exportImageMemoryHandleWin32(VkDevice device, PFN_vkGetDeviceProcAddr getDeviceProcAddr, - VmaAllocator allocator, const AllocatedImage& image) { -#if defined(VK_USE_PLATFORM_WIN32_KHR) && defined(VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR) && defined(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT) - if (!device || !getDeviceProcAddr || !allocator || !image.allocation) return 0; - auto getMemHandle = reinterpret_cast( - getDeviceProcAddr(device, "vkGetMemoryWin32HandleKHR")); - if (!getMemHandle) return 0; - VmaAllocationInfo allocInfo{}; - vmaGetAllocationInfo(allocator, image.allocation, &allocInfo); - if (allocInfo.deviceMemory == VK_NULL_HANDLE) return 0; - - VkMemoryGetWin32HandleInfoKHR handleInfo{}; - handleInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR; - handleInfo.memory = allocInfo.deviceMemory; - handleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; - - HANDLE outHandle = nullptr; - if (getMemHandle(device, &handleInfo, &outHandle) != VK_SUCCESS || !outHandle) return 0; - return reinterpret_cast(outHandle); -#else - (void)device; - (void)getDeviceProcAddr; - (void)allocator; - (void)image; - return 0; -#endif -} - -static uint64_t exportSemaphoreHandleWin32(VkDevice device, PFN_vkGetDeviceProcAddr getDeviceProcAddr, - VkSemaphore semaphore) { -#if defined(VK_USE_PLATFORM_WIN32_KHR) && defined(VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR) && defined(VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT) - if (!device || !getDeviceProcAddr || !semaphore) return 0; - auto getSemHandle = reinterpret_cast( - getDeviceProcAddr(device, "vkGetSemaphoreWin32HandleKHR")); - if (!getSemHandle) return 0; - - VkSemaphoreGetWin32HandleInfoKHR handleInfo{}; - handleInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_WIN32_HANDLE_INFO_KHR; - handleInfo.semaphore = semaphore; - handleInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT; - - HANDLE outHandle = nullptr; - if (getSemHandle(device, &handleInfo, &outHandle) != VK_SUCCESS || !outHandle) return 0; - return reinterpret_cast(outHandle); -#else - (void)device; - (void)getDeviceProcAddr; - (void)semaphore; - return 0; -#endif -} -#endif - -#if defined(__linux__) -static uint64_t exportImageMemoryHandleFd(VkDevice device, PFN_vkGetDeviceProcAddr getDeviceProcAddr, - VmaAllocator allocator, const AllocatedImage& image) { -#if !defined(VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR) || !defined(VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) - (void)device; - (void)getDeviceProcAddr; - (void)allocator; - (void)image; - return 0; -#else - if (!device || !getDeviceProcAddr || !allocator || !image.allocation) return 0; - auto getMemFd = reinterpret_cast( - getDeviceProcAddr(device, "vkGetMemoryFdKHR")); - if (!getMemFd) return 0; - - VmaAllocationInfo allocInfo{}; - vmaGetAllocationInfo(allocator, image.allocation, &allocInfo); - if (allocInfo.deviceMemory == VK_NULL_HANDLE) return 0; - - VkMemoryGetFdInfoKHR fdInfo{}; - fdInfo.sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR; - fdInfo.memory = allocInfo.deviceMemory; - fdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; - - int outFd = -1; - if (getMemFd(device, &fdInfo, &outFd) != VK_SUCCESS || outFd < 0) return 0; - return static_cast(static_cast(outFd)); -#endif -} - -static uint64_t exportSemaphoreHandleFd(VkDevice device, PFN_vkGetDeviceProcAddr getDeviceProcAddr, - VkSemaphore semaphore) { -#if !defined(VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR) || !defined(VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT) - (void)device; - (void)getDeviceProcAddr; - (void)semaphore; - return 0; -#else - if (!device || !getDeviceProcAddr || !semaphore) return 0; - auto getSemFd = reinterpret_cast( - getDeviceProcAddr(device, "vkGetSemaphoreFdKHR")); - if (!getSemFd) return 0; - - VkSemaphoreGetFdInfoKHR fdInfo{}; - fdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR; - fdInfo.semaphore = semaphore; - fdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT; - - int outFd = -1; - if (getSemFd(device, &fdInfo, &outFd) != VK_SUCCESS || outFd < 0) return 0; - return static_cast(static_cast(outFd)); -#endif -} -#endif static std::vector parseEmoteCommands(const std::string& raw) { std::vector out; @@ -3758,9 +3649,9 @@ bool Renderer::initFSRResources() { void Renderer::destroyFSRResources() { if (!vkCtx) return; + VkDevice device = vkCtx->getDevice(); VmaAllocator alloc = vkCtx->getAllocator(); - vkDeviceWaitIdle(device); if (fsr_.pipeline) { vkDestroyPipeline(device, fsr_.pipeline, nullptr); fsr_.pipeline = VK_NULL_HANDLE; } @@ -4293,9 +4184,9 @@ bool Renderer::initFSR2Resources() { void Renderer::destroyFSR2Resources() { if (!vkCtx) return; + VkDevice device = vkCtx->getDevice(); VmaAllocator alloc = vkCtx->getAllocator(); - vkDeviceWaitIdle(device); #if WOWEE_HAS_AMD_FSR2 @@ -4542,8 +4433,6 @@ void Renderer::dispatchAmdFsr2() { void Renderer::dispatchAmdFsr3Framegen() { #if WOWEE_HAS_AMD_FSR3_FRAMEGEN - VkDevice device = vkCtx->getDevice(); - VmaAllocator alloc = vkCtx->getAllocator(); if (!fsr2_.amdFsr3FramegenEnabled) { fsr2_.amdFsr3FramegenRuntimeActive = false; return; @@ -4604,127 +4493,6 @@ void Renderer::dispatchAmdFsr3Framegen() { fgDispatch.cameraFovYRadians = camera ? glm::radians(camera->getFovDegrees()) : 1.0f; fgDispatch.reset = fsr2_.needsHistoryReset; -#if defined(_WIN32) || defined(__linux__) -#if defined(_WIN32) - using ExportHandle = HANDLE; -#else - using ExportHandle = int; -#endif - bool exportInteropHandles = false; - if (fsr2_.amdFsr3Runtime && fsr2_.amdFsr3Runtime->hasWrapperExternalInterop()) { - exportInteropHandles = true; - } - - std::vector exportedHandles; - auto trackHandle = [&](uint64_t h) { - if (!h) return; - ExportHandle raw = -#if defined(_WIN32) - reinterpret_cast(h); -#else - static_cast(static_cast(h)); -#endif - exportedHandles.push_back(raw); - }; - auto cleanupExportedHandles = [&]() { - for (ExportHandle h : exportedHandles) { -#if defined(_WIN32) - if (h) CloseHandle(h); -#else - if (h >= 0) close(h); -#endif - } - exportedHandles.clear(); - }; - - fgDispatch.externalFlags = 0; - if (exportInteropHandles) { -#if defined(_WIN32) - fgDispatch.colorMemoryHandle = exportImageMemoryHandleWin32( - device, vkGetDeviceProcAddr, alloc, fsr2_.sceneColor); -#else - fgDispatch.colorMemoryHandle = exportImageMemoryHandleFd( - device, vkGetDeviceProcAddr, alloc, fsr2_.sceneColor); -#endif - if (fgDispatch.colorMemoryHandle) { - fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_COLOR_MEMORY; - trackHandle(fgDispatch.colorMemoryHandle); - } -#if defined(_WIN32) - fgDispatch.depthMemoryHandle = exportImageMemoryHandleWin32( - device, vkGetDeviceProcAddr, alloc, fsr2_.sceneDepth); -#else - fgDispatch.depthMemoryHandle = exportImageMemoryHandleFd( - device, vkGetDeviceProcAddr, alloc, fsr2_.sceneDepth); -#endif - if (fgDispatch.depthMemoryHandle) { - fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_DEPTH_MEMORY; - trackHandle(fgDispatch.depthMemoryHandle); - } -#if defined(_WIN32) - fgDispatch.motionVectorMemoryHandle = exportImageMemoryHandleWin32( - device, vkGetDeviceProcAddr, alloc, fsr2_.motionVectors); -#else - fgDispatch.motionVectorMemoryHandle = exportImageMemoryHandleFd( - device, vkGetDeviceProcAddr, alloc, fsr2_.motionVectors); -#endif - if (fgDispatch.motionVectorMemoryHandle) { - fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_MOTION_MEMORY; - trackHandle(fgDispatch.motionVectorMemoryHandle); - } -#if defined(_WIN32) - fgDispatch.outputMemoryHandle = exportImageMemoryHandleWin32( - device, vkGetDeviceProcAddr, alloc, fsr2_.history[fsr2_.currentHistory]); -#else - fgDispatch.outputMemoryHandle = exportImageMemoryHandleFd( - device, vkGetDeviceProcAddr, alloc, fsr2_.history[fsr2_.currentHistory]); -#endif - if (fgDispatch.outputMemoryHandle) { - fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_OUTPUT_MEMORY; - trackHandle(fgDispatch.outputMemoryHandle); - } -#if defined(_WIN32) - fgDispatch.frameGenOutputMemoryHandle = exportImageMemoryHandleWin32( - device, vkGetDeviceProcAddr, alloc, fsr2_.framegenOutput); -#else - fgDispatch.frameGenOutputMemoryHandle = exportImageMemoryHandleFd( - device, vkGetDeviceProcAddr, alloc, fsr2_.framegenOutput); -#endif - if (fgDispatch.frameGenOutputMemoryHandle) { - fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_FRAMEGEN_OUTPUT_MEMORY; - trackHandle(fgDispatch.frameGenOutputMemoryHandle); - } - - const FrameData& frameData = vkCtx->getCurrentFrameData(); -#if defined(_WIN32) - fgDispatch.acquireSemaphoreHandle = exportSemaphoreHandleWin32( - device, vkGetDeviceProcAddr, frameData.imageAvailableSemaphore); -#else - fgDispatch.acquireSemaphoreHandle = exportSemaphoreHandleFd( - device, vkGetDeviceProcAddr, frameData.imageAvailableSemaphore); -#endif - if (fgDispatch.acquireSemaphoreHandle) { - fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_ACQUIRE_SEMAPHORE; - trackHandle(fgDispatch.acquireSemaphoreHandle); - } -#if defined(_WIN32) - fgDispatch.releaseSemaphoreHandle = exportSemaphoreHandleWin32( - device, vkGetDeviceProcAddr, frameData.renderFinishedSemaphore); -#else - fgDispatch.releaseSemaphoreHandle = exportSemaphoreHandleFd( - device, vkGetDeviceProcAddr, frameData.renderFinishedSemaphore); -#endif - if (fgDispatch.releaseSemaphoreHandle) { - fgDispatch.externalFlags |= WOWEE_FSR3_WRAPPER_EXTERNAL_RELEASE_SEMAPHORE; - trackHandle(fgDispatch.releaseSemaphoreHandle); - } - uint64_t syncValue = fsr2_.amdFsr3InteropSyncValue; - if (syncValue == 0) syncValue = 1; - fgDispatch.acquireSemaphoreValue = syncValue; - fgDispatch.releaseSemaphoreValue = syncValue; - fsr2_.amdFsr3InteropSyncValue = syncValue + 1; - } -#endif if (!fsr2_.amdFsr3Runtime->dispatchUpscale(fgDispatch)) { static bool warnedRuntimeDispatch = false; @@ -4735,9 +4503,6 @@ void Renderer::dispatchAmdFsr3Framegen() { fsr2_.amdFsr3RuntimeLastError = fsr2_.amdFsr3Runtime->lastError(); fsr2_.amdFsr3FallbackCount++; fsr2_.amdFsr3FramegenRuntimeActive = false; -#if defined(_WIN32) || defined(__linux__) - cleanupExportedHandles(); -#endif return; } fsr2_.amdFsr3RuntimeLastError.clear(); @@ -4745,16 +4510,10 @@ void Renderer::dispatchAmdFsr3Framegen() { if (!fsr2_.amdFsr3FramegenEnabled) { fsr2_.amdFsr3FramegenRuntimeActive = false; -#if defined(_WIN32) || defined(__linux__) - cleanupExportedHandles(); -#endif return; } if (!fsr2_.amdFsr3Runtime->isFrameGenerationReady()) { fsr2_.amdFsr3FramegenRuntimeActive = false; -#if defined(_WIN32) || defined(__linux__) - cleanupExportedHandles(); -#endif return; } if (!fsr2_.amdFsr3Runtime->dispatchFrameGeneration(fgDispatch)) { @@ -4766,18 +4525,12 @@ void Renderer::dispatchAmdFsr3Framegen() { fsr2_.amdFsr3RuntimeLastError = fsr2_.amdFsr3Runtime->lastError(); fsr2_.amdFsr3FallbackCount++; fsr2_.amdFsr3FramegenRuntimeActive = false; -#if defined(_WIN32) || defined(__linux__) - cleanupExportedHandles(); -#endif return; } fsr2_.amdFsr3RuntimeLastError.clear(); fsr2_.amdFsr3FramegenDispatchCount++; fsr2_.framegenOutputValid = true; fsr2_.amdFsr3FramegenRuntimeActive = true; -#if defined(_WIN32) || defined(__linux__) - cleanupExportedHandles(); -#endif #else fsr2_.amdFsr3FramegenRuntimeActive = false; #endif