diff --git a/docs/samples/media/variable-shading/variable-shading.jpg b/docs/samples/media/variable-shading/variable-shading.jpg
index 33e8495d..5f1c4e7a 100644
Binary files a/docs/samples/media/variable-shading/variable-shading.jpg and b/docs/samples/media/variable-shading/variable-shading.jpg differ
diff --git a/docs/samples/media/variable-shading/variable-shading.png b/docs/samples/media/variable-shading/variable-shading.png
index 25e7f3df..7f70593b 100644
Binary files a/docs/samples/media/variable-shading/variable-shading.png and b/docs/samples/media/variable-shading/variable-shading.png differ
diff --git a/docs/samples/variable-shading.md b/docs/samples/variable-shading.md
index 712ef893..d74b47ea 100644
--- a/docs/samples/variable-shading.md
+++ b/docs/samples/variable-shading.md
@@ -24,13 +24,14 @@ The sample contains various UI elements to help you explore the techniques it de
| **PerDraw VRS** | `1x1, 1x2, 2x1, 2x2` | Shading rate value. Additional shading rates are 2x4, 4x2, 4x4. |
| **ShadingRateImage Enabled** | `Checked/Unchecked` | Enable/Disable Tier 2 VRS control image. |
| **ShadingRateImage Combiner** | `Checked/Unchecked` | The options for each combiner are: passthrough the previous state (i.e. disable the current stage), override (ignore previous stages), min, max and sum. |
+| **VRS Algorithm** | `Luminance and Motion Vectors, Foveated Rendering, Combined (Max)` | The technique used to generate the shading rate image. |
| **VRS variance Threshold** | `0.0 - 1.0` | Defines a value against which luminance variance gets compared in the compute shader generating the VRS image. |
| **VRS Motion Factor** | `0.0 - 1.0` | Sets a factor by which the motion of the pixel since the last frame gets scaled to modify the shading rate. |
| **ShadingRateImage Overlay** | `Checked/Unchecked` | Enable/Disable ShadingRateImage overlay, a debug image over the rendered scene. |
Setting up Variable Shading
-The Variable Shading compute shader takes as input the linear color buffer produced by the geometry rendering passes, and motion vectors buffer produced before geometry rendering passes. Final VRS control image is written to output buffer passed from setup.
+The Variable Shading compute shader takes as input the linear color buffer produced by the geometry rendering passes, and motion vectors buffer produced before geometry rendering passes. It also takes as input the center and radii for the foveated rendering regions. Final VRS control image is written to output buffer passed from setup.
Include the interface for the backend of the VRS API.
diff --git a/docs/techniques/variable-shading.md b/docs/techniques/variable-shading.md
index 4a094bf5..65ea2303 100644
--- a/docs/techniques/variable-shading.md
+++ b/docs/techniques/variable-shading.md
@@ -12,6 +12,8 @@ FidelityFX Variable Shading (VRS) provides a similar way to reduce the number of
One way to think about how VRS works is to think of MSAA: if a 4K frame is rendered with 2x2 VRS for everything, the required computational power and the final quality of the image would be comparable to rendering a 1080p image with 4x MSAA enabled. However, VRS provides additional features to enable more fine-grained control over which parts of the frame should get rendered with lower resolution.
+FidelityFX Variable Shading (VRS) also gives the option to implement Foveated Rendering by significanly reducing the number of pixel shading executions at the outer periphery of where the user is looking, taking advantage of the user not noticing the loss of visual quality in such regions. This can thus be paired with an eye tracker, whether built in a VR headset, a dedicated hardware or a webcam based software.
+
Implementing Variable Shading
Cases allowing VRS
@@ -24,8 +26,9 @@ image:
- Some objects may get distorted or blurred by being behind haze or semi-transparent objects like water or frosted glass.
- Some objects might be known to have little detail variance (such as rendering for toon shaded games) or due to being in very dark parts of the scene (e.g. the unlit or shadowed parts of objects in scenes with little ambient light).
- In fast moving scenes, high framerate and low input lag are important, but small details are less likely to get noticed by the player, so aggressively using VRS can help to achieve the performance goals.
+- When using an eye tracking device, one can establish where the user is looking, and can decrease the visual quality away from that area without being noticeable.
-In addition to the cases mentioned above, some pixels might be known to be of little interest to the player, either through eye-tracking (foveated rendering) or other systems, or because the game design aims to steer the focus of the player to certain parts of the screen. As an example, the game might choose to reduce the shading rate on the background geometry but make sure all enemies are rendered at highest quality.
+In addition to the cases mentioned above, some pixels might be known to be of little interest to the player, either through eye-tracking or other systems, or because the game design aims to steer the focus of the player to certain parts of the screen. As an example, the game might choose to reduce the shading rate on the background geometry but make sure all enemies are rendered at highest quality.
Due to saving computational power by focusing usage of GPU resources where it matters most, VRS can be used to make sure target frame times are achieved (similar to dynamic resolution scaling but with more fine-grained control over where detail needs to be preserved), as well as for power saving on portable devices without noticeably sacrificing image quality.
diff --git a/samples/vrs/vrsrendermodule.cpp b/samples/vrs/vrsrendermodule.cpp
index adcfc59f..9b220c72 100644
--- a/samples/vrs/vrsrendermodule.cpp
+++ b/samples/vrs/vrsrendermodule.cpp
@@ -299,6 +299,21 @@ void VRSRenderModule::BuildUI()
}
);
+ const char* algorithmOptions[] = {"Luminance and Motion Vectors", "Foveated Rendering", "Combined (Max)"};
+ comboOptions.clear();
+ for (int32_t i = 0; i < _countof(algorithmOptions); ++i)
+ {
+ comboOptions.push_back(algorithmOptions[i]);
+ }
+
+ uiSection->RegisterUIElement(
+ "VRS Algorithm",
+ (int32_t&)m_ShadingRateImageAlgorithmIndex,
+ std::move(comboOptions),
+ m_ShadingRateImageEnabled,
+ [this](int32_t cur, int32_t old) {}
+ );
+
uiSection->RegisterUIElement>("VRS variance Threshold", m_VRSThreshold, 0.f, 0.1f, m_ShadingRateImageEnabled);
uiSection->RegisterUIElement>("VRS Motion Factor", m_VRSMotionFactor, 0.f, 0.1f, m_ShadingRateImageEnabled);
@@ -691,8 +706,17 @@ void VRSRenderModule::ExecuteVRSImageGen(double deltaTime, cauldron::CommandList
uint32_t width = GetFramework()->GetResolutionInfo().RenderWidth;
uint32_t height = GetFramework()->GetResolutionInfo().RenderHeight;
+ uint32_t vrsAlgorithm;
+ if (m_ShadingRateImageAlgorithmIndex == 0)
+ vrsAlgorithm = FFX_VARIABLESHADING_IMAGE_ALGORITHM_LUMINANCE_AND_MOTION_VECTORS;
+ else if (m_ShadingRateImageAlgorithmIndex == 1)
+ vrsAlgorithm = FFX_VARIABLESHADING_IMAGE_ALGORITHM_FOVEATED;
+ else
+ vrsAlgorithm = FFX_VARIABLESHADING_IMAGE_ALGORITHM_LUMINANCE_AND_MOTION_VECTORS | FFX_VARIABLESHADING_IMAGE_ALGORITHM_FOVEATED;
+
FfxVrsDispatchDescription dispatchParameters = {};
dispatchParameters.commandList = SDKWrapper::ffxGetCommandList(pCmdList);
+ dispatchParameters.vrsAlgorithm = vrsAlgorithm;
dispatchParameters.output = SDKWrapper::ffxGetResource(m_pVRSTexture->GetResource(), L"VRSImage", FFX_RESOURCE_STATE_UNORDERED_ACCESS);
dispatchParameters.historyColor = SDKWrapper::ffxGetResource(m_pHistoryColorBuffer->GetResource(), L"HistoryColorBuffer", FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ);
dispatchParameters.motionVectors = SDKWrapper::ffxGetResource(m_pMotionVectors->GetResource(), L"VRSMotionVectorsTarget", FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ);
@@ -702,6 +726,12 @@ void VRSRenderModule::ExecuteVRSImageGen(double deltaTime, cauldron::CommandList
dispatchParameters.renderSize = {width, height};
dispatchParameters.motionVectorScale.x = -1.f;
dispatchParameters.motionVectorScale.y = -1.f;
+ dispatchParameters.foveationCenter.x = m_VRSFoveationCenter.x * width;
+ dispatchParameters.foveationCenter.y = m_VRSFoveationCenter.y * height;
+ dispatchParameters.foveationRadiiSquared.radius1x1 = (m_VRSFovRadii.radius1x1 * width) * (m_VRSFovRadii.radius1x1 * width);
+ dispatchParameters.foveationRadiiSquared.radius1x2 = (m_VRSFovRadii.radius1x2 * width) * (m_VRSFovRadii.radius1x2 * width);
+ dispatchParameters.foveationRadiiSquared.radius2x2 = (m_VRSFovRadii.radius2x2 * width) * (m_VRSFovRadii.radius2x2 * width);
+ dispatchParameters.foveationRadiiSquared.radius2x4 = (m_VRSFovRadii.radius2x4 * width) * (m_VRSFovRadii.radius2x4 * width);
// Disabled until remaining things are fixes
FfxErrorCode errorCode = ffxVrsContextDispatch(&m_VRSContext, &dispatchParameters);
diff --git a/samples/vrs/vrsrendermodule.h b/samples/vrs/vrsrendermodule.h
index 7ce3a36c..2c2250c0 100644
--- a/samples/vrs/vrsrendermodule.h
+++ b/samples/vrs/vrsrendermodule.h
@@ -140,10 +140,13 @@ class VRSRenderModule : public cauldron::RenderModule, public cauldron::ContentL
uint32_t m_ShadingRateIndex = 0;
uint32_t m_ShadingRateCombinerIndex = 0;
bool m_EnableShadingRateImage = false;
+ uint32_t m_ShadingRateImageAlgorithmIndex = 0;
bool m_AllowAdditionalShadingRates = false;
uint32_t m_VRSTierSupported = 0;
float m_VRSThreshold = 0.015f;
float m_VRSMotionFactor = 0.01f;
+ FfxFloatCoords2D m_VRSFoveationCenter{0.5f, 0.5f};
+ FfxVrsFovRadii m_VRSFovRadii{0.2f, 0.3f, 0.4f, 0.5f};
bool m_VariableShadingEnabled = false;
bool m_ShadingRateImageEnabled = false;
diff --git a/sdk/include/FidelityFX/gpu/vrs/ffx_variable_shading.h b/sdk/include/FidelityFX/gpu/vrs/ffx_variable_shading.h
index d041c597..2d4d2c6a 100644
--- a/sdk/include/FidelityFX/gpu/vrs/ffx_variable_shading.h
+++ b/sdk/include/FidelityFX/gpu/vrs/ffx_variable_shading.h
@@ -29,6 +29,9 @@
#define FFX_CPU
#include
+FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_IMAGE_ALGORITHM_LUMINANCE_AND_MOTION_VECTORS = 0x1;
+FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_IMAGE_ALGORITHM_FOVEATED = 0x2;
+
FFX_STATIC void ffxVariableShadingGetDispatchInfo(
const FfxDimensions2D resolution, const FfxUInt32 tileSize, const bool useAditionalShadingRates, FfxUInt32& numThreadGroupsX, FfxUInt32& numThreadGroupsY)
{
@@ -61,6 +64,9 @@ FFX_STATIC void ffxVariableShadingGetDispatchInfo(
}
#elif defined(FFX_GPU)
+FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_IMAGE_ALGORITHM_LUMINANCE_AND_MOTION_VECTORS = 0x1;
+FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_IMAGE_ALGORITHM_FOVEATED = 0x2;
+
// Forward declaration of functions that need to be implemented by shader code using this technique
FfxFloat32 ReadLuminance(FfxInt32x2 pos);
FfxFloat32x2 ReadMotionVec2D(FfxInt32x2 pos);
@@ -70,6 +76,8 @@ FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_RATE1D_1X = 0x0;
FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_RATE1D_2X = 0x1;
FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_RATE1D_4X = 0x2;
#define FFX_VARIABLESHADING_MAKE_SHADING_RATE(x,y) ((x << 2) | (y))
+#define FFX_VARIABLESHADING_SHADING_RATE_2D_MAX(xy, wz) \
+ FFX_VARIABLESHADING_MAKE_SHADING_RATE(max(xy >> 2, wz >> 2), max(xy & 0x3,wz & 0x3))
FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_RATE_1X1 = FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_1X, FFX_VARIABLESHADING_RATE1D_1X); // 0;
FFX_STATIC const FfxUInt32 FFX_VARIABLESHADING_RATE_1X2 = FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_1X, FFX_VARIABLESHADING_RATE1D_2X); // 0x1;
@@ -91,6 +99,7 @@ FFX_STATIC const FfxUInt32 FFX_VariableShading_ThreadCount1D = 16;
FFX_STATIC const FfxUInt32 FFX_VariableShading_NumBlocks1D = 1;
#endif
FFX_STATIC const FfxUInt32 FFX_VariableShading_SampleCount1D = FFX_VariableShading_ThreadCount1D + 2;
+FFX_STATIC const FfxUInt32 FFX_VariableShading_TileCenterOffset1D = FFX_VARIABLESHADING_TILESIZE >> 1 - 1;
FFX_GROUPSHARED FfxUInt32 FFX_VariableShading_LdsGroupReduce;
@@ -107,6 +116,7 @@ FFX_STATIC const FfxUInt32 FFX_VariableShading_ThreadCount1D = 8;
FFX_STATIC const FfxUInt32 FFX_VariableShading_NumBlocks1D = 32 / FFX_VARIABLESHADING_TILESIZE;
FFX_STATIC const FfxUInt32 FFX_VariableShading_TilesPerGroup = FFX_VariableShading_NumBlocks1D * FFX_VariableShading_NumBlocks1D;
FFX_STATIC const FfxUInt32 FFX_VariableShading_SampleCount1D = FFX_VariableShading_ThreadCount1D + 2;
+FFX_STATIC const FfxUInt32 FFX_VariableShading_TileCenterOffset1D = FFX_VARIABLESHADING_TILESIZE >> 1 - 1;
FFX_GROUPSHARED FfxUInt32 FFX_VariableShading_LdsGroupReduce[FFX_VariableShading_TilesPerGroup];
@@ -118,6 +128,46 @@ FFX_STATIC const FfxUInt32 FFX_VariableShading_NumBlocks = FFX_VariableShading_N
FFX_GROUPSHARED FfxUInt32 FFX_VariableShading_LdsShadingRate[FFX_VariableShading_SampleCount];
#endif
+FfxUInt32 VrsComputeFoveatedShadingRate(FfxUInt32x3 Gid, FfxUInt32x3 Gtid, FfxUInt32 Gidx)
+{
+ FfxFloat32x2 tileVRSImageCoords = FfxFloat32x2(Gid.xy * FFX_VariableShading_NumBlocks1D + FfxUInt32x2(Gidx / FFX_VariableShading_NumBlocks1D, Gidx % FFX_VariableShading_NumBlocks1D));
+ FfxFloat32x2 tileRenderingTargetCoords = FfxFloat32x2(tileVRSImageCoords.x * FFX_VARIABLESHADING_TILESIZE, tileVRSImageCoords.y * FFX_VARIABLESHADING_TILESIZE) + FfxFloat32x2(FFX_VariableShading_TileCenterOffset1D, FFX_VariableShading_TileCenterOffset1D);
+ FfxFloat32x2 dxy = tileRenderingTargetCoords - FoveationCenter();
+ FfxFloat32 distSquared = dot(dxy, dxy);
+
+ FfxUInt32 shadingRate;
+ if (distSquared < FoveationRadiiSquared().x) // 1X1
+ {
+ shadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_1X, FFX_VARIABLESHADING_RATE1D_1X);
+ }
+ else if (distSquared < FoveationRadiiSquared().y) // 1X2 or 2X1
+ {
+ bool horizontal = abs(dxy.x) > abs(dxy.y);
+ shadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE(horizontal ? FFX_VARIABLESHADING_RATE1D_1X : FFX_VARIABLESHADING_RATE1D_2X, horizontal ? FFX_VARIABLESHADING_RATE1D_2X : FFX_VARIABLESHADING_RATE1D_1X);
+ }
+#if !defined FFX_VARIABLESHADING_ADDITIONALSHADINGRATES
+ else // 2X2
+ {
+ shadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_2X, FFX_VARIABLESHADING_RATE1D_2X);
+ }
+#else // if defined FFX_VARIABLESHADING_ADDITIONALSHADINGRATES
+ else if (distSquared < FoveationRadiiSquared().z) // 2X2
+ {
+ shadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_2X, FFX_VARIABLESHADING_RATE1D_2X);
+ }
+ else if (distSquared < FoveationRadiiSquared().w) // 2X4 or 4X2
+ {
+ bool horizontal = abs(dxy.x) > abs(dxy.y);
+ shadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE(horizontal ? FFX_VARIABLESHADING_RATE1D_2X : FFX_VARIABLESHADING_RATE1D_4X, horizontal ? FFX_VARIABLESHADING_RATE1D_4X : FFX_VARIABLESHADING_RATE1D_2X);
+ }
+ else // 4X4
+ {
+ shadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_4X, FFX_VARIABLESHADING_RATE1D_4X);
+ }
+#endif
+ return shadingRate;
+}
+
// Read luminance value from previous frame's color buffer.
FfxFloat32 VrsGetLuminance(FfxInt32x2 pos)
{
@@ -152,6 +202,24 @@ FfxInt32 VrsFlattenLdsOffset(FfxInt32x2 coord)
/// @ingroup FfxGPUVrs
void VrsGenerateVrsImage(FfxUInt32x3 Gid, FfxUInt32x3 Gtid, FfxUInt32 Gidx)
{
+ FfxUInt32 foveatedShadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_1X, FFX_VARIABLESHADING_RATE1D_1X);
+ if ((VrsAlgorithm() & FFX_VARIABLESHADING_IMAGE_ALGORITHM_FOVEATED) != 0)
+ {
+ foveatedShadingRate = VrsComputeFoveatedShadingRate(Gid, Gtid, Gidx);
+ }
+
+ // if motion based algorithm is disabled, or if foveation is returning coarsest rate already, early exit
+ if (((VrsAlgorithm() & FFX_VARIABLESHADING_IMAGE_ALGORITHM_LUMINANCE_AND_MOTION_VECTORS) == 0) ||
+ (foveatedShadingRate == FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_2X, FFX_VARIABLESHADING_RATE1D_2X)))
+ {
+ if (Gidx < FFX_VariableShading_NumBlocks)
+ {
+ WriteVrsImage(
+ FfxInt32x2(Gid.xy * FFX_VariableShading_NumBlocks1D + FfxUInt32x2(Gidx / FFX_VariableShading_NumBlocks1D, Gidx % FFX_VariableShading_NumBlocks1D)), foveatedShadingRate);
+ }
+ return;
+ }
+
FfxInt32x2 tileOffset = FfxInt32x2(Gid.xy * FFX_VariableShading_ThreadCount1D * 2);
FfxInt32x2 baseOffset = tileOffset + FfxInt32x2(-2, -2);
FfxUInt32 index = Gidx;
@@ -315,6 +383,9 @@ void VrsGenerateVrsImage(FfxUInt32x3 Gid, FfxUInt32x3 Gtid, FfxUInt32 Gidx)
shadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE((varH > VarianceCutoff()) ? FFX_VARIABLESHADING_RATE1D_1X : FFX_VARIABLESHADING_RATE1D_2X, FFX_VARIABLESHADING_RATE1D_1X);
}
}
+
+ shadingRate = FFX_VARIABLESHADING_SHADING_RATE_2D_MAX(shadingRate, foveatedShadingRate);
+
// Store
WriteVrsImage(
FfxInt32x2(Gid.xy * FFX_VariableShading_NumBlocks1D + FfxUInt32x2(Gidx / FFX_VariableShading_NumBlocks1D, Gidx % FFX_VariableShading_NumBlocks1D)), shadingRate);
@@ -333,6 +404,24 @@ void VrsGenerateVrsImage(FfxUInt32x3 Gid, FfxUInt32x3 Gtid, FfxUInt32 Gidx)
/// @ingroup FfxGPUVrs
void VrsGenerateVrsImage(FfxUInt32x3 Gid, FfxUInt32x3 Gtid, FfxUInt32 Gidx)
{
+ FfxUInt32 foveatedShadingRate = FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_1X, FFX_VARIABLESHADING_RATE1D_1X);
+ if ((VrsAlgorithm() & FFX_VARIABLESHADING_IMAGE_ALGORITHM_FOVEATED) != 0)
+ {
+ foveatedShadingRate = VrsComputeFoveatedShadingRate(Gid, Gtid, Gidx);
+ }
+
+ // if motion based algorithm is disabled, or if foveation is returning coarsest rate already, early exit
+ if (((VrsAlgorithm() & FFX_VARIABLESHADING_IMAGE_ALGORITHM_LUMINANCE_AND_MOTION_VECTORS) == 0) ||
+ (foveatedShadingRate == FFX_VARIABLESHADING_MAKE_SHADING_RATE(FFX_VARIABLESHADING_RATE1D_4X, FFX_VARIABLESHADING_RATE1D_4X)))
+ {
+ if (Gidx < FFX_VariableShading_TilesPerGroup)
+ {
+ WriteVrsImage(
+ FfxInt32x2(Gid.xy * FFX_VariableShading_NumBlocks1D + FfxUInt32x2(Gidx / FFX_VariableShading_NumBlocks1D, Gidx % FFX_VariableShading_NumBlocks1D)), foveatedShadingRate);
+ }
+ return;
+ }
+
FfxInt32x2 tileOffset = FfxInt32x2(Gid.xy * FFX_VariableShading_ThreadCount1D * 4);
FfxInt32x2 baseOffset = tileOffset;
FfxUInt32 index = Gidx;
@@ -469,6 +558,8 @@ void VrsGenerateVrsImage(FfxUInt32x3 Gid, FfxUInt32x3 Gtid, FfxUInt32 Gidx)
// write out final rates
if (Gidx < FFX_VariableShading_TilesPerGroup)
{
+ FFX_VariableShading_LdsGroupReduce[Gidx] = FFX_VARIABLESHADING_SHADING_RATE_2D_MAX(FFX_VariableShading_LdsGroupReduce[Gidx], foveatedShadingRate);
+
WriteVrsImage(
FfxInt32x2(Gid.xy * FFX_VariableShading_NumBlocks1D + FfxUInt32x2(Gidx / FFX_VariableShading_NumBlocks1D, Gidx % FFX_VariableShading_NumBlocks1D)),
FFX_VariableShading_LdsGroupReduce[Gidx]);
@@ -477,6 +568,8 @@ void VrsGenerateVrsImage(FfxUInt32x3 Gid, FfxUInt32x3 Gtid, FfxUInt32 Gidx)
// write out final rates
if (Gidx < FFX_VariableShading_TilesPerGroup)
{
+ shadingRate[Gidx] = FFX_VARIABLESHADING_SHADING_RATE_2D_MAX(shadingRate[Gidx], foveatedShadingRate);
+
WriteVrsImage(
FfxInt32x2(Gid.xy * FFX_VariableShading_NumBlocks1D + FfxUInt32x2(Gidx / FFX_VariableShading_NumBlocks1D, Gidx % FFX_VariableShading_NumBlocks1D)),
shadingRate[Gidx]);
diff --git a/sdk/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_glsl.h b/sdk/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_glsl.h
index 1df0e018..0726e2d6 100644
--- a/sdk/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_glsl.h
+++ b/sdk/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_glsl.h
@@ -33,10 +33,13 @@
layout(set = 0, binding = VRS_BIND_CB_VRS, std140) uniform cbVRS_t
{
FfxFloat32x2 motionVectorScale;
+ FfxFloat32x2 foveationCenter;
+ FfxFloat32x4 foveationRadiiSquared;
FfxFloat32 varianceCutoff;
FfxFloat32 motionFactor;
FfxInt32x2 resolution;
FfxUInt32 tileSize;
+ FfxUInt32 vrsAlgorithm;
} cbVRS;
#endif
@@ -86,6 +89,33 @@ FfxFloat32x2 MotionVectorScale()
#endif
}
+FfxFloat32x2 FoveationCenter()
+{
+#if defined(VRS_BIND_CB_VRS)
+ return cbVRS.foveationCenter;
+#else
+ return FfxFloat32x2(0.0f);
+#endif
+}
+
+FfxFloat32x4 FoveationRadiiSquared()
+{
+#if defined(VRS_BIND_CB_VRS)
+ return cbVRS.foveationRadiiSquared;
+#else
+ return FfxFloat32x4(0.0f);
+#endif
+}
+
+FfxUInt32 VrsAlgorithm()
+{
+#if defined(VRS_BIND_CB_VRS)
+ return cbVRS.vrsAlgorithm;
+#else
+ return 0;
+#endif
+}
+
// SRVs
#if defined VRS_BIND_SRV_INPUT_COLOR
layout (set = 0, binding = VRS_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color;
diff --git a/sdk/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_hlsl.h b/sdk/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_hlsl.h
index 9176a179..4f90382c 100644
--- a/sdk/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_hlsl.h
+++ b/sdk/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_hlsl.h
@@ -50,11 +50,14 @@
cbuffer cbVRS : FFX_VRS_DECLARE_CB(VRS_BIND_CB_VRS)
{
FfxFloat32x2 motionVectorScale;
+ FfxFloat32x2 foveationCenter;
+ FfxFloat32x4 foveationRadiiSquared;
FfxFloat32 varianceCutoff;
FfxFloat32 motionFactor;
FfxInt32x2 resolution;
FfxUInt32 tileSize;
- #define FFX_VRS_CONSTANT_BUFFER_1_SIZE 7
+ FfxUInt32 vrsAlgorithm;
+ #define FFX_VRS_CONSTANT_BUFFER_1_SIZE 14
}
#else
#define resolution 0
@@ -62,6 +65,9 @@
#define varianceCutoff 0
#define motionFactor 0
#define motionVectorScale 0
+ #define foveationCenter 0
+ #define foveationRadiiSquared 0
+ #define vrsAlgorithm 0
#endif
FfxInt32x2 Resolution()
@@ -89,6 +95,21 @@ FfxFloat32x2 MotionVectorScale()
return motionVectorScale;
}
+FfxFloat32x2 FoveationCenter()
+{
+ return foveationCenter;
+}
+
+FfxFloat32x4 FoveationRadiiSquared()
+{
+ return foveationRadiiSquared;
+}
+
+FfxUInt32 VrsAlgorithm()
+{
+ return vrsAlgorithm;
+}
+
#if defined(FFX_GPU)
#define FFX_VRS_ROOTSIG_STRINGIFY(p) FFX_VRS_ROOTSIG_STR(p)
#define FFX_VRS_ROOTSIG_STR(p) #p
diff --git a/sdk/include/FidelityFX/host/ffx_vrs.h b/sdk/include/FidelityFX/host/ffx_vrs.h
index 3533976f..e5f7ca26 100644
--- a/sdk/include/FidelityFX/host/ffx_vrs.h
+++ b/sdk/include/FidelityFX/host/ffx_vrs.h
@@ -99,6 +99,17 @@ typedef struct FfxVrsContextDescription
FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX.
} FfxVrsContextDescription;
+/// A structure encapsulating the 4 foveation shading rate regions radii.
+///
+/// @ingroup FfxVrs
+typedef struct FfxVrsFovRadii
+{
+ float radius1x1; ///< The radius of the 1x1 foveated shading rate outer boundary.
+ float radius1x2; ///< The radius of the 1x2 foveated shading rate outer boundary.
+ float radius2x2; ///< The radius of the 2x2 foveated shading rate outer boundary.
+ float radius2x4; ///< The radius of the 2x4 foveated shading rate outer boundary.
+} FfxVrsFovRadii;
+
/// A structure encapsulating the parameters for dispatching the various passes
/// of FidelityFX Variable Shading
///
@@ -106,6 +117,7 @@ typedef struct FfxVrsContextDescription
typedef struct FfxVrsDispatchDescription
{
FfxCommandList commandList; ///< The FfxCommandList to record VRS rendering commands into.
+ uint32_t vrsAlgorithm; ///< The algorithm to use for the VRS.
FfxResource historyColor; ///< A FfxResource containing the color buffer for the previous frame (at presentation resolution).
FfxResource motionVectors; ///< A FfxResource containing the velocity buffer for the current frame (at presentation resolution).
FfxResource output; ///< A FfxResource containing the ShadingRateImage buffer for the current frame.
@@ -114,6 +126,8 @@ typedef struct FfxVrsDispatchDescription
float motionFactor; ///< The lower this value, the faster a pixel has to move to get the shading rate reduced.
uint32_t tileSize; ///< ShadingRateImage tile size.
FfxFloatCoords2D motionVectorScale; ///< Scale motion vectors to different format
+ FfxFloatCoords2D foveationCenter; ///< The center of the foveated region.
+ FfxVrsFovRadii foveationRadiiSquared; ///< The radius of the foveated regions, expected squared by the shader.
} FfxVrsDispatchDescription;
/// A structure encapsulating the FidelityFX Variable Shading context.
diff --git a/sdk/src/components/vrs/ffx_vrs.cpp b/sdk/src/components/vrs/ffx_vrs.cpp
index 47fbc767..f26509bb 100644
--- a/sdk/src/components/vrs/ffx_vrs.cpp
+++ b/sdk/src/components/vrs/ffx_vrs.cpp
@@ -313,6 +313,7 @@ static FfxErrorCode vrsDispatch(FfxVrsContext_Private* context, const FfxVrsDisp
VrsConstants constants;
// Complete setting up the constant buffer data
+ constants.vrsAlgorithm = params->vrsAlgorithm;
constants.width = params->renderSize.width;
constants.height = params->renderSize.height;
constants.tileSize = params->tileSize;
@@ -320,6 +321,12 @@ static FfxErrorCode vrsDispatch(FfxVrsContext_Private* context, const FfxVrsDisp
constants.varianceCutoff = params->varianceCutoff;
constants.motionVectorScale[0] = params->motionVectorScale.x;
constants.motionVectorScale[1] = params->motionVectorScale.y;
+ constants.foveationCenter[0] = params->foveationCenter.x;
+ constants.foveationCenter[1] = params->foveationCenter.y;
+ constants.foveationRadiiSquared[0] = params->foveationRadiiSquared.radius1x1;
+ constants.foveationRadiiSquared[1] = params->foveationRadiiSquared.radius1x2;
+ constants.foveationRadiiSquared[2] = params->foveationRadiiSquared.radius2x2;
+ constants.foveationRadiiSquared[3] = params->foveationRadiiSquared.radius2x4;
// This value is the image region dimension that each thread group of the FSR shader operates on
uint32_t dispatchX;
diff --git a/sdk/src/components/vrs/ffx_vrs_private.h b/sdk/src/components/vrs/ffx_vrs_private.h
index e7a75fd7..d4cd7eb3 100644
--- a/sdk/src/components/vrs/ffx_vrs_private.h
+++ b/sdk/src/components/vrs/ffx_vrs_private.h
@@ -1,7 +1,7 @@
// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
-//
+//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
@@ -40,10 +40,13 @@ typedef enum VrsShaderPermutationOptions
typedef struct VrsConstants
{
float motionVectorScale[2];
+ float foveationCenter[2];
+ float foveationRadiiSquared[4];
float varianceCutoff;
float motionFactor;
uint32_t width, height;
uint32_t tileSize;
+ uint32_t vrsAlgorithm;
} VrsConstants;
// FfxFsr1Context_Private