mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Integrate AMD FSR2 backend and document SDK bootstrap
This commit is contained in:
parent
a24ff375fb
commit
51a8cf565f
11 changed files with 329 additions and 28 deletions
|
|
@ -217,3 +217,8 @@ You can also specify an expansion: `.\extract_assets.ps1 "C:\Games\WoW\Data" wot
|
|||
```bash
|
||||
git submodule update --init --recursive
|
||||
```
|
||||
- AMD FSR2 SDK is fetched automatically by `build.sh` / `rebuild.sh` / `build.ps1` / `rebuild.ps1` from:
|
||||
- `https://github.com/GPUOpen-Effects/FidelityFX-FSR2.git`
|
||||
- target path: `extern/FidelityFX-FSR2`
|
||||
- AMD backend is enabled only when SDK headers and generated Vulkan permutation headers are present.
|
||||
If generated permutation headers are missing, the build uses the internal FSR2 fallback path.
|
||||
|
|
|
|||
|
|
@ -27,18 +27,49 @@ option(WOWEE_ENABLE_AMD_FSR2 "Enable AMD FidelityFX FSR2 backend when SDK is pre
|
|||
# AMD FidelityFX FSR2 SDK detection (drop-in under extern/FidelityFX-FSR2)
|
||||
set(WOWEE_AMD_FSR2_DIR ${CMAKE_SOURCE_DIR}/extern/FidelityFX-FSR2)
|
||||
set(WOWEE_AMD_FSR2_HEADER ${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api/ffx_fsr2.h)
|
||||
if(WOWEE_ENABLE_AMD_FSR2 AND EXISTS ${WOWEE_AMD_FSR2_HEADER})
|
||||
set(WOWEE_AMD_FSR2_VK_PERM_HEADER ${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api/vk/shaders/ffx_fsr2_accumulate_pass_permutations.h)
|
||||
if(WOWEE_ENABLE_AMD_FSR2 AND EXISTS ${WOWEE_AMD_FSR2_HEADER} AND EXISTS ${WOWEE_AMD_FSR2_VK_PERM_HEADER})
|
||||
message(STATUS "AMD FSR2 SDK detected at ${WOWEE_AMD_FSR2_DIR}")
|
||||
add_compile_definitions(WOWEE_HAS_AMD_FSR2=1)
|
||||
include_directories(
|
||||
add_compile_definitions(FFX_GCC=1)
|
||||
|
||||
# AMD FSR2 Vulkan backend sources (official SDK implementation)
|
||||
set(WOWEE_AMD_FSR2_SOURCES
|
||||
${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api/ffx_assert.cpp
|
||||
${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api/ffx_fsr2.cpp
|
||||
${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api/vk/ffx_fsr2_vk.cpp
|
||||
${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api/vk/shaders/ffx_fsr2_shaders_vk.cpp
|
||||
)
|
||||
add_library(wowee_fsr2_amd_vk STATIC ${WOWEE_AMD_FSR2_SOURCES})
|
||||
set_target_properties(wowee_fsr2_amd_vk PROPERTIES
|
||||
CXX_STANDARD 17
|
||||
CXX_STANDARD_REQUIRED ON
|
||||
)
|
||||
target_include_directories(wowee_fsr2_amd_vk PUBLIC
|
||||
${WOWEE_AMD_FSR2_DIR}/src
|
||||
${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api
|
||||
${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api/vk
|
||||
${WOWEE_AMD_FSR2_DIR}/src/ffx-fsr2-api/vk/shaders
|
||||
)
|
||||
set(WOWEE_FFX_COMPAT_HEADER ${CMAKE_SOURCE_DIR}/include/third_party/ffx_fsr2_compat.h)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
target_compile_options(wowee_fsr2_amd_vk PRIVATE
|
||||
"-include${WOWEE_FFX_COMPAT_HEADER}"
|
||||
)
|
||||
elseif(MSVC)
|
||||
target_compile_options(wowee_fsr2_amd_vk PRIVATE
|
||||
"/FI${WOWEE_FFX_COMPAT_HEADER}"
|
||||
)
|
||||
endif()
|
||||
target_link_libraries(wowee_fsr2_amd_vk PUBLIC Vulkan::Vulkan)
|
||||
else()
|
||||
add_compile_definitions(WOWEE_HAS_AMD_FSR2=0)
|
||||
if(WOWEE_ENABLE_AMD_FSR2)
|
||||
if(NOT EXISTS ${WOWEE_AMD_FSR2_HEADER})
|
||||
message(WARNING "AMD FSR2 SDK not found at ${WOWEE_AMD_FSR2_DIR}; using internal fallback implementation.")
|
||||
elseif(NOT EXISTS ${WOWEE_AMD_FSR2_VK_PERM_HEADER})
|
||||
message(WARNING "AMD FSR2 SDK found, but generated Vulkan permutation headers are missing (e.g. ${WOWEE_AMD_FSR2_VK_PERM_HEADER}); using internal fallback implementation.")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
|
@ -556,6 +587,10 @@ if(TARGET vk-bootstrap)
|
|||
target_link_libraries(wowee PRIVATE vk-bootstrap)
|
||||
endif()
|
||||
|
||||
if(TARGET wowee_fsr2_amd_vk)
|
||||
target_link_libraries(wowee PRIVATE wowee_fsr2_amd_vk)
|
||||
endif()
|
||||
|
||||
# Link Unicorn if available
|
||||
if(HAVE_UNICORN)
|
||||
target_link_libraries(wowee PRIVATE ${UNICORN_LIBRARY})
|
||||
|
|
|
|||
11
README.md
11
README.md
|
|
@ -168,6 +168,17 @@ make -j$(nproc)
|
|||
./bin/wowee
|
||||
```
|
||||
|
||||
### AMD FSR2 SDK (External)
|
||||
|
||||
- Build scripts (`build.sh`, `rebuild.sh`, `build.ps1`, `rebuild.ps1`) auto-fetch the AMD SDK to:
|
||||
- `extern/FidelityFX-FSR2`
|
||||
- Source URL:
|
||||
- `https://github.com/GPUOpen-Effects/FidelityFX-FSR2.git`
|
||||
- The renderer enables the AMD backend only when both are present:
|
||||
- `extern/FidelityFX-FSR2/src/ffx-fsr2-api/ffx_fsr2.h`
|
||||
- `extern/FidelityFX-FSR2/src/ffx-fsr2-api/vk/shaders/ffx_fsr2_accumulate_pass_permutations.h`
|
||||
- If SDK files or generated Vulkan permutation headers are missing, CMake falls back to the internal non-AMD FSR2 path automatically.
|
||||
|
||||
## Controls
|
||||
|
||||
### Camera & Movement
|
||||
|
|
|
|||
19
build.ps1
19
build.ps1
|
|
@ -12,7 +12,26 @@ $ErrorActionPreference = "Stop"
|
|||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
Set-Location $ScriptDir
|
||||
|
||||
function Ensure-Fsr2Sdk {
|
||||
$sdkDir = Join-Path $ScriptDir "extern\FidelityFX-FSR2"
|
||||
$sdkHeader = Join-Path $sdkDir "src\ffx-fsr2-api\ffx_fsr2.h"
|
||||
if (Test-Path $sdkHeader) { return }
|
||||
|
||||
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
||||
Write-Warning "git not found; cannot auto-fetch AMD FSR2 SDK."
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Fetching AMD FidelityFX FSR2 SDK into $sdkDir ..."
|
||||
New-Item -ItemType Directory -Path (Join-Path $ScriptDir "extern") -Force | Out-Null
|
||||
& git clone --depth 1 https://github.com/GPUOpen-Effects/FidelityFX-FSR2.git $sdkDir
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "Failed to clone AMD FSR2 SDK. Build will use internal fallback path."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Building wowee..."
|
||||
Ensure-Fsr2Sdk
|
||||
|
||||
# Create build directory if it doesn't exist
|
||||
if (-not (Test-Path "build")) {
|
||||
|
|
|
|||
18
build.sh
18
build.sh
|
|
@ -5,7 +5,25 @@ set -e # Exit on error
|
|||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
ensure_fsr2_sdk() {
|
||||
local sdk_dir="extern/FidelityFX-FSR2"
|
||||
local sdk_header="$sdk_dir/src/ffx-fsr2-api/ffx_fsr2.h"
|
||||
if [ -f "$sdk_header" ]; then
|
||||
return
|
||||
fi
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
echo "Warning: git not found; cannot auto-fetch AMD FSR2 SDK."
|
||||
return
|
||||
fi
|
||||
echo "Fetching AMD FidelityFX FSR2 SDK into $sdk_dir ..."
|
||||
mkdir -p extern
|
||||
git clone --depth 1 https://github.com/GPUOpen-Effects/FidelityFX-FSR2.git "$sdk_dir" || {
|
||||
echo "Warning: failed to clone AMD FSR2 SDK. Build will use internal fallback path."
|
||||
}
|
||||
}
|
||||
|
||||
echo "Building wowee..."
|
||||
ensure_fsr2_sdk
|
||||
|
||||
# Create build directory if it doesn't exist
|
||||
mkdir -p build
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@ public:
|
|||
glm::mat4 getViewProjectionMatrix() const { return projectionMatrix * viewMatrix; }
|
||||
glm::mat4 getUnjitteredViewProjectionMatrix() const { return unjitteredProjectionMatrix * viewMatrix; }
|
||||
float getAspectRatio() const { return aspectRatio; }
|
||||
float getFovDegrees() const { return fov; }
|
||||
float getNearPlane() const { return nearPlane; }
|
||||
float getFarPlane() const { return farPlane; }
|
||||
|
||||
// Sub-pixel jitter for temporal upscaling (FSR 2)
|
||||
void setJitter(float jx, float jy);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
#include "rendering/vk_frame_data.hpp"
|
||||
#include "rendering/vk_utils.hpp"
|
||||
#include "rendering/sky_system.hpp"
|
||||
#if WOWEE_HAS_AMD_FSR2
|
||||
#include "ffx_fsr2.h"
|
||||
#include "ffx_fsr2_vk.h"
|
||||
#endif
|
||||
|
||||
namespace wowee {
|
||||
namespace core { class Window; }
|
||||
|
|
@ -420,6 +424,13 @@ private:
|
|||
glm::vec2 prevJitter = glm::vec2(0.0f);
|
||||
uint32_t frameIndex = 0;
|
||||
bool needsHistoryReset = true;
|
||||
bool useAmdBackend = false;
|
||||
#if WOWEE_HAS_AMD_FSR2
|
||||
FfxFsr2Context amdContext{};
|
||||
FfxFsr2Interface amdInterface{};
|
||||
void* amdScratchBuffer = nullptr;
|
||||
size_t amdScratchBufferSize = 0;
|
||||
#endif
|
||||
|
||||
// Convergent accumulation: jitter for N frames then freeze
|
||||
int convergenceFrame = 0;
|
||||
|
|
@ -431,6 +442,7 @@ private:
|
|||
void destroyFSR2Resources();
|
||||
void dispatchMotionVectors();
|
||||
void dispatchTemporalAccumulate();
|
||||
void dispatchAmdFsr2();
|
||||
void renderFSR2Sharpen();
|
||||
static float halton(uint32_t index, uint32_t base);
|
||||
|
||||
|
|
|
|||
15
include/third_party/ffx_fsr2_compat.h
vendored
Normal file
15
include/third_party/ffx_fsr2_compat.h
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
// Compatibility shim for building AMD FSR2 SDK sources on non-MSVC toolchains.
|
||||
#include <stddef.h>
|
||||
#include <wchar.h>
|
||||
#include <locale>
|
||||
#include <codecvt>
|
||||
|
||||
#ifndef _countof
|
||||
#define _countof(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
#ifndef wcscpy_s
|
||||
#define wcscpy_s(dst, src) wcscpy((dst), (src))
|
||||
#endif
|
||||
19
rebuild.ps1
19
rebuild.ps1
|
|
@ -12,7 +12,26 @@ $ErrorActionPreference = "Stop"
|
|||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
Set-Location $ScriptDir
|
||||
|
||||
function Ensure-Fsr2Sdk {
|
||||
$sdkDir = Join-Path $ScriptDir "extern\FidelityFX-FSR2"
|
||||
$sdkHeader = Join-Path $sdkDir "src\ffx-fsr2-api\ffx_fsr2.h"
|
||||
if (Test-Path $sdkHeader) { return }
|
||||
|
||||
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
|
||||
Write-Warning "git not found; cannot auto-fetch AMD FSR2 SDK."
|
||||
return
|
||||
}
|
||||
|
||||
Write-Host "Fetching AMD FidelityFX FSR2 SDK into $sdkDir ..."
|
||||
New-Item -ItemType Directory -Path (Join-Path $ScriptDir "extern") -Force | Out-Null
|
||||
& git clone --depth 1 https://github.com/GPUOpen-Effects/FidelityFX-FSR2.git $sdkDir
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning "Failed to clone AMD FSR2 SDK. Build will use internal fallback path."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Clean rebuilding wowee..."
|
||||
Ensure-Fsr2Sdk
|
||||
|
||||
# Remove build directory completely
|
||||
if (Test-Path "build") {
|
||||
|
|
|
|||
18
rebuild.sh
18
rebuild.sh
|
|
@ -5,7 +5,25 @@ set -e # Exit on error
|
|||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
ensure_fsr2_sdk() {
|
||||
local sdk_dir="extern/FidelityFX-FSR2"
|
||||
local sdk_header="$sdk_dir/src/ffx-fsr2-api/ffx_fsr2.h"
|
||||
if [ -f "$sdk_header" ]; then
|
||||
return
|
||||
fi
|
||||
if ! command -v git >/dev/null 2>&1; then
|
||||
echo "Warning: git not found; cannot auto-fetch AMD FSR2 SDK."
|
||||
return
|
||||
fi
|
||||
echo "Fetching AMD FidelityFX FSR2 SDK into $sdk_dir ..."
|
||||
mkdir -p extern
|
||||
git clone --depth 1 https://github.com/GPUOpen-Effects/FidelityFX-FSR2.git "$sdk_dir" || {
|
||||
echo "Warning: failed to clone AMD FSR2 SDK. Build will use internal fallback path."
|
||||
}
|
||||
}
|
||||
|
||||
echo "Clean rebuilding wowee..."
|
||||
ensure_fsr2_sdk
|
||||
|
||||
# Remove build directory completely
|
||||
if [ -d "build" ]; then
|
||||
|
|
|
|||
|
|
@ -1022,10 +1022,9 @@ void Renderer::beginFrame() {
|
|||
return;
|
||||
}
|
||||
|
||||
// FSR2 jitter pattern for temporal accumulation.
|
||||
constexpr bool kFsr2TemporalEnabled = false;
|
||||
// FSR2 jitter pattern.
|
||||
if (fsr2_.enabled && fsr2_.sceneFramebuffer && camera) {
|
||||
if (!kFsr2TemporalEnabled) {
|
||||
if (!fsr2_.useAmdBackend) {
|
||||
camera->setJitter(0.0f, 0.0f);
|
||||
} else {
|
||||
glm::mat4 currentVP = camera->getViewProjectionMatrix();
|
||||
|
|
@ -1044,10 +1043,27 @@ void Renderer::beginFrame() {
|
|||
fsr2_.needsHistoryReset = true;
|
||||
}
|
||||
|
||||
#if WOWEE_HAS_AMD_FSR2
|
||||
// AMD-recommended jitter sequence in pixel space, converted to NDC projection offset.
|
||||
int32_t phaseCount = ffxFsr2GetJitterPhaseCount(
|
||||
static_cast<int32_t>(fsr2_.internalWidth),
|
||||
static_cast<int32_t>(vkCtx->getSwapchainExtent().width));
|
||||
float jitterX = 0.0f;
|
||||
float jitterY = 0.0f;
|
||||
if (phaseCount > 0 &&
|
||||
ffxFsr2GetJitterOffset(&jitterX, &jitterY, static_cast<int32_t>(fsr2_.frameIndex % static_cast<uint32_t>(phaseCount)), phaseCount) == FFX_OK) {
|
||||
float ndcJx = (2.0f * jitterX) / static_cast<float>(fsr2_.internalWidth);
|
||||
float ndcJy = (2.0f * jitterY) / static_cast<float>(fsr2_.internalHeight);
|
||||
camera->setJitter(ndcJx, ndcJy);
|
||||
} else {
|
||||
camera->setJitter(0.0f, 0.0f);
|
||||
}
|
||||
#else
|
||||
const float jitterScale = 0.5f;
|
||||
float jx = (halton(fsr2_.frameIndex + 1, 2) - 0.5f) * 2.0f * jitterScale / static_cast<float>(fsr2_.internalWidth);
|
||||
float jy = (halton(fsr2_.frameIndex + 1, 3) - 0.5f) * 2.0f * jitterScale / static_cast<float>(fsr2_.internalHeight);
|
||||
camera->setJitter(jx, jy);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1152,14 +1168,13 @@ void Renderer::endFrame() {
|
|||
if (!vkCtx || currentCmd == VK_NULL_HANDLE) return;
|
||||
|
||||
if (fsr2_.enabled && fsr2_.sceneFramebuffer) {
|
||||
constexpr bool kFsr2TemporalEnabled = false;
|
||||
// End the off-screen scene render pass
|
||||
vkCmdEndRenderPass(currentCmd);
|
||||
|
||||
if (kFsr2TemporalEnabled) {
|
||||
if (fsr2_.useAmdBackend) {
|
||||
// Compute passes: motion vectors -> temporal accumulation
|
||||
dispatchMotionVectors();
|
||||
dispatchTemporalAccumulate();
|
||||
dispatchAmdFsr2();
|
||||
|
||||
// Transition history output: GENERAL -> SHADER_READ_ONLY for sharpen pass
|
||||
transitionImageLayout(currentCmd, fsr2_.history[fsr2_.currentHistory].image,
|
||||
|
|
@ -1209,7 +1224,7 @@ void Renderer::endFrame() {
|
|||
fsr2_.prevViewProjection = camera->getViewProjectionMatrix();
|
||||
fsr2_.prevJitter = camera->getJitter();
|
||||
camera->clearJitter();
|
||||
if (kFsr2TemporalEnabled) {
|
||||
if (fsr2_.useAmdBackend) {
|
||||
fsr2_.currentHistory = 1 - fsr2_.currentHistory;
|
||||
}
|
||||
fsr2_.frameIndex = (fsr2_.frameIndex + 1) % 256; // Wrap to keep Halton values well-distributed
|
||||
|
|
@ -3739,6 +3754,7 @@ bool Renderer::initFSR2Resources() {
|
|||
LOG_INFO("FSR2: initializing at ", fsr2_.internalWidth, "x", fsr2_.internalHeight,
|
||||
" -> ", swapExtent.width, "x", swapExtent.height,
|
||||
" (scale=", fsr2_.scaleFactor, ")");
|
||||
fsr2_.useAmdBackend = false;
|
||||
#if WOWEE_HAS_AMD_FSR2
|
||||
LOG_INFO("FSR2: AMD FidelityFX SDK detected at build time.");
|
||||
#else
|
||||
|
|
@ -3802,6 +3818,51 @@ bool Renderer::initFSR2Resources() {
|
|||
samplerInfo.magFilter = VK_FILTER_NEAREST;
|
||||
vkCreateSampler(device, &samplerInfo, nullptr, &fsr2_.nearestSampler);
|
||||
|
||||
#if WOWEE_HAS_AMD_FSR2
|
||||
// Initialize AMD FSR2 context; fall back to internal path on any failure.
|
||||
fsr2_.amdScratchBufferSize = ffxFsr2GetScratchMemorySizeVK(vkCtx->getPhysicalDevice());
|
||||
if (fsr2_.amdScratchBufferSize > 0) {
|
||||
fsr2_.amdScratchBuffer = std::malloc(fsr2_.amdScratchBufferSize);
|
||||
}
|
||||
if (!fsr2_.amdScratchBuffer) {
|
||||
LOG_WARNING("FSR2 AMD: failed to allocate scratch buffer, using internal fallback.");
|
||||
} else {
|
||||
FfxErrorCode ifaceErr = ffxFsr2GetInterfaceVK(
|
||||
&fsr2_.amdInterface,
|
||||
fsr2_.amdScratchBuffer,
|
||||
fsr2_.amdScratchBufferSize,
|
||||
vkCtx->getPhysicalDevice(),
|
||||
vkGetDeviceProcAddr);
|
||||
if (ifaceErr != FFX_OK) {
|
||||
LOG_WARNING("FSR2 AMD: ffxFsr2GetInterfaceVK failed (", static_cast<int>(ifaceErr), "), using internal fallback.");
|
||||
std::free(fsr2_.amdScratchBuffer);
|
||||
fsr2_.amdScratchBuffer = nullptr;
|
||||
fsr2_.amdScratchBufferSize = 0;
|
||||
} else {
|
||||
FfxFsr2ContextDescription ctxDesc{};
|
||||
ctxDesc.flags = FFX_FSR2_ENABLE_AUTO_EXPOSURE | FFX_FSR2_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION;
|
||||
ctxDesc.maxRenderSize.width = fsr2_.internalWidth;
|
||||
ctxDesc.maxRenderSize.height = fsr2_.internalHeight;
|
||||
ctxDesc.displaySize.width = swapExtent.width;
|
||||
ctxDesc.displaySize.height = swapExtent.height;
|
||||
ctxDesc.callbacks = fsr2_.amdInterface;
|
||||
ctxDesc.device = ffxGetDeviceVK(vkCtx->getDevice());
|
||||
ctxDesc.fpMessage = nullptr;
|
||||
|
||||
FfxErrorCode ctxErr = ffxFsr2ContextCreate(&fsr2_.amdContext, &ctxDesc);
|
||||
if (ctxErr == FFX_OK) {
|
||||
fsr2_.useAmdBackend = true;
|
||||
LOG_INFO("FSR2 AMD: context created successfully.");
|
||||
} else {
|
||||
LOG_WARNING("FSR2 AMD: context creation failed (", static_cast<int>(ctxErr), "), using internal fallback.");
|
||||
std::free(fsr2_.amdScratchBuffer);
|
||||
fsr2_.amdScratchBuffer = nullptr;
|
||||
fsr2_.amdScratchBufferSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// --- Motion Vector Compute Pipeline ---
|
||||
{
|
||||
// Descriptor set layout: binding 0 = depth (sampler), binding 1 = motion vectors (storage image)
|
||||
|
|
@ -4078,6 +4139,18 @@ void Renderer::destroyFSR2Resources() {
|
|||
|
||||
vkDeviceWaitIdle(device);
|
||||
|
||||
#if WOWEE_HAS_AMD_FSR2
|
||||
if (fsr2_.useAmdBackend) {
|
||||
ffxFsr2ContextDestroy(&fsr2_.amdContext);
|
||||
fsr2_.useAmdBackend = false;
|
||||
}
|
||||
if (fsr2_.amdScratchBuffer) {
|
||||
std::free(fsr2_.amdScratchBuffer);
|
||||
fsr2_.amdScratchBuffer = nullptr;
|
||||
}
|
||||
fsr2_.amdScratchBufferSize = 0;
|
||||
#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; }
|
||||
if (fsr2_.sharpenDescPool) { vkDestroyDescriptorPool(device, fsr2_.sharpenDescPool, nullptr); fsr2_.sharpenDescPool = VK_NULL_HANDLE; fsr2_.sharpenDescSets[0] = fsr2_.sharpenDescSets[1] = VK_NULL_HANDLE; }
|
||||
|
|
@ -4220,9 +4293,82 @@ void Renderer::dispatchTemporalAccumulate() {
|
|||
fsr2_.needsHistoryReset = false;
|
||||
}
|
||||
|
||||
void Renderer::dispatchAmdFsr2() {
|
||||
if (currentCmd == VK_NULL_HANDLE || !camera) return;
|
||||
#if WOWEE_HAS_AMD_FSR2
|
||||
if (!fsr2_.useAmdBackend) return;
|
||||
|
||||
VkExtent2D swapExtent = vkCtx->getSwapchainExtent();
|
||||
uint32_t outputIdx = fsr2_.currentHistory;
|
||||
|
||||
transitionImageLayout(currentCmd, fsr2_.sceneColor.image,
|
||||
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
transitionImageLayout(currentCmd, fsr2_.motionVectors.image,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
transitionImageLayout(currentCmd, fsr2_.sceneDepth.image,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
transitionImageLayout(currentCmd, fsr2_.history[outputIdx].image,
|
||||
fsr2_.needsHistoryReset ? VK_IMAGE_LAYOUT_UNDEFINED : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT);
|
||||
|
||||
FfxFsr2DispatchDescription desc{};
|
||||
desc.commandList = ffxGetCommandListVK(currentCmd);
|
||||
desc.color = ffxGetTextureResourceVK(&fsr2_.amdContext,
|
||||
fsr2_.sceneColor.image, fsr2_.sceneColor.imageView,
|
||||
fsr2_.internalWidth, fsr2_.internalHeight, vkCtx->getSwapchainFormat(),
|
||||
L"FSR2_InputColor", FFX_RESOURCE_STATE_COMPUTE_READ);
|
||||
desc.depth = ffxGetTextureResourceVK(&fsr2_.amdContext,
|
||||
fsr2_.sceneDepth.image, fsr2_.sceneDepth.imageView,
|
||||
fsr2_.internalWidth, fsr2_.internalHeight, vkCtx->getDepthFormat(),
|
||||
L"FSR2_InputDepth", FFX_RESOURCE_STATE_COMPUTE_READ);
|
||||
desc.motionVectors = ffxGetTextureResourceVK(&fsr2_.amdContext,
|
||||
fsr2_.motionVectors.image, fsr2_.motionVectors.imageView,
|
||||
fsr2_.internalWidth, fsr2_.internalHeight, VK_FORMAT_R16G16_SFLOAT,
|
||||
L"FSR2_InputMotionVectors", FFX_RESOURCE_STATE_COMPUTE_READ);
|
||||
desc.output = ffxGetTextureResourceVK(&fsr2_.amdContext,
|
||||
fsr2_.history[outputIdx].image, fsr2_.history[outputIdx].imageView,
|
||||
swapExtent.width, swapExtent.height, VK_FORMAT_R16G16B16A16_SFLOAT,
|
||||
L"FSR2_Output", FFX_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
// Camera jitter is stored as NDC projection offsets; convert to render-pixel offsets.
|
||||
glm::vec2 jitterNdc = camera->getJitter();
|
||||
desc.jitterOffset.x = jitterNdc.x * 0.5f * static_cast<float>(fsr2_.internalWidth);
|
||||
desc.jitterOffset.y = jitterNdc.y * 0.5f * static_cast<float>(fsr2_.internalHeight);
|
||||
desc.motionVectorScale.x = static_cast<float>(fsr2_.internalWidth);
|
||||
desc.motionVectorScale.y = static_cast<float>(fsr2_.internalHeight);
|
||||
desc.renderSize.width = fsr2_.internalWidth;
|
||||
desc.renderSize.height = fsr2_.internalHeight;
|
||||
desc.enableSharpening = false; // Keep existing RCAS post pass.
|
||||
desc.sharpness = 0.0f;
|
||||
desc.frameTimeDelta = glm::max(0.001f, lastDeltaTime_ * 1000.0f);
|
||||
desc.preExposure = 1.0f;
|
||||
desc.reset = fsr2_.needsHistoryReset;
|
||||
desc.cameraNear = camera->getNearPlane();
|
||||
desc.cameraFar = camera->getFarPlane();
|
||||
desc.cameraFovAngleVertical = glm::radians(camera->getFovDegrees());
|
||||
desc.viewSpaceToMetersFactor = 1.0f;
|
||||
desc.enableAutoReactive = false;
|
||||
|
||||
FfxErrorCode dispatchErr = ffxFsr2ContextDispatch(&fsr2_.amdContext, &desc);
|
||||
if (dispatchErr != FFX_OK) {
|
||||
LOG_WARNING("FSR2 AMD: dispatch failed (", static_cast<int>(dispatchErr), "), forcing history reset.");
|
||||
fsr2_.needsHistoryReset = true;
|
||||
} else {
|
||||
fsr2_.needsHistoryReset = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Renderer::renderFSR2Sharpen() {
|
||||
if (!fsr2_.sharpenPipeline || currentCmd == VK_NULL_HANDLE) return;
|
||||
constexpr bool kFsr2TemporalEnabled = false;
|
||||
|
||||
VkExtent2D ext = vkCtx->getSwapchainExtent();
|
||||
uint32_t outputIdx = fsr2_.currentHistory;
|
||||
|
|
@ -4234,7 +4380,7 @@ void Renderer::renderFSR2Sharpen() {
|
|||
// Update sharpen descriptor to point at current history output
|
||||
VkDescriptorImageInfo imgInfo{};
|
||||
imgInfo.sampler = fsr2_.linearSampler;
|
||||
imgInfo.imageView = kFsr2TemporalEnabled
|
||||
imgInfo.imageView = fsr2_.useAmdBackend
|
||||
? fsr2_.history[outputIdx].imageView
|
||||
: fsr2_.sceneColor.imageView;
|
||||
imgInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue