跳至内容

FidelityFX Super Resolution 3.1.4 (FSR3) - 升采样器

Screenshot

AMD FidelityFX Super Resolution Upscaler 是一款开源的高质量解决方案,用于从低分辨率输入生成高分辨率帧。

目录

引言

FidelityFX Super Resolution Upscaler(简称 FSR)是一项尖端放大技术,其开发宗旨是从低分辨率输入生成高分辨率帧。

alt text

FSR 使用时间反馈来重建高分辨率图像,同时保持甚至提高与原生渲染相比的图像质量。

FSR 可以为昂贵的渲染操作(如硬件光线追踪)实现“实际性能”。

着色语言要求

  • HLSL
    • CS_6_2
    • CS_6_6†

† 在某些支持 64 位宽波前的硬件上使用 CS_6_6

  • Vulkan 1.x
  • GLSL 4.50,并支持以下扩展
    • GL_EXT_samplerless_texture_functions
    • GL_EXT_shader_image_load_formatted

请注意,GLSL 编译器还必须支持 GL_GOOGLE_include_directive 以处理 GLSL 着色器系统中使用的 #include

集成指南

FidelityFX Super Resolution Upscaler 应使用 FidelityFX API 进行集成,具体方法请参阅 组合 FSR 集成文档

本节其余部分的代码示例和参考描述了对 FidelityFX API 不支持的平台的集成。

缩放模式

为了方便最终用户,FSR API 提供了一些命名预设的缩放比例。

画质每维缩放因子
原生 AA1.0x
画质1.5x
平衡1.7x
性能2.0x
超高性能3.0x

我们强烈建议应用程序在其用户界面中使用一致的命名和缩放比例。这是为了确保你的应用程序的用户能够获得与其他使用 FSR 的应用程序相同的用户体验。

性能

根据您的目标硬件和配置,FSR 将在不同的性能级别运行。FSR3.1 的性能略低于 FSR3.0 放大器,但换来了更高的放大质量。

内存要求

使用 FSR 需要分配一些额外的 GPU 本地内存供 GPU 使用。在使用 FSR API 时,此内存会在创建 FSR 上下文时分配,并通过构成后端接口的回调系列进行分配。此内存用于存储 FSR 算法在 GPU 上计算的中间表面,以及在应用程序的许多帧中保持不变的持久性表面。下表包含 FSR 在各种操作条件下使用的内存量。“工作集”列表示 FSR 在 GPU 上执行算法时使用的总内存量;这是 FSR 运行所需的内存量。“持久内存”列表示“工作集”列中有多少内存需要保留下来供应用程序后续帧使用;此内存存储 FSR 使用的时间数据。“可别名内存”列表示“工作集”列中有多少内存可能与应用程序在 FSR 操作边界之外使用的表面或其他资源发生别名。

通过覆盖 FSR 后端接口的资源创建和销毁部分,并转发别名标志,您可以控制 FSR 中的资源创建。这意味着,对于 FSR 的完美集成,根据您的操作条件,需要额外的内存,其量等于下表中“持久内存”列的值。

分辨率画质工作集 (MB)持久内存 (MB)可别名内存 (MB)
3840x2160质量 (1.5x)218MB183MB35MB
平衡 (1.7x)174MB145MB29MB
性能 (2x)133MB111MB22MB
超高性能 (3x)58MB48MB10MB
2560x1440质量 (1.5x)106MB89MB17MB
平衡 (1.7x)84MB70MB14MB
性能 (2x)61MB51MB10MB
超高性能 (3x)30MB25MB5MB
1920x1080质量 (1.5x)61MB51MB10MB
平衡 (1.7x)47MB39MB8MB
性能 (2x)40MB33MB7MB
超高性能 (3x)17MB14MB3MB

数据为近似值,使用 RX 6700XT GPU 在 DX12 下四舍五入到最近的 MB,可能会有变动。

输入资源

FSR 是一种时间算法,因此需要访问当前帧和上一帧的数据。下表列出了 FSR 所需的所有外部输入。

分辨率列表示数据应该是“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。所有资源均来自当前渲染的帧,对于 DirectX(R)12 和 Vulkan(R) 应用程序,在调用 ffxFsr3UpscalerContextDispatch 之前,所有输入资源都应分别转换为 D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCEVK_ACCESS_SHADER_READ_BIT

名称分辨率格式类型说明
颜色缓冲区渲染应用程序指定纹理应用程序提供的当前帧的渲染分辨率颜色缓冲区。如果颜色缓冲区的内容是高动态范围 (HDR),则应在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置 FFX_FSR3UPSCALER_ENABLE_HIGH_DYNAMIC_RANGE 标志。
深度缓冲区渲染应用程序指定 (1x FLOAT)纹理应用程序提供的当前帧的渲染分辨率深度缓冲区。数据应提供为单个浮点值,其精度由应用程序控制。应通过创建 FfxFsr3UpscalerContextFfxFsr3UpscalerContextDescription 结构体的 flags 字段将深度配置传达给 FSR。如果您的深度缓冲区是反转的(即 [1..0] 范围),则应设置 FFX_FSR3UPSCALER_ENABLE_DEPTH_INVERTED 标志,如果您的深度缓冲区具有无限远平面,则应设置 FFX_FSR3UPSCALER_ENABLE_DEPTH_INFINITE 标志。如果应用程序以 D32S8 格式提供深度缓冲区,则 FSR 将忽略缓冲区的模板分量,并创建一个 R32_FLOAT 资源来处理深度缓冲区。在 GCN 和 RDNA 硬件上,深度缓冲区与模板缓冲区分开存储。
运动矢量渲染或呈现应用程序指定 (2x FLOAT)纹理应用程序提供的当前帧的 2D 运动向量,范围为 **[<-width, -height> … <width, height>]**。如果您的应用程序以不同的范围渲染运动向量,则可以使用 FfxFsr3UpscalerDispatchDescription 结构的 motionVectorScale 字段来调整它们以匹配 FSR 的预期范围。在内部,FSR 在许多情况下使用 16 位量来表示运动向量,这意味着虽然可以提供更高精度的运动向量,但 FSR 将无法从增加的精度中受益。除非在创建 FfxFsr3UpscalerContext 时在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置了 FFX_FSR3UPSCALER_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS 标志,否则运动向量缓冲区的分辨率应等于渲染分辨率,在这种情况下,它应等于显示分辨率。
T&C 遮罩渲染R8_UNORM纹理渲染图像的某些区域可能没有与着色变化相匹配的运动矢量,尤其是对于高度反射的表面或具有纹理动画的对象。在这些情况下,使用 T&C 遮罩比反应式遮罩更柔和,因为它仅影响锁定和颜色钳制,而反应式遮罩会减弱历史信息的影响。
反应式遮罩渲染R8_UNORM纹理由于渲染图像的某些区域在深度缓冲区中没有留下痕迹或包含运动矢量,FSR 支持反应式遮罩纹理,可用于向 FSR 指示这些区域的位置。粒子或不写入深度或运动矢量的 Alpha 混合对象是很好的例子。如果未设置此资源,则 FSR 的着色变化检测逻辑将尽力处理这些情况,但为获得最佳结果,应设置此资源。有关反应式遮罩的更多信息,请参阅 反应式遮罩 部分。
曝光1x1R32_FLOAT纹理包含当前帧计算的曝光值的 1x1 纹理。此资源是可选的,如果创建 FfxFsr3UpscalerContext 时在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置了 FFX_FSR3UPSCALER_ENABLE_AUTO_EXPOSURE 标志,则可以省略此资源。

所有在渲染分辨率下提供的输入(运动向量除外)都应进行抖动渲染。除非存在 FFX_FSR_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION 标志,否则不应对运动向量应用抖动。

深度缓冲区配置

强烈建议使用反转的无限深度缓冲区与 FSR 一起使用。但是,也支持替代的深度缓冲区配置。应用程序应通过在创建 FfxFsr3UpscalerContext 时设置适当的标志来告知 FSR API 其深度缓冲区配置。下表包含相应的标志。

FSR 标志说明
FFX_FSR3UPSCALER_ENABLE_DEPTH_INVERTED一个位,指示提供的输入深度缓冲区数据是反转的 [max..0]。
FFX_FSR3UPSCALER_ENABLE_DEPTH_INFINITE一个位,指示提供的输入深度缓冲区数据使用的是无限远平面。

提供运动矢量

空间

时间算法(无论是抗锯齿还是放大)的一个关键部分是提供运动矢量。FSR 接受 2D 运动矢量,它编码了当前帧中像素到上一帧同一像素位置的运动。FSR 期望应用程序提供的运动矢量在 [<-width, -height>..<width, height>] 范围内;这与屏幕空间匹配。例如,屏幕左上角像素的运动矢量值为 <width, height>,表示一个横跨输入表面全部宽度和高度的运动,源自右下角。

alt text

如果您的应用程序在其他空间(例如,标准化设备坐标空间)中计算运动向量,则可以使用 FfxFsr3UpscalerDispatchDescription 结构的 motionVectorScale 字段来指导 FSR 将它们调整为匹配 FSR 的预期范围。下面的代码示例说明了如何将 NDC 空间运动向量缩放到屏幕空间。下面的 HLSL 和 C++ 代码示例说明了如何使用 FSR 主机 API 来缩放 NDC 空间运动向量。

// GPU: Example of application NDC motion vector computation
float2 motionVector = (previousPosition.xy / previousPosition.w) - (currentPosition.xy / currentPosition.w);
// CPU: Matching FSR 2.0 motionVectorScale configuration
dispatchParameters.motionVectorScale.x = (float)renderWidth;
dispatchParameters.motionVectorScale.y = (float)renderHeight;

精度和分辨率

在内部,FSR 在许多情况下使用 16 位量来表示运动向量,这意味着虽然可以提供更高精度的运动向量,但 FSR 目前将无法从增加的精度中受益。运动向量缓冲区的分辨率应等于渲染分辨率,除非在创建 FfxFsr3UpscalerContext 时在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置了 FFX_FSR3UPSCALER_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS 标志,在这种情况下,它应等于显示分辨率。

覆盖率

当更多对象提供其运动矢量时,FSR 的放大质量会更好。因此,建议所有不透明、Alpha 测试和 Alpha 混合对象都为其覆盖的所有像素写入其运动矢量。如果应用了顶点着色器效果(例如滚动 UV),这些计算也应纳入运动计算中以获得最佳结果。对于 Alpha 混合对象,强烈建议将每个覆盖像素的 Alpha 值存储到 反应式遮罩 中对应的像素。这将使 FSR 在放大时能够更好地处理 Alpha 混合对象。反应式遮罩对于 Alpha 混合对象尤其重要,因为对于这些对象,写入运动矢量可能会很困难,例如粒子。

反应式遮罩

在 FSR 的上下文中,“反应性”一词指的是当前帧渲染的样本对最终放大图像的生成有多大影响。通常,当前帧渲染的样本对 FSR 计算的结果贡献相对较小;但是,也有例外。为了对快速移动的 Alpha 混合对象产生最佳结果,FSR 要求“重投影和累积”阶段对这些像素变得更加具反应性。由于无法通过颜色、深度或运动矢量准确判断哪些像素是使用 Alpha 混合渲染的,因此当应用程序显式标记这些区域时,FSR 的效果最好。

因此,强烈鼓励应用程序向 FSR 提供反应式遮罩。反应式遮罩指导 FSR 在何处应减少对历史信息的依赖来组合当前像素,并允许当前帧的样本更多地贡献到最终结果。反应式遮罩允许应用程序提供一个 [0.0..1.0] 范围内的值,其中 0.0 表示像素完全不具反应性(并应使用默认的 FSR 合成策略),而 1.0 表示像素应完全具反应性。这是一个浮点范围,可以根据不同情况进行定制。

虽然反应式遮罩还有其他应用,但其主要应用是改善包含 Alpha 混合对象的图像放大结果。Alpha 混合对象组合到场景中的 Alpha 值实际上是反应性的良好代理,因此,应用程序应将 alpha 写入反应式遮罩。需要注意的是,反应性值接近 1 可能不太可能产生好的结果。因此,我们建议将最大反应性值钳制在 0.9 左右。

如果未向 FSR 提供“反应性掩码”(通过将 FfxFsr3UpscalerDispatchDescriptionreactive 字段设置为 NULL),则将使用一个内部生成的 1x1 纹理,其中反应性值已清除。

自动生成反应性

为了帮助应用程序生成 反应式遮罩透明度和合成遮罩,FSR 提供了一个可选的辅助 API。在底层,API 会启动一个计算着色器,该计算着色器使用基于亮度的启发式方法为每个像素计算这些值。

希望执行此操作的应用程序可以调用 FfxFsr3UpscalerContextGenerateReactiveMask 函数,并应传递颜色缓冲区的两个版本:一个包含纯不透明几何体,另一个包含不透明和 alpha 混合对象。

透明度和合成遮罩

除了 反应式遮罩 之外,FSR 还允许应用程序标记其他专业渲染区域,这些区域应在放大过程中予以考虑。此类特殊渲染的示例包括光线追踪反射或动画纹理的区域。

虽然 反应式遮罩 调整累积平衡,但 透明度和合成遮罩 调整像素历史保护机制。该遮罩还会消除亮度不稳定性因子的影响。在 透明度和合成遮罩 中值为 0 的像素不会对该像素的锁定进行任何额外修改。相反,值为 1 表示该像素的锁定应完全移除。

如果未向 FSR 提供“透明度和组合掩码”(通过将 FfxFsr3UpscalerDispatchDescriptiontransparencyAndComposition 字段设置为 NULL),则将使用一个内部生成的 1x1 纹理,其中透明度和组合值已清除。

曝光

FSR 提供两个值来控制放大过程中使用的曝光。它们如下:

  1. 预曝光:一个值,我们将输入信号除以它,以恢复游戏在打包到低精度渲染目标之前生成的原始信号。
  2. 曝光:一个值,它乘以预曝光颜色值的计算结果。

曝光值应与应用程序在后续色调映射过程中使用的值匹配。这意味着 FSR 将与最终色调映射图像中可能看到的内容一致地运行。

在此文档中描述的 FSR 算法的各个阶段,FSR 将计算自己的曝光值供内部使用。值得注意的是,FSR 的所有输出将在写入最终输出之前,将其内部色调映射反转。这意味着 FSR 返回的结果与原始输入信号的域相同。

选择不当的曝光值会对 FSR 放大质量的最终质量产生巨大影响。因此,除非有特殊原因,否则建议应用程序使用 FFX_FSR3UPSCALER_ENABLE_AUTO_EXPOSURE。当在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置 FFX_FSR3UPSCALER_ENABLE_AUTO_EXPOSURE 时,将使用下面 HLSL 代码中所示的曝光计算来计算曝光值,该值与 ISO 100 胶片感光度的曝光响应相匹配。

float ComputeAutoExposureFromAverageLog(float averageLogLuminance)
{
const float averageLuminance = exp(averageLogLuminance);
const float S = 100.0f; // ISO arithmetic speed
const float K = 12.5f;
const float exposureIso100 = log2((averageLuminance * S) / K);
const float q = 0.65f;
const float luminanceMax = (78.0f / (q * S)) * pow(2.0f, exposureIso100);
return 1 / luminanceMax;
}

在帧中的位置

FSR 的主要目标是通过使用依赖于多个输入的时域放大算法来提高应用程序的渲染性能。因此,其在管线中的位置是确保最高视觉质量与出色性能之间正确平衡的关键。

alt text

对于任何图像放大方法,了解如何将其他图像空间算法放置在放大算法相对于其位置都很重要。在放大之前放置这些其他图像空间效果的优点是它们以较低的分辨率运行,这当然会为应用程序带来性能优势。然而,这可能不适用于某些类别的图像空间技术。例如,许多应用程序可能会在最终图像中引入噪点或颗粒感,或许是为了模拟物理相机。在放大器之前执行此操作可能会导致放大器放大噪点,从而在放大的图像中产生不期望的伪影。下表将常见的实时图像空间技术分为两列。“后期处理 A”包含通常在 FSR 放大之前运行的所有技术,这意味着它们都将在渲染分辨率下运行。相反,“后期处理 B”列包含建议在 FSR 之后运行的所有技术,这意味着它们将在较大的显示分辨率下运行。

后期处理 A后期处理 B
屏幕空间反射胶片颗粒
屏幕空间环境光遮蔽色差
去噪器(阴影、反射)晕影
曝光(可选)色调映射
光晕
景深
动态模糊

请注意,此处提出的建议仅供参考,具体取决于你的应用程序实现的具体特性。

时间抗锯齿

时间抗锯齿 (TAA) 是一种利用上一帧输出来构建当前帧更高质量输出的技术。由于 FSR 具有类似的目标(尽管还增加了提高渲染图像分辨率的目标),因此不再需要在应用程序中包含单独的 TAA 通道。

相机抖动

FSR 依赖应用程序在渲染时应用亚像素抖动 - 这通常包含在相机的投影矩阵中。为了简化相机抖动的应用,FSR API 提供了一小组实用函数,用于计算特定帧在独立抖动偏移序列中的亚像素抖动偏移。

int32_t ffxFsr3UpscalerGetJitterPhaseCount(int32_t renderWidth, int32_t displayWidth);
FfxErrorCode ffxFsr3UpscalerGetJitterOffset(float* outX, float* outY, int32_t jitterPhase, int32_t sequenceLength);

内部,这些函数实现了 Halton[2,3] 序列 [Halton]。Halton 序列的目标是提供空间分离的点,这些点覆盖了可用空间。

alt text

重要的是要理解从 ffxFsr3UpscalerGetJitterOffset 返回的值是以单位像素空间为单位的,并且为了正确地将其合成到投影矩阵中,我们必须将其转换为投影偏移量。上图显示了单位像素空间中的单个像素,以及投影空间中的单个像素。下面的代码列表显示了如何将亚像素抖动偏移量正确地合成到投影矩阵中。

const int32_t jitterPhaseCount = ffxFsr3UpscalerGetJitterPhaseCount(renderWidth, displayWidth);
float jitterX = 0;
float jitterY = 0;
ffxFsr3UpscalerGetJitterOffset(&jitterX, &jitterY, index, jitterPhaseCount);
// Calculate the jittered projection matrix.
const float jitterX = 2.0f * jitterX / (float)renderWidth;
const float jitterY = -2.0f * jitterY / (float)renderHeight;
const Matrix4 jitterTranslationMatrix = translateMatrix(Matrix3::identity, Vector3(jitterX, jitterY, 0));
const Matrix4 jitteredProjectionMatrix = jitterTranslationMatrix * projectionMatrix;

抖动应应用于所有渲染。这包括不透明、alpha 透明和光线追踪对象。对于栅格化对象,可以通过最终用于在顶点着色期间执行变换的相机投影矩阵来应用 ffxFsr3UpscalerGetJitterOffset 函数计算出的亚像素抖动值。对于光线追踪渲染,亚像素抖动应应用于射线的起点——通常是相机的位置。

无论您选择使用推荐的 ffxFsr3UpscalerGetJitterOffset 函数还是自己的序列生成器,您都必须将 FfxFsr3UpscalerDispatchDescription 结构体的 jitterOffset 字段设置为 true,以告知 FSR 已应用抖动偏移量来渲染每个帧。此外,如果未使用推荐的 ffxFsr3UpscalerGetJitterOffset 函数,则应小心确保您的抖动序列永远不会生成空向量;即 X 和 Y 维度的值为 0。

下表显示了每个默认质量模式的抖动序列长度。

质量模式缩放因子序列长度
画质1.5x (每维)18
平衡1.7x (每维)23
性能2.0x (每维)32
超高性能3.0x (每维)72
自定义[1..n]x (每维)ceil(8 * n^2)

相机跳切

大多数具有实时渲染的应用程序在任何两个连续帧之间都具有高度的时间一致性。但是,在某些情况下,相机变换的更改可能会导致渲染内容发生剧烈变化。在这种情况下,FSR 不太可能重用它从前几帧累积的任何数据,并且应该清除这些数据,以将其排除在合成过程的考虑之外。为了向 FSR 表明相机发生了跳转剪辑,您应该将 FfxFsr3UpscalerDispatchDescription 结构体的 reset 字段设置为 true,用于不连续相机变换的第一帧。

使用 reset 标志时,FSR 将清除一些额外的内部资源,因此渲染性能可能略低于典型的帧到帧操作。

Mipmap 偏差

应用负的 mipmap 偏差通常会生成具有更好纹理细节的放大图像。我们建议将以下公式应用于你的 Mipmap 偏差:

mipBias = log2(renderResolution/displayResolution) - 1.0;

建议应用程序为特定的高频纹理内容调整 MIP 偏差,这些内容容易出现时间混叠问题。

下表说明了根据上述伪代码计算出的、与应用程序应向最终用户提供的建议画质模式相匹配的缩放比例所产生的Mipmap偏置因子。

质量模式缩放因子Mipmap偏置
画质1.5倍 (每维度)-1.58
平衡1.7倍 (每维度)-1.76
性能2.0倍 (每维度)-2.0
超高性能3.0倍 (每维度)-2.58

帧时间增量输入

FSR API 要求应用程序通过 FfxFsr3UpscalerDispatchDescription 结构体提供 frameTimeDelta。此值以**毫秒**为单位:如果以 60fps 运行,则传递的值应约为 **16.6f**。

该值用于 FSR 2 自动曝光功能的时域部分。这允许为了质量目的对历史累积进行调整。

HDR 支持

FSR 支持高动态范围图像。要启用此功能,您应该在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置 FFX_FSR3UPSCALER_ENABLE_HIGH_DYNAMIC_RANGE 位。图像应以线性颜色空间提供给 FSR。

未来版本的FSR可能会提供对其他色彩空间的支持。

回退到 32 位浮点

FSR 被设计用于利用半精度 (FP16) 硬件加速来实现最高性能。但是,为了提供最大的兼容性和灵活性,FSR 还包含使用全精度 (FP32) 操作编译着色器的功能。

建议在所有支持它的硬件上使用 FSR 的 FP16 版本。您可以通过查询 DirectX(R)12 中的 D3D12_FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT 功能来查询您的图形卡的 FP16 支持级别——您应该检查是否设置了 D3D[11/12]_SHADER_MIN_PRECISION_16_BIT,如果没有,则回退到 FSR 的 FP32 版本。对于 Vulkan,如果未设置 VkPhysicalDeviceShaderFloat16Int8FeaturesKHR::shaderFloat16,则应回退到 FSR 的 FP32 版本。同样,如果未设置 VkPhysicalDevice16BitStorageFeatures::storageBuffer16BitAccess,您也应回退到 FSR 的 FP32 版本。

要在 FSR 着色器源代码中启用 FP32 路径,您应该将 FFX_HALF 定义为 1。为了在 FP16 和 FP32 之间共享大部分算法的源代码(确保高水平的代码共享以支持持续维护),您会注意到 FSR 着色器源代码使用了一组类型宏,这些宏可以方便地在着色器源代码中 16 位和 32 位基本类型之间进行切换。

FidelityFX 类型FP32FP16
FFX_MIN16_Ffloatmin16float
FFX_MIN16_F2float2min16float2
FFX_MIN16_F3float3min16float3
FFX_MIN16_F4float4min16float4

上表列出了抽象 FidelityFX SDK 类型与底层内在类型之间的映射,具体取决于编译期间着色器源代码的配置。

64 位宽波前

现代 GPU 以 SIMT 方式一起执行线程集合(称为波前)。构成单个波精的确切线程数是特定于硬件的数量。某些硬件,例如 AMD 的 GCN 和 RDNA 系列 GPU,支持将 64 个线程组合成单个波前。根据算法执行的精确特性,偏好特定波前宽度可能更有利或更有利。随着 Shader Model 6.6 的引入,Microsoft 添加了通过 HLSL 指定波前宽度的功能。对于支持 32 位和 64 位波前宽度的硬件(如 RDNA),这是优化用途的一个非常有用的工具,因为它提供了一种清晰且可移植的方式来请求驱动程序软件堆栈执行特定宽度的波前。

对于在 RDNA 和 RDNA2 系列 GPU 上运行并使用 Microsoft Agility SDK 的 DirectX(R)12 应用程序,FSR 主机 API 将选择一个 64 位宽的波前宽度。

调试器

启用调试检查器以在调度放大时验证应用程序提供的输入。此功能可以在运行时(例如,来自PrebuiltSignedDll文件夹的发布二进制文件或调试构建)的任何构建配置中启用。建议仅在游戏的开发构建中启用此功能。

FfxFsr3UpscalerContextDescription 的 flags 成员中传递 FFX_FSR3UPSCALER_ENABLE_DEBUG_CHECKING 标志,默认情况下将从放大器向调试器 TTY 输出文本警告消息。应用程序可以设置运行时回调函数,将消息传递给底层应用程序。应用程序可以将 FfxFsr3UpscalerContextDescription 中的 fpMessage 分配给合适的函数。fpMessage 的类型为 FfxFsr3UpscalerMessage,它是一个函数指针,用于传递各种类型的字符串消息。另一种方法是在放大器上下文上调用 ffx::Configure fpMessage in ffxConfigureDescGlobalDebug1

当检查器检测到潜在问题时可能发生的输出示例如下:

FSR_API_DEBUG_WARNING: FFX_FSR_ENABLE_DEPTH_INFINITE and FFX_FSR_ENABLE_DEPTH_INVERTED present, cameraFar value is very low which may result in depth separation artefacting
FSR_API_DEBUG_WARNING: frameTimeDelta is less than 1.0f - this value should be milliseconds (~16.6f for 60fps)

技术

算法结构

FSR 算法实现为一系列阶段,如下所示:

  1. 准备输入
  2. 计算亮度金字塔
  3. 计算着色变化金字塔
  4. 计算着色变化
  5. 准备反应性
  6. 计算亮度不稳定性
  7. 累积
  8. (可选) 鲁棒对比度自适应锐化 (RCAS)

算法的每个传递阶段将在接下来的章节中进行阐述,但下面图表中显示了完整 FSR 算法的数据流。

alt text

准备输入

准备输入阶段会消耗应用程序的颜色、深度缓冲区和运动向量,并生成上一帧的重建和扩张深度缓冲区,以及 UV 空间中的扩张运动向量集。它还会生成最远和最近的扩张深度缓冲区,并计算当前颜色缓冲区的亮度。该阶段在渲染分辨率下运行。

alt text

资源输入

下表包含准备输入阶段所需的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
颜色缓冲区当前帧渲染应用程序指定纹理应用程序提供的当前帧的渲染分辨率颜色缓冲区。如果颜色缓冲区的内容是高动态范围 (HDR),则应在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置 FFX_FSR3UPSCALER_ENABLE_HIGH_DYNAMIC_RANGE 标志。
深度缓冲区当前帧渲染应用程序指定 (1x FLOAT)纹理应用程序提供的当前帧的渲染分辨率深度缓冲区。数据应提供为单个浮点值,其精度由应用程序控制。应通过创建 FfxFsr3UpscalerContextFfxFsr3UpscalerContextDescription 结构体的 flags 字段将深度配置传达给 FSR。如果您的深度缓冲区是反转的(即 [1..0] 范围),则应设置 FFX_FSR3UPSCALER_ENABLE_DEPTH_INVERTED 标志,如果您的深度缓冲区具有无限远平面,则应设置该标志。如果应用程序以 D32S8 格式提供深度缓冲区,则 FSR 将忽略缓冲区的模板分量,并创建一个 R32_FLOAT 资源来处理深度缓冲区。在 GCN 和 RDNA 硬件上,深度缓冲区与模板缓冲区分开存储。
运动矢量当前帧渲染或呈现应用程序指定 (2x FLOAT)纹理应用程序提供的当前帧的 2D 运动向量,范围为 [<-width, -height>..<width, height>]。如果您的应用程序以不同的范围渲染运动向量,则可以使用 FfxFsr3UpscalerDispatchDescription 结构的 motionVectorScale 字段来调整它们以匹配 FSR 的预期范围。在内部,FSR 在许多情况下使用 16 位量来表示运动向量,这意味着虽然可以提供更高精度的运动向量,但 FSR 将无法从增加的精度中受益。运动向量缓冲区的分辨率应等于渲染分辨率,除非在创建 FfxFsr3UpscalerContext 时在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置了 FFX_FSR3UPSCALER_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS 标志,在这种情况下,它应等于显示分辨率。

资源输出

下表包含准备输入阶段产生的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
重建的上一帧深度缓冲区当前帧渲染R32_UINT纹理包含重建的上一帧深度值的纹理。此表面应首先清除,请参阅“调整输入颜色”阶段以获取详细信息。
扩张的深度当前帧渲染R32_FLOAT纹理包含从应用程序深度缓冲区计算出的最近深度值的扩张的纹理。
最远深度当前帧渲染R16_FLOAT纹理包含从应用程序深度缓冲区计算出的深度值的纹理。
扩张的运动向量当前帧渲染R16G16_FLOAT纹理包含从应用程序 2D 运动向量缓冲区计算出的扩张的 2D 运动向量的纹理。红色和绿色通道包含 NDC 空间中的二维运动向量。
亮度当前帧渲染R16_FLOAT纹理包含输入颜色图像亮度的纹理。

描述

准备输入阶段的第一步是计算当前帧的深度值和运动向量的扩张深度值和运动向量。扩张的深度值和运动向量会强调已渲染到深度缓冲区中的几何体的边缘。这是因为几何体的边缘通常会在连续的深度值序列中引入不连续性,这意味着当深度值和运动向量被扩张时,它们会自然地遵循深度缓冲区中存在的几何边缘的轮廓。为了计算扩张的深度值和运动向量,FSR 会查看每个像素的 3x3 邻域的深度值,然后选择该邻域中深度值最接近相机的深度值和运动向量。在下面的图表中,您可以看到 3x3 核的中心像素如何被更新为具有最大深度值的像素(中心右侧的像素)的深度值和运动向量。

由于这是 FSR 首次使用运动向量,如果使用 FSR 主机 API,则在此处应用运动向量缩放。通过 FfxFsr3UpscalerDispatchDescription 结构的 motionVectorScale 字段提供的运动向量缩放因子允许您将非屏幕空间运动向量转换为 FSR 期望的屏幕空间运动向量。

// An example of how to manipulate motion vector scaling factors using the FSR host API.
FfxFSRDispatchParameters dispatchParams = { 0 };
dispatchParams.motionVectorScale.x = renderWidth;
dispatchParams.motionVectorScale.y = renderHeight;

有了扩张的运动向量,我们现在可以近似地将当前帧深度缓冲区的每个像素重新投影到上一帧中相应几何体所在的位置。这是通过将扩张的运动向量应用于 UV 坐标来实现的,以获得上一帧的 UV 坐标。然后,当前深度值被写入重建的上一帧深度缓冲区中的 4 个像素,这些像素位于上一帧 UV 之间。由于可能有很多像素重新投影到上一帧深度缓冲区中的同一像素,因此使用原子操作来解析每个像素的最近深度值。这是使用 InterlockedMaxInterlockedMin 操作(选择取决于应用程序的深度缓冲区是否反转)。请注意,此操作不会产生与上一帧匹配的深度缓冲区,因为未考虑 Z 轴上的运动,但它对于计算遮挡/非遮挡仍然足够好。

alt text

在使用 FSR API 时,应用程序的深度缓冲区和应用程序的速度缓冲区必须根据上面的资源输入表指定为单独的资源。但是,如果您正在进行定制集成到您的应用程序中,则此约束可能会放宽。请注意,如果在运动向量纹理的格式(例如,作为延迟渲染器中打包的 g-buffer 的一部分)发生变化时,此通道的性能特征不会改变。

准备输入阶段的最后任务是读取抖动的输入颜色,计算亮度值并将其存储在亮度纹理中。

计算亮度金字塔

计算亮度金字塔阶段有两个职责:

  1. 计算输入颜色的曝光、log(亮度) 和场景平均亮度值,这些值存储在 FrameInfo 中。这用于准备反应性、计算亮度不稳定性以及累积传递。
  2. 计算最远深度图的半分辨率版本,该版本将在累积阶段使用。

资源输入

下表包含计算亮度金字塔阶段消耗的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
最远深度当前帧渲染R16_FLOAT纹理包含应用程序深度缓冲区经过扩张、降低分辨率版本的纹理。
亮度当前帧渲染R16_FLOAT纹理包含输入颜色图像亮度的纹理。请注意:此纹理是一个包含两个纹理的数组。用于输入和输出的数组中纹理的选择每帧都会交换。

资源输出

下表包含计算亮度金字塔阶段产生或修改的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
FrameInfo当前帧1x1R32G32B32A32_FLOAT纹理一个 1x1 的纹理,包含当前帧的曝光值、log(亮度) 和场景平均亮度。自动曝光值是可选的,如果创建 FfxFsr3UpscalerContext 时,在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中没有设置 FFX_FSR_ENABLE_AUTO_EXPOSURE 标志,则可以省略。
最远深度 Mip1当前帧半分辨率渲染R16_FLOAT纹理一个 50% 渲染分辨率的纹理,其中包含平均最远深度。

描述

计算亮度金字塔”阶段使用 FidelityFX 单通道降采样器 (Single Pass Downsampler) 实现,这是一种使用单个计算着色器调度生成 mipmap 链的优化技术。与传统的(完整)金字塔方法不同,SPD 提供了一种机制,可以为任意输入纹理生成一组特定的 mipmap 级别,并在将数据存储到内存目标位置时对该数据执行任意计算。在 FSR 中,我们根据 FfxFsr3UpscalerContext 的配置,最多只需要生成两个中间资源。第一个资源是当前亮度的低分辨率表示,稍后在 FSR 中用于检测着色变化。第二个是曝光值,虽然它总是被计算出来,但只有当上下文创建时,在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中设置了 FFX_FSR3UPSCALER_ENABLE_AUTO_EXPOSURE 标志时,后续阶段才会使用它。曝光值(无论是来自应用程序还是“计算亮度金字塔”阶段)都会在 FSR 的“调整输入颜色”阶段以及“重投影与累积”阶段中使用。第三个值是由“准备输入”阶段通过膨胀深度缓冲区计算出的最远深度。在第一个缩减阶段(对这三个值进行平均)之后,将写入 FarthestDepthMip1。其余的通道会向下缩减亮度,直到可以在 1x1 的输出纹理中写入自动曝光值。

alt text

FSR 使用的 SPD 被配置为仅写入最远深度图的第二个(半分辨率)mipmap 级别,以及亮度/曝光的最后一个(1x1)mipmap 级别。此外,该算法还需要写入第六个 mipmap 级别以同步所有线程组,并切换到使用单个工作组计算 mip-chain 的尾部。有关更多详细信息,请参阅 SPD 的文档。此外,在这些级别上的不同计算用于计算 FSR 算法后续阶段所需的值。这意味着 mipmap 链的其余部分不需要由 GPU 本地内存(甚至任何类型的内存)支持。

计算着色变化金字塔

计算着色变化金字塔”阶段消耗膨胀的运动矢量以及当前和前一帧的亮度,并生成一个包含自上一帧以来亮度变化的完整 mipmap 链。该阶段以半渲染分辨率运行。

资源输入

下表包含“计算着色变化金字塔”阶段所需的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
亮度当前帧渲染R16_FLOAT纹理当前帧的渲染分辨率亮度缓冲区。此纹理在准备输入通道中计算。
亮度上一帧渲染R16_FLOAT纹理上一帧的渲染分辨率亮度缓冲区。此纹理是在上一帧的准备输入通道中计算的。
扩张的运动向量当前帧渲染R16G16_FLOAT纹理当前帧的膨胀 2D 运动矢量,由应用程序在准备输入中提供的运动矢量计算得出。

资源输出

下表包含“计算着色变化金字塔”阶段产生的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
着色变化 mip当前帧半分辨率渲染R16G16_FLOAT纹理一个纹理,包含自上一帧以来发生的着色变化,包括完整的 mip 链。第一个通道包含亮度的最小差异,第二个通道包含亮度差异的平均符号,因此它表示局部亮度变化的**方向**。例如,第二个通道中的值为 1.0 表示所有像素都变亮了,-1.0 表示所有像素都变暗了。值为 0.0 可能仍然表示所有像素都发生了重大变化,但不是**同一方向**。

描述

计算着色变化金字塔”阶段使用 FidelityFX 单通道降采样器 (Single Pass Downsampler) 实现,这是一种使用单个计算着色器调度生成 mipmap 链的优化技术。与传统的(完整)金字塔方法不同,SPD 提供了一种机制,可以为任意输入纹理生成一组特定的 mipmap 级别,并在将数据存储到内存目标位置时对该数据执行任意计算。在 FSR 中,我们根据 FfxFsr3UpscalerContext 的配置,最多只需要生成两个中间资源。此通道在加载资源时加载当前帧和上一帧的亮度值(使用膨胀的运动矢量加载上一帧的数据),并计算四边形内亮度**最小相对差**。它还计算最小差值的**符号**。后续通道通过简单平均计算出前一个 mipmap 的下一个 mipmap。这会产生平均着色变化和一个与发生着色变化的像素数量成比例的值。

计算着色变化

计算着色变化”阶段通过将着色变化 mip 链的层组合成一个单一层来计算平均着色变化。

此阶段以半渲染分辨率运行。

资源输入

下表包含“计算着色变化”阶段所消耗的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
着色变化 mip当前帧半分辨率渲染R16G16_FLOAT纹理一个纹理,包含完整 mip 链的值,描述了着色变化的程度以及变化在像素覆盖区域内的一致性。

资源输出

下表包含“计算着色变化”阶段产生的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
着色变化当前帧渲染R8_UNORM纹理一个纹理,包含有关每个像素附近着色变化的**信息**。

描述

为了生成着色变化率,此通道计算绝对着色变化并将其乘以一致性。然后将此值在所有 mip 级别上的最大值存储为着色变化值。

准备反应性

此“准备响应性”阶段负责计算响应性,即定义如何将上一帧的颜色与当前样本混合以计算最终输出值的**值**。为此,它通过计算“计算着色变化”阶段计算出的着色变化值与可选的 T&C 和响应性掩码来计算最终响应性掩码。它还计算**遮挡解除掩码**,计算**新锁定**并更新**累积值**。

此阶段以渲染分辨率运行。

资源输入

下表包含“准备响应性”阶段消耗的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
亮度当前帧渲染R16_FLOAT纹理一个包含将由锁定阶段消耗的亮度数据的纹理。
FrameInfo当前帧1x1R32G32B32A32_FLOAT纹理一个 1x1 的纹理,包含当前帧的曝光值、log(亮度) 和场景平均亮度。自动曝光值是可选的,如果创建 FfxFsr3UpscalerContext 时,在 FfxFsr3UpscalerContextDescription 结构体的 flags 字段中没有设置 FFX_FSR3UPSCALER_ENABLE_AUTO_EXPOSURE 标志,则可以省略。
膨胀运动矢量当前帧渲染R16G16_FLOAT纹理一个包含膨胀游戏运动矢量的纹理。
重建的上一帧深度当前帧渲染R32_UINT纹理一个包含上一帧估计深度的纹理,从当前深度缓冲区和游戏运动矢量计算得出。
膨胀深度当前帧渲染R32_FLOAT纹理一个包含膨胀深度值的纹理。
着色变化当前帧半分辨率渲染R8_UNORM纹理一个纹理,包含从上一帧到当前帧的亮度变化计算出的当前着色变化因子。
累积上一帧渲染R8_UNORM纹理一个纹理,包含主要基于遮挡解除、着色变化和响应性掩码的累积值。请注意:此纹理是两个纹理数组的一部分。用于输入和输出的数组中的纹理选择每帧都会交换。
T&C 掩码(可选)当前帧渲染单通道纹理一个可选的、由游戏提供的包含 T&C 掩码的纹理。
响应性掩码(可选)当前帧渲染单通道纹理一个可选的、由游戏提供的包含响应性掩码的纹理。

资源输出

下表包含 [准备响应性](#prepare reactivity) 阶段生成或修改的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
膨胀响应性掩码当前帧渲染R8G8B8A8_UNORM纹理一组指示响应性的掩码。
新锁定掩码当前帧演示R8_UNORM纹理一个指示是否对像素执行颜色校正的掩码,可以看作是像素上的一个锁,以阻止校正消除细节。用于输入和输出的数组中的纹理选择每帧都会交换。[准备响应性](#prepare reactivity) 阶段仅更新此资源的一个子集。
累积当前帧渲染R8_UNORM纹理一个包含基于遮挡解除、着色变化和响应性掩码的累积值的纹理。请注意:此纹理是两个纹理数组的一部分。用于输入和输出的数组中的纹理选择每帧都会交换。

描述

准备响应性”阶段有两个目的:

  • 它计算膨胀响应性掩码,该掩码在一个表面中包含最终响应性、遮挡解除掩码、着色变化因子和累积值。此信息用于计算最终的亮度不稳定性,并在累积阶段限制历史记录对最终输出的影响。
  • 它计算新的锁定,以限制颜色校正应用于像素。新的锁定纹理是输出分辨率,以节省累积阶段的 ALU 指令并避免精度问题。

最终响应性是膨胀的 T&C 掩码和运动散度的**最大值**。遮挡解除是通过比较估计的上一帧深度缓冲区中的 2x2 样本与当前深度缓冲区来计算的,并计算一个代表当前样本在上一个帧中被遮挡的**概率**的值。累积因子是从上一帧的累积因子计算得出的,并随着时间的推移而增加。在遮挡解除后的前几帧中,累积会增加当前样本的权重,以加快收敛速度。最终着色变化是膨胀响应性掩码和着色变化掩码的**最大值**。

直观地说,像素锁定是一种防止颜色校正应用于像素的机制。此锁定的净效果是,在“累积”阶段计算最终的超分辨率像素颜色时,将使用更多上一帧的颜色数据。新的锁定纹理包含像素上下文应被锁定的**置信度**。锁定需要每帧应用才能持续存在,这是 FSR 3.1 与先前版本相比的主要变化之一。锁定不再跨多帧持续存在,减少了因锁定激活时间过长而可能产生的拖影。

计算亮度不稳定性

计算亮度不稳定性”阶段计算亮度不稳定性。亮度不稳定性是衡量输入像素的亮度是否会被感知为闪烁的**度量**。如果是这种情况,将在累积阶段**减少颜色钳制**,否则历史记录将始终被钳制为当前亮度,从而导致最终输出图像出现更多闪烁。

此阶段以渲染分辨率运行。

资源输入

下表包含 [计算亮度不稳定性](#compute-luminance instability) 阶段所消耗的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
输入曝光(帧信息)当前帧1x1R32_FLOAT纹理一个包含曝光值的纹理。这可以是“计算亮度金字塔”通道中计算的自动曝光值,也可以是应用程序提供的曝光值。
膨胀响应性掩码当前帧渲染R8G8B8A8_UNORM纹理一个包含膨胀响应性、遮挡解除掩码、着色变化和累积值的纹理。
膨胀速度掩码当前帧渲染R16G16_UNORM纹理一个包含膨胀运动矢量的纹理。
亮度历史掩码上一帧渲染R16G16B16A16_FLOAT纹理一个包含过去 4 帧亮度的纹理。请注意:此纹理是两个纹理数组的一部分。用于输入和输出的数组中的纹理选择每帧都会交换。
亮度当前帧渲染R16_FLOAT纹理一个包含当前帧亮度的纹理。

资源输出

下表包含“计算亮度不稳定性”阶段产生的所有资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
亮度历史当前帧渲染R16G16B16A16_FLOAT纹理一个包含过去 4 帧亮度的纹理。请注意:此纹理是两个纹理数组的一部分。用于输入和输出的数组中的纹理选择每帧都会交换。
亮度不稳定性当前帧渲染R16_FLOAT纹理一个纹理,包含有关 2-4 帧前的亮度是否比上一帧的亮度更接近当前亮度的**信息**。

描述

计算亮度不稳定性”阶段通过将当前亮度与过去 4 帧的亮度历史进行比较来计算亮度不稳定性因子。它还重投影过去 3 帧的亮度历史,并应用当前曝光值。此阶段还考虑了高速度、遮挡解除、强响应性掩码或强着色变化的情况,会忽略亮度不稳定性,因为在这种情况下,历史记录不被认为是可信的,因此不应影响颜色钳制。

累积

此“累积”阶段执行以下步骤:

  1. 使用 Lanczos 滤波对当前帧的颜色缓冲区进行上采样。
  2. 重投影上一帧的输出颜色和锁定状态缓冲区,就好像它们是从当前摄像机的视角观看一样。
  3. 对历史颜色数据进行各种清理步骤。
  4. 累积历史颜色数据和当前帧的上采样颜色数据。

此阶段以呈现分辨率运行。

资源输入

下表包含“累积”阶段所需的所有资源。

时间层指示应从哪一帧获取数据。“当前帧”表示数据应从为下一帧要呈现的资源中获取。“上一帧”表示数据应从为已呈现的帧创建的资源中获取。分辨率列表示数据应是“渲染”分辨率还是“呈现”分辨率。“渲染”分辨率表示资源应与应用程序执行渲染的分辨率相匹配。相反,“呈现”表示目标的分辨率应与将显示给用户的分辨率相匹配。如果提供了显示分辨率运动矢量,重投影步骤将使用矢量的完整精度,因为我们直接读取资源。

名称时间层分辨率格式类型说明
曝光当前帧1x1R32_FLOAT纹理一个 1x1 的纹理,包含为当前帧计算的曝光值。此资源包含应用程序提供的曝光值或在“计算亮度金字塔”阶段计算的自动曝光值。
扩张的运动向量当前帧渲染R16G16_FLOAT纹理一个包含从应用程序的速度缓冲区计算出的膨胀运动矢量的纹理。红色和绿色通道包含 UV 空间中的二维运动矢量。
膨胀响应性掩码当前帧渲染R8G8B8A8_UNORM纹理膨胀响应性掩码。
内部上采样缓冲区上一帧演示R16G16B16A16_FLOAT纹理上一帧 FSR 算法运行产生的输出缓冲区。请注意:此缓冲区由 FSR 内部使用,并且与从输出缓冲区派生的呈现缓冲区不同,后者应用了 RCAS。此外,此纹理是两个纹理数组的一部分,另一个是“累积”阶段生成的输出缓冲区纹理。用于输入和输出的数组中的纹理选择每帧都会交换。
最远深度 mip1当前帧半分辨率渲染R16_FLOAT纹理当前帧深度信息的保守半分辨率版本。
亮度不稳定性当前帧渲染R16_FLOAT纹理一个纹理,包含过去 4 帧的亮度不稳定性。
颜色缓冲区当前帧渲染应用程序指定纹理一个包含应用程序颜色缓冲区的纹理。
新锁定掩码当前帧演示R8_UNORM纹理一个输出分辨率的掩码,指示是否对像素执行颜色校正,可以看作是像素上的一个锁,以阻止校正消除细节。请注意:此纹理作为 UAV 绑定,因为此通道在累积阶段读取该纹理后会清除其内容。

资源输出

此表包含“累积”阶段产生的资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
内部上采样缓冲区当前帧演示R16G16B16A16_FLOAT纹理用于下一帧历史记录的内部上采样缓冲区版本。它包含 RGB 格式的输出颜色以及 Alpha 通道中的当前锁定。请注意:此缓冲区由 FSR 内部使用,并且与此阶段应用 RCAS 后产生的呈现缓冲区不同。此外,此纹理是两个纹理数组的一部分,另一个是“累积”阶段消耗的输出缓冲区纹理。用于输入和输出的数组中的纹理选择每帧都会交换。
新锁定掩码下一帧演示R8_UNORM纹理为下一帧清除。
上采样缓冲区当前帧演示R16G16B16A16_FLOAT纹理累积”阶段为当前帧生成的输出缓冲区。只有当 RCAS 未启用时,“累积”阶段才会写入此缓冲区。

描述

FSR 的“累积”阶段是算法中最复杂和最昂贵的阶段。它汇集了先前算法步骤的结果,并将上一帧的重投影颜色数据与当前帧的上采样颜色数据累积起来。

累积”阶段的第一步是评估每个像素的着色变化。如果我们处于锁定区域,则将创建锁定时的亮度与 FSR 的着色变化阈值进行比较。在非锁定区域,将使用当前帧和历史亮度值来确定此项。着色变化确定是 FSR “累积”阶段的关键部分,并为该阶段的许多其他部分提供输入。

alt text

接下来,我们必须对调整后的颜色进行上采样。为了执行上采样,调整后的颜色的像素位置被用作 Lanczos 重采样核 5x5 的中心 [Lanczos]。在上图的示意图中,您可以看到 Lanczos 函数以显示分辨率样本 S 为中心。每个像素中的点 - 标记为 P - 表示我们计算 Lanczos 权重的渲染分辨率抖动样本位置。查看 5x5 像素邻域的上方和右侧,您可以看到 Lanczos(x, 2) 重采样核应用于围绕像素位置的 5x5 像素网格中的渲染分辨率样本。值得注意的是,尽管概念上邻域是 5x5,但在实现中,由于外围像素的零加权贡献,实际上只采样了 4x4。Lanczos 核的实现可能因 GPU 产品而异。在基于 RDNA2 的产品上,我们使用查找表 (LUT) 来编码 sinc(x) 函数。这有助于在“累积”阶段的 ALU 和内存之间实现更和谐的平衡。由于上采样步骤可以访问 5x5 邻域像素,因此从效率的角度来看,在此处计算 YCoCg 边界框(在颜色校正期间使用)是有意义的。下图显示了一个 2D YCo 边界框,它由当前像素周围的 3x3 邻域构成,实际上边界框还有一个用于 Cg 的第三个维度。

alt text

重投影是“累积”阶段的另一个关键部分。为了执行重投影,将采样由“累积”阶段生成的膨胀运动矢量,然后将其应用于 FSR 上一帧执行的输出缓冲区。下图的左侧显示了二维运动矢量 **M** 应用于当前像素位置。右侧,您可以看到 Lanczos(x, 2) 重采样核应用于翻译后的像素位置周围的 5x5 像素网格。与上采样步骤一样,Lanczos 核的实现可能因 GPU 产品而异。重投影的结果是一个呈现分辨率图像,其中包含上一帧可以映射到当前帧的所有数据。但是,重投影的不仅仅是上一帧的输出颜色。由于 FSR 依赖于一种机制,即每个像素都可以被锁定以增强其时间稳定性,因此锁定也必须从上一帧重投影到当前帧。这与颜色数据的重投影方式类似,但也结合了我们在当前和历史亮度值上执行的着色变化检测结果。

alt text

在应用了我们的锁定更新并确定了其可信度后,我们可以进入颜色校正,这是 FSR “累积”阶段的下一个关键步骤。在此阶段,将根据像素的历史数据确定最终颜色,然后将其与当前帧的上采样颜色混合,以形成最终累积的超分辨率颜色。最终历史颜色及其贡献的确定主要由两件事控制:

  1. 减少遮挡区域历史样本的影响。这通过用遮挡解除掩码调制颜色值来完成。
  2. 减少历史样本(在下图的 Sh 中标记)远离当前帧颜色边界框(在“累积”阶段的上采样阶段计算)的影响。

alt text

累积”阶段的最后一步是将当前帧的上采样颜色与校正后的历史颜色数据累积起来。默认情况下,FSR 通常会以相对较低的线性插值因子混合当前帧,这意味着最终输出中包含的当前帧相对较少。然而,这可以根据应用程序提供的响应性掩码的内容进行更改。有关详细信息,请参阅响应性掩码部分。

鲁棒对比度自适应锐化 (RCAS)

鲁棒对比度自适应锐化 (RCAS) 最初在 FidelityFX Super Resolution 1.0 中引入,作为额外的锐化通道,以帮助生成最终上采样图像的额外清晰度和锐度。RCAS 是流行的对比度自适应锐化 (CAS) 算法的衍生,但有一些关键区别使其更适合上采样。CAS 使用简化的机制将局部对比度转换为可变锐度,而 RCAS 使用更精确的机制,在钳制之前求解可能的最大局部锐度。此外,RCAS 还内置了一个过程来限制对它检测到的可能噪声的锐化。CAS 中包含的一些缩放功能不包含在 RCAS 中,因此它应该以呈现分辨率运行。

资源输入

此表包含鲁棒对比度自适应锐化 (RCAS) 阶段所需的资源。

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
内部上采样缓冲区当前帧演示R16G16B16A16_FLOAT纹理累积”阶段为当前帧生成的输出缓冲区。请注意:此缓冲区由 FSR 内部使用,并且与此阶段应用 RCAS 后产生的呈现缓冲区不同。请注意:此纹理是两个纹理数组的一部分,另一个是“累积”阶段消耗的输出缓冲区纹理。用于输入和输出的数组中的纹理选择每帧都会交换。

资源输出

时间层表示数据应来自哪个帧。“当前帧”表示数据应来自为下一帧要显示的帧创建的资源。“上一帧”表示数据应来自为刚刚显示的帧创建的资源。分辨率列表示数据应为“渲染”分辨率还是“显示”分辨率。“渲染”分辨率表示资源应与应用程序进行渲染的分辨率匹配。反之,“显示”表示目标分辨率应与向用户显示的分辨率匹配。

名称时间层分辨率格式类型说明
呈现缓冲区当前帧演示应用程序特定纹理当前帧完成 FSR 算法产生的呈现缓冲区。

描述

RCAS 在使用十字形图案配置的 5 采样滤波器采样的数据上操作。请参见下图。

alt text

检索样本后,RCAS 选择导致无钳制的“w”,限制“w”,并乘以“sharp”量。上述解决方案在 MSAA 输入时存在问题,因为沿梯度的步长会导致边缘检测问题。为了帮助稳定 RCAS 的结果,它使用最大值和最小值的 4 倍(取决于方程)来代替各个采样点,并从“m”切换到最小值或最大值(取决于侧面),以帮助能量守恒。

调试视图

FFX_FSR3UPSCALER_DISPATCH_DRAW_DEBUG_VIEW 设置在 FfxFsr3UpscalerDispatchDescription 的 flags 属性中时,将执行一个额外的调试输出通道,将内部表面的调试数据渲染到上采样帧上,以便您可以进行调试。

Frame interpolation debug overlay

构建示例

要构建FSR示例,请遵循以下说明:

  1. 安装以下工具

  2. 生成 Visual Studio 解决方案

    终端窗口
    > <installation path>\BuildSamplesSolution.bat

    批处理文件将询问是否应将 SDK 构建为 DLL(如果未提供‘n’,则构建为静态链接库),以及应包含哪些示例。请使用‘1’来构建包含所有示例的解决方案,或提供要包含的示例列表(使用示例对应的编号,数字之间用空格隔开)。

    这将生成一个 build\ 目录,您将在其中找到 SDK 示例的解决方案(FidelityFX SDK Samples.sln)。

  3. 打开解决方案,编译并运行。

局限性

FSR 需要支持类型化 UAV 加载和 R16G16B16A16_UNORM 的 GPU。

版本历史

版本日期
3.0.12023-11-28
3.1.02024-06-05

有关版本的更多详细信息,请参阅变更日志。

参考文献

[Akeley-06] Kurt Akeley 和 Jonathan Su,“Minimum Triangle Separation for Correct Z-Buffer Occlusion”http://www.cs.cmu.edu/afs/cs/academic/class/15869-f11/www/readings/akeley06_triseparation.pdf

[Lanczos] Lanczos 重采样,“Lanczos resampling”https://en.wikipedia.org/wiki/Lanczos_resampling

[Halton] Halton序列,“Halton序列”https://en.wikipedia.org/wiki/Halton_sequence

[YCoCg] YCoCg 色彩空间,https://en.wikipedia.org/wiki/YCoCg

另请参阅

© . This site is unofficial and not affiliated with AMD.