diff --git a/modules/upscaling/include/vkcv/upscaling/FSR2Upscaling.hpp b/modules/upscaling/include/vkcv/upscaling/FSR2Upscaling.hpp
index 9b1b702147034a782d5c7f63674ff0304d090d04..f10b23ec029a88bd56e8e5fa78ebdbdd502e1e14 100644
--- a/modules/upscaling/include/vkcv/upscaling/FSR2Upscaling.hpp
+++ b/modules/upscaling/include/vkcv/upscaling/FSR2Upscaling.hpp
@@ -10,11 +10,69 @@
 
 namespace vkcv::upscaling {
 
-/**
+	/**
      * @addtogroup vkcv_upscaling
      * @{
      */
 
+	/**
+     * Enum to set the mode of quality for
+     * FSR2 upscaling.
+     */
+	enum class FSR2QualityMode : int {
+		/**
+		 * Don't upscale anything.
+		 */
+		NONE = 0,
+		
+		/**
+		 * High quality of FSR upscaling:
+		 * 1.5x per dimension
+		 */
+		QUALITY = 2,
+		
+		/**
+		 * Medium quality of FSR upscaling:
+		 * 1.7x per dimension
+		 */
+		BALANCED = 3,
+		
+		/**
+		 * Low quality of FSR upscaling:
+		 * 2.0x per dimension
+		 */
+		PERFORMANCE = 4,
+		
+		/**
+         * Lowest quality of FSR upscaling:
+         * 3.0x per dimension
+         */
+		ULTRA_PERFORMANCE = 5,
+	};
+	
+	/**
+     * Calculates the internal resolution for actual rendering if
+     * a specific mode of quality is used for upscaling with FSR2.
+     *
+     * @param[in] mode Mode of quality
+     * @param[in] outputWidth Final resolution width
+     * @param[in] outputHeight Final resolution height
+     * @param[out] inputWidth Internal resolution width
+     * @param[out] inputHeight Internal resolution height
+     */
+	void getFSR2Resolution(FSR2QualityMode mode,
+						   uint32_t outputWidth, uint32_t outputHeight,
+						   uint32_t &inputWidth, uint32_t &inputHeight);
+	
+	/**
+	 * Returns the matching negative lod bias to reduce artifacts
+	 * upscaling with FSR2 under a given mode of quality.
+	 *
+	 * @param mode Mode of quality
+	 * @return Lod bias
+	 */
+	float getFSR2LodBias(FSR2QualityMode mode);
+
 	/**
      * A class to handle upscaling via FidelityFX Super Resolution.
      * https://github.com/GPUOpen-Effects/FidelityFX-FSR2
@@ -29,6 +87,8 @@ namespace vkcv::upscaling {
 		ImageHandle m_depth;
 		ImageHandle m_velocity;
 		
+		uint32_t m_frameIndex;
+		
 		float m_frameDeltaTime;
 		bool m_reset;
 		
@@ -83,6 +143,20 @@ namespace vkcv::upscaling {
 		 */
 		void update(float deltaTime, bool reset = false);
 		
+		/**
+		 * Calculates the jitter offset for the projection
+		 * matrix of the camera to use in the current frame.
+		 *
+		 * @param[in] renderWidth Render resolution width
+		 * @param[in] renderHeight Render resolution height
+		 * @param[out] jitterOffsetX Jitter offset x-coordinate
+		 * @param[out] jitterOffsetY Jitter offset y-coordinate
+		 */
+		void calcJitterOffset(uint32_t renderWidth,
+							 uint32_t renderHeight,
+							 float& jitterOffsetX,
+							 float& jitterOffsetY);
+		
 		/**
 		 * Bind the depth buffer image to use with the FSR2
 		 * upscaling instance for utilizing depth information.
diff --git a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp
index ee2572da2d01a8234f03ced018704b48686e1a9b..5330c063f29a647e9d1a48d0d5b8e21dc2213bc2 100644
--- a/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp
+++ b/modules/upscaling/include/vkcv/upscaling/FSRUpscaling.hpp
@@ -45,12 +45,6 @@ namespace vkcv::upscaling {
          * 2.0x per dimension
          */
 		PERFORMANCE = 4,
-		
-		/**
-         * Lowest quality of FSR upscaling:
-         * 3.0x per dimension
-         */
-		ULTRA_PERFORMANCE = 5,
 	};
 
     /**
diff --git a/modules/upscaling/src/vkcv/upscaling/FSR2Upscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSR2Upscaling.cpp
index 4ef213e3d89ba57f7be6958a8d74a49a8c4cf4bd..d3b7b6c5b484c5943884576eb7c21f88640a9c1a 100644
--- a/modules/upscaling/src/vkcv/upscaling/FSR2Upscaling.cpp
+++ b/modules/upscaling/src/vkcv/upscaling/FSR2Upscaling.cpp
@@ -1,12 +1,61 @@
 
 #include "vkcv/upscaling/FSR2Upscaling.hpp"
 
+#include <cmath>
+
 #define FFX_GCC
 #include <ffx_fsr2_vk.h>
 #undef FFX_GCC
 
 namespace vkcv::upscaling {
 	
+	void getFSR2Resolution(FSR2QualityMode mode,
+						   uint32_t outputWidth, uint32_t outputHeight,
+						   uint32_t &inputWidth, uint32_t &inputHeight) {
+		float scale;
+		
+		switch (mode) {
+			case FSR2QualityMode::QUALITY:
+				scale = 1.5f;
+				break;
+			case FSR2QualityMode::BALANCED:
+				scale = 1.7f;
+				break;
+			case FSR2QualityMode::PERFORMANCE:
+				scale = 2.0f;
+				break;
+			case FSR2QualityMode::ULTRA_PERFORMANCE:
+				scale = 3.0f;
+				break;
+			default:
+				scale = 1.0f;
+				break;
+		}
+		
+		inputWidth = static_cast<uint32_t>(
+				std::round(static_cast<float>(outputWidth) / scale)
+		);
+		
+		inputHeight = static_cast<uint32_t>(
+				std::round(static_cast<float>(outputHeight) / scale)
+		);
+	}
+	
+	float getFSR2LodBias(FSR2QualityMode mode) {
+		switch (mode) {
+			case FSR2QualityMode::QUALITY:
+				return -1.58f;
+			case FSR2QualityMode::BALANCED:
+				return -1.76f;
+			case FSR2QualityMode::PERFORMANCE:
+				return -2.0f;
+			case FSR2QualityMode::ULTRA_PERFORMANCE:
+				return -2.58f;
+			default:
+				return 0.0f;
+		}
+	}
+	
 	void FSR2Upscaling::createFSR2Context(uint32_t displayWidth,
 									 uint32_t displayHeight,
 									 uint32_t renderWidth,
@@ -30,6 +79,8 @@ namespace vkcv::upscaling {
 		m_core.getContext().getDevice().waitIdle();
 		
 		assert(ffxFsr2ContextDestroy(&m_context) == FFX_OK);
+		
+		m_frameIndex = 0;
 	}
 	
 	FSR2Upscaling::FSR2Upscaling(Core &core) : Upscaling(core) {
@@ -60,10 +111,33 @@ namespace vkcv::upscaling {
 	}
 	
 	void FSR2Upscaling::update(float deltaTime, bool reset) {
+		if (reset) {
+			m_frameIndex = 0;
+		}
+		
 		m_frameDeltaTime = deltaTime;
 		m_reset = reset;
 	}
 	
+	void FSR2Upscaling::calcJitterOffset(uint32_t renderWidth,
+										 uint32_t renderHeight,
+										 float &jitterOffsetX,
+										 float &jitterOffsetY) {
+		const int32_t phaseCount = ffxFsr2GetJitterPhaseCount(
+				renderWidth,
+				renderHeight
+		);
+		
+		const int32_t phaseIndex = (static_cast<int32_t>(m_frameIndex) % phaseCount);
+		
+		assert(ffxFsr2GetJitterOffset(
+				&jitterOffsetX,
+				&jitterOffsetY,
+				phaseIndex,
+				phaseCount
+		) == FFX_OK);
+	}
+	
 	void FSR2Upscaling::bindDepthBuffer(const ImageHandle &depthInput) {
 		m_depth = depthInput;
 	}
@@ -166,11 +240,15 @@ namespace vkcv::upscaling {
 				static_cast<VkFormat>(m_core.getImageFormat(output))
 		);
 		
-		dispatch.jitterOffset.x = 0;
-		dispatch.jitterOffset.y = 0;
+		calcJitterOffset(
+				inputWidth,
+				inputHeight,
+				dispatch.jitterOffset.x,
+				dispatch.jitterOffset.y
+		);
 		
-		dispatch.motionVectorScale.x = 0;
-		dispatch.motionVectorScale.y = 0;
+		dispatch.motionVectorScale.x = static_cast<float>(inputWidth);
+		dispatch.motionVectorScale.y = static_cast<float>(inputHeight);
 		
 		dispatch.renderSize.width = inputWidth;
 		dispatch.renderSize.height = inputHeight;
@@ -194,6 +272,7 @@ namespace vkcv::upscaling {
 					&dispatch
 			) == FFX_OK);
 			
+			m_frameIndex++;
 			m_reset = false;
 		});
 	}
diff --git a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
index 2f37765e270c342a7aea3d52d37f1c9d4828cd89..d9ca8d9f0429960f1d43c074fb58ac6d79f6e677 100644
--- a/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
+++ b/modules/upscaling/src/vkcv/upscaling/FSRUpscaling.cpp
@@ -36,9 +36,6 @@ namespace vkcv::upscaling {
 			case FSRQualityMode::PERFORMANCE:
 				scale = 2.0f;
 				break;
-			case FSRQualityMode::ULTRA_PERFORMANCE:
-				scale = 3.0f;
-				break;
 			default:
 				scale = 1.0f;
 				break;
@@ -63,8 +60,6 @@ namespace vkcv::upscaling {
 				return -0.79f;
 			case FSRQualityMode::PERFORMANCE:
 				return -1.0f;
-			case FSRQualityMode::ULTRA_PERFORMANCE:
-				return -2.0f;
 			default:
 				return 0.0f;
 		}