diff --git a/README.md b/README.md index cf7b67db..4df25ec1 100644 --- a/README.md +++ b/README.md @@ -197,7 +197,10 @@ 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. - - Current state is staging-only (`dispatch not linked yet`) until FidelityFX-SDK runtime component binaries are integrated. + - 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). + - Current state is still dispatch-staged until full FI/OF dispatch activation is linked. ### Current FSR Defaults diff --git a/docs/AMD_FSR2_INTEGRATION.md b/docs/AMD_FSR2_INTEGRATION.md index f58be84b..867571ad 100644 --- a/docs/AMD_FSR2_INTEGRATION.md +++ b/docs/AMD_FSR2_INTEGRATION.md @@ -36,7 +36,10 @@ Detection expects: Runtime note: - Renderer/UI now expose a persisted experimental framegen toggle. -- Current runtime status is `staged` (no FI/OF dispatch yet) until FidelityFX-SDK runtime implementation/shader blob linking is completed. +- Runtime loader now probes for AMD FSR3 SDK runtime binaries. +- You can point to an explicit runtime binary with: + - `WOWEE_FFX_SDK_RUNTIME_LIB=/absolute/path/to/libffx_fsr3_vk.so` (or `.dll` / `.dylib`). +- Current runtime status is still `dispatch staged` (FI/OF dispatch activation pending). ## Current Status diff --git a/include/rendering/renderer.hpp b/include/rendering/renderer.hpp index 5c5342bb..4b764baf 100644 --- a/include/rendering/renderer.hpp +++ b/include/rendering/renderer.hpp @@ -291,6 +291,7 @@ public: bool isAmdFsr3FramegenSdkAvailable() const { return false; } #endif bool isAmdFsr3FramegenRuntimeActive() const { return fsr2_.amdFsr3FramegenRuntimeActive; } + bool isAmdFsr3FramegenRuntimeReady() const { return fsr2_.amdFsr3FramegenRuntimeReady; } void setWaterRefractionEnabled(bool enabled); bool isWaterRefractionEnabled() const; diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index 121e75de..1db52d51 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -71,6 +71,13 @@ #include #include #include +#if WOWEE_HAS_AMD_FSR3_FRAMEGEN +#if defined(_WIN32) +#include +#else +#include +#endif +#endif namespace wowee { namespace rendering { @@ -109,6 +116,63 @@ static int envIntOrDefault(const char* key, int defaultValue) { return static_cast(n); } +#if WOWEE_HAS_AMD_FSR3_FRAMEGEN +struct AmdFsr3RuntimeApi { + void* libHandle = nullptr; + std::string loadedPath; + + bool load() { + if (libHandle) return true; + + std::vector candidates; + if (const char* envPath = std::getenv("WOWEE_FFX_SDK_RUNTIME_LIB")) { + if (*envPath) candidates.emplace_back(envPath); + } +#if defined(_WIN32) + candidates.emplace_back("ffx_fsr3_vk.dll"); + candidates.emplace_back("ffx_fsr3.dll"); +#elif defined(__APPLE__) + candidates.emplace_back("libffx_fsr3_vk.dylib"); + candidates.emplace_back("libffx_fsr3.dylib"); +#else + candidates.emplace_back("libffx_fsr3_vk.so"); + candidates.emplace_back("libffx_fsr3.so"); +#endif + + for (const std::string& path : candidates) { +#if defined(_WIN32) + HMODULE h = LoadLibraryA(path.c_str()); + if (!h) continue; + libHandle = reinterpret_cast(h); +#else + void* h = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL); + if (!h) continue; + libHandle = h; +#endif + loadedPath = path; + return true; + } + return false; + } + + void unload() { + if (!libHandle) return; +#if defined(_WIN32) + FreeLibrary(reinterpret_cast(libHandle)); +#else + dlclose(libHandle); +#endif + libHandle = nullptr; + loadedPath.clear(); + } +}; + +static AmdFsr3RuntimeApi& getAmdFsr3RuntimeApi() { + static AmdFsr3RuntimeApi s_runtimeApi; + return s_runtimeApi; +} +#endif + static std::vector parseEmoteCommands(const std::string& raw) { std::vector out; std::string cur; @@ -3843,11 +3907,15 @@ bool Renderer::initFSR2Resources() { LOG_INFO("FSR2 AMD: context created successfully."); #if WOWEE_HAS_AMD_FSR3_FRAMEGEN if (fsr2_.amdFsr3FramegenEnabled) { - // Runtime dispatch path is staged behind SDK runtime binary integration. - // Keep the user toggle persisted, but report inactive runtime for now. fsr2_.amdFsr3FramegenRuntimeActive = false; - fsr2_.amdFsr3FramegenRuntimeReady = false; - LOG_WARNING("FSR3 framegen is enabled in settings, but runtime dispatch is not linked yet; running FSR2-only."); + fsr2_.amdFsr3FramegenRuntimeReady = getAmdFsr3RuntimeApi().load(); + if (fsr2_.amdFsr3FramegenRuntimeReady) { + LOG_INFO("FSR3 framegen runtime library loaded from ", getAmdFsr3RuntimeApi().loadedPath, + " (dispatch staged)"); + } else { + LOG_WARNING("FSR3 framegen toggle is enabled, but runtime library was not found. ", + "Set WOWEE_FFX_SDK_RUNTIME_LIB to the SDK runtime binary path."); + } } #endif } else { @@ -4149,6 +4217,9 @@ void Renderer::destroyFSR2Resources() { #endif fsr2_.amdFsr3FramegenRuntimeActive = false; fsr2_.amdFsr3FramegenRuntimeReady = false; +#if WOWEE_HAS_AMD_FSR3_FRAMEGEN + getAmdFsr3RuntimeApi().unload(); +#endif if (fsr2_.sharpenPipeline) { vkDestroyPipeline(device, fsr2_.sharpenPipeline, nullptr); fsr2_.sharpenPipeline = VK_NULL_HANDLE; } if (fsr2_.sharpenPipelineLayout) { vkDestroyPipelineLayout(device, fsr2_.sharpenPipelineLayout, nullptr); fsr2_.sharpenPipelineLayout = VK_NULL_HANDLE; } @@ -4376,11 +4447,14 @@ void Renderer::dispatchAmdFsr3Framegen() { // Runtime FI/OF dispatch requires linked FidelityFX-SDK implementation binaries. // The integration hook is intentionally placed here (right after FSR2 dispatch), // so we can enable real frame generation without refactoring the frame pipeline. + if (!fsr2_.amdFsr3FramegenRuntimeReady) { + fsr2_.amdFsr3FramegenRuntimeReady = getAmdFsr3RuntimeApi().load(); + } if (!fsr2_.amdFsr3FramegenRuntimeReady) { static bool warnedMissingRuntime = false; if (!warnedMissingRuntime) { warnedMissingRuntime = true; - LOG_WARNING("FSR3 framegen is staged, but runtime binaries are not linked; skipping frame generation dispatch."); + LOG_WARNING("FSR3 framegen runtime library not found; skipping frame generation dispatch."); } } fsr2_.amdFsr3FramegenRuntimeActive = false; @@ -4469,11 +4543,18 @@ void Renderer::setAmdFsr3FramegenEnabled(bool enabled) { #if WOWEE_HAS_AMD_FSR3_FRAMEGEN if (enabled) { fsr2_.amdFsr3FramegenRuntimeActive = false; - fsr2_.amdFsr3FramegenRuntimeReady = false; - LOG_WARNING("FSR3 framegen toggle enabled, but runtime dispatch is not linked yet; running FSR2-only."); + fsr2_.amdFsr3FramegenRuntimeReady = getAmdFsr3RuntimeApi().load(); + if (fsr2_.amdFsr3FramegenRuntimeReady) { + LOG_INFO("FSR3 framegen runtime library loaded from ", getAmdFsr3RuntimeApi().loadedPath, + " (dispatch staged)."); + } else { + LOG_WARNING("FSR3 framegen enabled, but runtime library not found. ", + "Set WOWEE_FFX_SDK_RUNTIME_LIB to the runtime binary path."); + } } else { fsr2_.amdFsr3FramegenRuntimeActive = false; fsr2_.amdFsr3FramegenRuntimeReady = false; + getAmdFsr3RuntimeApi().unload(); } #else fsr2_.amdFsr3FramegenRuntimeActive = false; diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index ebb8e761..8b6e2175 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -6342,8 +6342,15 @@ void GameScreen::renderSettingsWindow() { renderer->setAmdFsr3FramegenEnabled(pendingAMDFramegen); saveSettings(); } - ImGui::TextDisabled("Runtime: %s", - renderer->isAmdFsr3FramegenRuntimeActive() ? "Active" : "Staged (dispatch not linked yet)"); + const char* runtimeStatus = "Unavailable"; + if (renderer->isAmdFsr3FramegenRuntimeActive()) { + runtimeStatus = "Active"; + } else if (renderer->isAmdFsr3FramegenRuntimeReady()) { + runtimeStatus = "Library loaded (dispatch staged)"; + } else { + runtimeStatus = "Library missing"; + } + ImGui::TextDisabled("Runtime: %s", runtimeStatus); } else { ImGui::BeginDisabled(); bool disabledFg = false;