diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp index ecec244e..585434bd 100644 --- a/src/rendering/renderer.cpp +++ b/src/rendering/renderer.cpp @@ -1205,7 +1205,9 @@ void Renderer::endFrame() { renderFSR2Sharpen(); // Maintain frame bookkeeping - fsr2_.prevViewProjection = camera->getViewProjectionMatrix(); + fsr2_.prevViewProjection = fsr2_.useAmdBackend + ? camera->getUnjitteredViewProjectionMatrix() + : camera->getViewProjectionMatrix(); fsr2_.prevJitter = camera->getJitter(); camera->clearJitter(); if (fsr2_.useAmdBackend) { @@ -3824,7 +3826,9 @@ bool Renderer::initFSR2Resources() { fsr2_.amdScratchBufferSize = 0; } else { FfxFsr2ContextDescription ctxDesc{}; - ctxDesc.flags = FFX_FSR2_ENABLE_AUTO_EXPOSURE | FFX_FSR2_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION; + // AMD path uses unjittered reprojection matrices for motion vectors. + // Keep jitter cancellation off to avoid double compensation jitter. + ctxDesc.flags = FFX_FSR2_ENABLE_AUTO_EXPOSURE; ctxDesc.maxRenderSize.width = fsr2_.internalWidth; ctxDesc.maxRenderSize.height = fsr2_.internalHeight; ctxDesc.displaySize.width = swapExtent.width; @@ -4183,14 +4187,17 @@ void Renderer::dispatchMotionVectors() { vkCmdBindDescriptorSets(currentCmd, VK_PIPELINE_BIND_POINT_COMPUTE, fsr2_.motionVecPipelineLayout, 0, 1, &fsr2_.motionVecDescSet, 0, nullptr); - // Reprojection with jittered matrices: - // reconstruct world position from current depth, then project into previous clip. + // Reprojection matrices: + // AMD path uses unjittered matrices (FSR handles jitter via desc.jitterOffset). + // Internal fallback keeps existing jittered behavior. struct { glm::mat4 prevViewProjection; glm::mat4 invCurrentViewProj; } pc; - glm::mat4 currentVP = camera->getViewProjectionMatrix(); + glm::mat4 currentVP = fsr2_.useAmdBackend + ? camera->getUnjitteredViewProjectionMatrix() + : camera->getViewProjectionMatrix(); pc.prevViewProjection = fsr2_.prevViewProjection; pc.invCurrentViewProj = glm::inverse(currentVP);