Remove FSR3 wrapper path and keep official Path-A runtime only

This commit is contained in:
Kelsi 2026-03-09 04:33:05 -07:00
parent 9ff9f2f1f1
commit 1c7b87ee78
9 changed files with 46 additions and 2208 deletions

View file

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

View file

@ -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/<amd-runtime-library>`
- If runtime is missing, FG is cleanly unavailable (Path C).
### Current FSR Defaults

View file

@ -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=<path-to-amd_fidelityfx_framegeneration_dx12.dll>`
- 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

View file

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

View file

@ -1,104 +0,0 @@
#pragma once
#include <stdint.h>
#include <vulkan/vulkan.h>
#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

View file

@ -1,5 +1,4 @@
#include "rendering/amd_fsr3_runtime.hpp"
#include "rendering/amd_fsr3_wrapper_abi.h"
#include <algorithm>
#include <cstdlib>
@ -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<Candidate> candidates;
std::vector<std::string> 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<void*>(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_cast<decltype(fns_->wrapperGetAbiVersion)>(resolveSym("wowee_fsr3_wrapper_get_abi_version"));
fns_->wrapperGetName = reinterpret_cast<decltype(fns_->wrapperGetName)>(resolveSym("wowee_fsr3_wrapper_get_name"));
fns_->wrapperGetBackend = reinterpret_cast<decltype(fns_->wrapperGetBackend)>(resolveSym("wowee_fsr3_wrapper_get_backend"));
fns_->wrapperGetCapabilities = reinterpret_cast<decltype(fns_->wrapperGetCapabilities)>(resolveSym("wowee_fsr3_wrapper_get_capabilities"));
fns_->wrapperInitialize = reinterpret_cast<decltype(fns_->wrapperInitialize)>(resolveSym("wowee_fsr3_wrapper_initialize"));
fns_->wrapperDispatchUpscale = reinterpret_cast<decltype(fns_->wrapperDispatchUpscale)>(resolveSym("wowee_fsr3_wrapper_dispatch_upscale"));
fns_->wrapperDispatchFramegen = reinterpret_cast<decltype(fns_->wrapperDispatchFramegen)>(resolveSym("wowee_fsr3_wrapper_dispatch_framegen"));
fns_->wrapperShutdown = reinterpret_cast<decltype(fns_->wrapperShutdown)>(resolveSym("wowee_fsr3_wrapper_shutdown"));
fns_->wrapperGetLastError = reinterpret_cast<decltype(fns_->wrapperGetLastError)>(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<uint32_t>(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<unsigned int>(wrapperCaps));
}
}
LOG_INFO("FSR3 runtime: loaded wrapper library ", loadedLibraryPath_,
" framegenReady=", frameGenerationReady_ ? "yes" : "no");
return true;
}
fns_->getScratchMemorySizeVK = reinterpret_cast<decltype(fns_->getScratchMemorySizeVK)>(resolveSym("ffxGetScratchMemorySizeVK"));
fns_->getDeviceVK = reinterpret_cast<decltype(fns_->getDeviceVK)>(resolveSym("ffxGetDeviceVK"));
fns_->getInterfaceVK = reinterpret_cast<decltype(fns_->getInterfaceVK)>(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<WoweeFsr3WrapperContext>(wrapperContext_), &wrapperDesc) == 0;
if (!ok) {
if (fns_->wrapperGetLastError) {
const char* err = fns_->wrapperGetLastError(static_cast<WoweeFsr3WrapperContext>(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<void*>(desc.colorImage), colorDesc, kColorName, FFX_RESOURCE_STATE_COMPUTE_READ);
dispatch.depth = fns_->getResourceVK(reinterpret_cast<void*>(desc.depthImage), depthDesc, kDepthName, FFX_RESOURCE_STATE_COMPUTE_READ);
dispatch.motionVectors = fns_->getResourceVK(reinterpret_cast<void*>(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<void*>(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<WoweeFsr3WrapperContext>(wrapperContext_), &wrapperDesc) == 0;
if (!ok) {
if (fns_->wrapperGetLastError) {
const char* err = fns_->wrapperGetLastError(static_cast<WoweeFsr3WrapperContext>(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<void*>(desc.outputImage), presentDesc, kPresentName, FFX_RESOURCE_STATE_COMPUTE_READ);
fgDispatch.outputs[0] = fns_->getResourceVK(
reinterpret_cast<void*>(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<WoweeFsr3WrapperContext>(wrapperContext_));
}
wrapperContext_ = nullptr;
if (contextStorage_ && fns_ && fns_->fsr3ContextDestroy) {
fns_->fsr3ContextDestroy(reinterpret_cast<FfxFsr3Context*>(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

File diff suppressed because it is too large Load diff

View file

@ -1,107 +0,0 @@
#include "rendering/amd_fsr3_wrapper_abi.h"
#include <cstdint>
#include <cstring>
#include <iostream>
#if defined(_WIN32)
#include <windows.h>
using LibHandle = HMODULE;
static LibHandle openLibrary(const char* path) { return LoadLibraryA(path); }
static void* loadSymbol(LibHandle lib, const char* name) {
return lib ? reinterpret_cast<void*>(GetProcAddress(lib, name)) : nullptr;
}
static void closeLibrary(LibHandle lib) {
if (lib) FreeLibrary(lib);
}
#else
#include <dlfcn.h>
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<uint32_t (*)()>(
loadSymbol(lib, "wowee_fsr3_wrapper_get_abi_version"));
auto getName = reinterpret_cast<const char* (*)()>(
loadSymbol(lib, "wowee_fsr3_wrapper_get_name"));
auto getBackend = reinterpret_cast<const char* (*)(WoweeFsr3WrapperContext)>(
loadSymbol(lib, "wowee_fsr3_wrapper_get_backend"));
auto getCaps = reinterpret_cast<uint32_t (*)(WoweeFsr3WrapperContext)>(
loadSymbol(lib, "wowee_fsr3_wrapper_get_capabilities"));
auto initialize = reinterpret_cast<int32_t (*)(const WoweeFsr3WrapperInitDesc*, WoweeFsr3WrapperContext*, char*, uint32_t)>(
loadSymbol(lib, "wowee_fsr3_wrapper_initialize"));
auto dispatchUpscale = reinterpret_cast<int32_t (*)(WoweeFsr3WrapperContext, const WoweeFsr3WrapperDispatchDesc*)>(
loadSymbol(lib, "wowee_fsr3_wrapper_dispatch_upscale"));
auto shutdown = reinterpret_cast<void (*)(WoweeFsr3WrapperContext)>(
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<uint32_t>(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;
}

View file

@ -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 <imgui.h>
#include <imgui_impl_vulkan.h>
#include <glm/gtc/matrix_transform.hpp>
@ -116,115 +115,7 @@ static int envIntOrDefault(const char* key, int defaultValue) {
return static_cast<int>(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<PFN_vkGetMemoryWin32HandleKHR>(
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<uint64_t>(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<PFN_vkGetSemaphoreWin32HandleKHR>(
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<uint64_t>(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<PFN_vkGetMemoryFdKHR>(
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<uint64_t>(static_cast<uint32_t>(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<PFN_vkGetSemaphoreFdKHR>(
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<uint64_t>(static_cast<uint32_t>(outFd));
#endif
}
#endif
static std::vector<std::string> parseEmoteCommands(const std::string& raw) {
std::vector<std::string> 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<ExportHandle> exportedHandles;
auto trackHandle = [&](uint64_t h) {
if (!h) return;
ExportHandle raw =
#if defined(_WIN32)
reinterpret_cast<ExportHandle>(h);
#else
static_cast<ExportHandle>(static_cast<int>(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