版权所有 (c) 2023 Advanced Micro Devices, Inc. 保留所有权利。
特此免费授予获得本软件和相关文档文件(“软件”)副本的任何人不受限制地使用本软件,包括但不限于使用、复制、修改、合并的权利、发布、分发、再许可和/或销售软件的副本,并允许向其提供软件的人员这样做,但须满足以下条件:上述版权声明和本许可声明应包含在所有副本中或软件的大部分。
本软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、特定用途的适用性和不侵权的保证。在任何情况下,作者或版权持有者均不对因本软件或本软件中的使用或其他交易而产生或与之相关的任何索赔、损害或其他责任负责,无论是合同、侵权行为还是其他行为。软件。
与本机渲染相比,FSR2 使用时间反馈来重建高分辨率图像,同时保持甚至提高图像质量。
FSR2 可以为昂贵的渲染操作(例如硬件光线追踪)提供“实用性能”。
HLSL
CS_6_2
CS_6_6*
* - CS_6_6 用于某些支持 64 宽波前的硬件。
要使用 FSR2,您应该按照以下步骤操作:
双击build
目录中的GenerateSolutions.bat
。
打开与您的 API 匹配的解决方案,并构建该解决方案。
将 API 库从bin/ffx_fsr2_api
复制到项目中包含第三方库的文件夹的文件夹中。
复制与您要使用的 FSR2 后端匹配的库,例如: bin/ffx_fsr2_api/ffx_fsr2_api_dx12_x64.lib
for DirectX12。
将以下核心 API 头文件从 src/ffx-fsr2-api 复制到您的项目中: ffx_fsr2.h
、 ffx_types.h
、 ffx_error.h
、 ffx_fsr2_interface.h
、 ffx_util.h
、 shaders/ffx_fsr2_common.h
和shaders/ffx_fsr2_resources.h
.应注意维护文件复制目的地的相对目录结构。
复制您选择的 API 后端的头文件,例如对于 DirectX12,您将复制dx12/ffx_fsr2_dx12.h
和dx12/shaders/ffx_fsr2_shaders_dx12.h
。应注意维护文件复制目的地的相对目录结构。
将ffx_fsr2.h
头文件包含在您希望与 FSR2 交互的代码库中。
为您的目标 API 创建后端。例如,对于 DirectX12,您应该调用ffxFsr2GetInterfaceDX12
。应分配通过调用ffxFsr2GetScratchMemorySizeDX12
返回的大小的暂存缓冲区,并将指向该缓冲区的指针传递给ffxFsr2GetInterfaceDX12
。
通过调用ffxFsr2ContextCreate
创建 FSR2 上下文。参数结构的填写应与您的应用程序的配置相匹配。有关更多详细信息,请参阅 API 参考文档。
您应该在每个帧调用ffxFsr2ContextDispatch
来启动 FSR2 工作负载。参数结构的填写应与您的应用程序的配置相匹配。有关更多详细信息,请参阅 API 参考文档,并确保以毫秒为单位提供frameTimeDelta
字段。
当您的应用程序终止时(或者您希望因其他原因销毁上下文),您应该调用ffxFsr2ContextDestroy
。调用此函数之前 GPU 应处于空闲状态。
子像素抖动应该应用于应用程序的投影矩阵。这应该在执行应用程序的主渲染时完成。您应该使用ffxFsr2GetJitterOffset
函数来计算精确的抖动偏移。有关更多详细信息,请参阅相机抖动部分。
为了获得最佳的升级质量,强烈建议您根据我们的指南填充反应性蒙版以及透明度和成分蒙版。您还可以使用ffxFsr2ContextGenerateReactiveMask
作为起点。
应用程序应按以下顺序在其用户界面中公开缩放模式:质量、平衡、性能和(可选)超性能。
应用程序还应该公开锐化滑块,以允许最终用户获得额外的质量。
为了方便最终用户,FSR2 API 提供了许多已命名的预设缩放比例。
质量 | 每维缩放因子 |
---|---|
质量 | 1.5倍 |
均衡 | 1.7倍 |
表现 | 2.0倍 |
超高性能 | 3.0倍 |
我们强烈建议应用程序在其用户界面中采用一致的命名和缩放比例。这是为了确保您的应用程序的用户的用户体验是一致的,这些用户可能有使用 FSR2 的其他应用程序的经验。
根据您的目标硬件和操作配置,FSR2 将以不同的性能级别运行。
下表总结了在 DX12 中各种硬件上测得的 FSR2 性能。
目标分辨率 | 质量 | RX 7900 XTX | RX 6950XT | RX 6900XT | RX 6800XT | RX 6800 | RX 6700XT | RX 6650XT | RX 5700XT | RX维加56 | RX 590 |
---|---|---|---|---|---|---|---|---|---|---|---|
3840x2160 | 质量 (1.5x) | 0.7毫秒 | 1.1毫秒 | 1.2毫秒 | 1.2毫秒 | 1.4毫秒 | 2.0毫秒 | 2.8毫秒 | 2.4毫秒 | 4.9毫秒 | 5.4毫秒 |
平衡 (1.7x) | 0.6毫秒 | 1.0毫秒 | 1.0毫秒 | 1.1毫秒 | 1.4毫秒 | 1.8毫秒 | 2.6毫秒 | 2.2毫秒 | 4.1毫秒 | 4.9毫秒 | |
性能 (2x) | 0.6毫秒 | 0.9毫秒 | 1.0毫秒 | 1.0毫秒 | 1.3毫秒 | 1.7毫秒 | 2.3毫秒 | 2.0毫秒 | 3.6毫秒 | 4.4毫秒 | |
超性能。 (3x) | 0.5毫秒 | 0.8毫秒 | 0.8毫秒 | 0.9毫秒 | 1.1毫秒 | 1.5毫秒 | 1.8毫秒 | 1.7毫秒 | 2.9毫秒 | 3.7毫秒 | |
2560x1440 | 质量 (1.5x) | 0.3毫秒 | 0.5毫秒 | 0.5毫秒 | 0.5毫秒 | 0.7毫秒 | 0.9毫秒 | 1.2毫秒 | 1.1毫秒 | 1.9毫秒 | 2.3毫秒 |
平衡 (1.7x) | 0.3毫秒 | 0.5毫秒 | 0.5毫秒 | 0.5毫秒 | 0.6毫秒 | 0.8毫秒 | 1.1毫秒 | 1.0毫秒 | 1.7毫秒 | 2.1毫秒 | |
性能 (2x) | 0.3毫秒 | 0.4毫秒 | 0.4毫秒 | 0.4毫秒 | 0.6毫秒 | 0.8毫秒 | 0.9毫秒 | 0.9毫秒 | 1.5毫秒 | 1.9毫秒 | |
超性能。 (3x) | 0.2毫秒 | 0.4毫秒 | 0.4毫秒 | 0.4毫秒 | 0.5毫秒 | 0.7毫秒 | 0.8毫秒 | 0.8毫秒 | 1.2毫秒 | 1.7毫秒 | |
1920x1080 | 质量 (1.5x) | 0.2毫秒 | 0.3毫秒 | 0.3毫秒 | 0.3毫秒 | 0.4毫秒 | 0.5毫秒 | 0.6毫秒 | 0.6毫秒 | 1.0毫秒 | 1.3毫秒 |
平衡 (1.7x) | 0.2毫秒 | 0.3毫秒 | 0.3毫秒 | 0.3毫秒 | 0.4毫秒 | 0.5毫秒 | 0.6毫秒 | 0.6毫秒 | 0.9毫秒 | 1.2毫秒 | |
性能 (2x) | 0.2毫秒 | 0.2毫秒 | 0.2毫秒 | 0.3毫秒 | 0.3毫秒 | 0.5毫秒 | 0.5毫秒 | 0.5毫秒 | 0.8毫秒 | 1.1毫秒 | |
超性能。 (3x) | 0.1毫秒 | 0.2毫秒 | 0.2毫秒 | 0.2毫秒 | 0.3毫秒 | 0.4毫秒 | 0.4毫秒 | 0.4毫秒 | 0.7毫秒 | 0.9毫秒 |
数字四舍五入到最接近的 0.1 毫秒,没有额外的sharpness
,并且可能会发生变化。
使用 FSR2 需要分配一些额外的 GPU 本地内存以供 GPU 使用。使用 FSR2 API 时,会在创建 FSR2 上下文时分配此内存,并通过构成后端接口的一系列回调完成分配。该内存用于存储由 FSR2 算法计算的中间表面以及在应用程序的许多帧中持久存在的表面。下表包括 FSR2 在各种操作条件下使用的内存量。 “工作集”列表示算法在 GPU 上执行时 FSR2 使用的内存总量;这是 FSR2 运行所需的内存量。 “持久内存”列指示需要为应用程序的后续帧保留多少“工作集”列;该存储器存储 FSR2 消耗的临时数据。 “可别名内存”列指示有多少“工作集”列可以被 FSR2 操作边界之外的应用程序使用的表面或其他资源别名。
您可以通过覆盖 FSR2 后端接口的资源创建和销毁部分并转发别名标志来控制 FSR2 中的资源创建。这意味着,为了完美集成 FSR2,根据您的操作条件,需要相当于下表“持久内存”列的额外内存。
解决 | 质量 | 工作集 (MB) | 持久内存 (MB) | 可别名内存 (MB) |
---|---|---|---|---|
3840x2160 | 质量 (1.5x) | 448MB | 354MB | 93MB |
平衡 (1.7x) | 407MB | 330MB | 77MB | |
性能 (2x) | 376MB | 312MB | 63MB | |
超高性能 (3x) | 323MB | 281MB | 42MB | |
2560x1440 | 质量 (1.5x) | 207MB | 164MB | 43MB |
平衡 (1.7x) | 189MB | 153MB | 36MB | |
性能 (2x) | 172MB | 143MB | 29MB | |
超高性能 (3x) | 149MB | 130MB | 19MB | |
1920x1080 | 质量 (1.5x) | 115MB | 90MB | 24MB |
平衡 (1.7x) | 105MB | 85MB | 20MB | |
性能 (2x) | 101MB | 83MB | 18MB | |
超高性能 (3x) | 84MB | 72MB | 11MB |
数字为近似值,使用 DX12 中的 RX 6700XT GPU 四舍五入到最接近的 MB,并且可能会发生变化。
有关如何管理 FSR2 内存要求的详细信息,请参阅本文档中有关内存管理的部分。
FSR2 是一种时间算法,因此需要访问当前帧和前一帧的数据。下表列出了 FSR2 所需的所有外部输入。
分辨率列指示数据应采用“渲染”分辨率还是“演示”分辨率。 “渲染”分辨率表示资源应与应用程序执行渲染时的分辨率相匹配。相反,“呈现”表示目标的分辨率应与要呈现给用户的分辨率相匹配。所有资源均来自当前渲染帧,对于 DirectX(R)12 和 Vulkan(R) 应用程序,所有输入资源应在调用
ffxFsr2ContextDispatch
之前分别转换为D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE
和VK_ACCESS_SHADER_READ_BIT
。
姓名 | 解决 | 格式 | 类型 | 笔记 |
---|---|---|---|---|
颜色缓冲区 | 使成为 | APPLICATION SPECIFIED | 质地 | 应用程序提供的当前帧的渲染分辨率颜色缓冲区。如果颜色缓冲区的内容处于高动态范围 (HDR) 中,则应在FfxFsr2ContextDescription 结构的flags 字段中设置FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE 标志。 |
深度缓冲区 | 使成为 | APPLICATION SPECIFIED (1x FLOAT) | 质地 | 应用程序提供的当前帧的渲染分辨率深度缓冲区。数据应作为单个浮点值提供,其精度由应用程序控制。创建FfxFsr2Context 时,深度的配置应通过FfxFsr2ContextDescription 结构的flags 字段传达给 FSR2。如果深度缓冲区反转(即 [1..0] 范围),则应设置FFX_FSR2_ENABLE_DEPTH_INVERTED 标志;如果深度缓冲区具有无限远平面,则应设置FFX_FSR2_ENABLE_DEPTH_INFINITE 标志。如果应用程序提供D32S8 格式的深度缓冲区,则 FSR2 将忽略缓冲区的模板组件,并创建R32_FLOAT 资源来寻址深度缓冲区。在 GCN 和 RDNA 硬件上,深度缓冲区与模板缓冲区分开存储。 |
运动矢量 | 渲染或演示 | APPLICATION SPECIFIED (2x FLOAT) | 质地 | 应用程序提供的当前帧的 2D 运动矢量在 [ (<-width, -height> .. <width, height> ] 范围内。如果您的应用程序渲染具有不同范围的motionVectorScale 矢量,您可以使用FfxFsr2DispatchDescription 结构来调整它们以匹配 FSR2 的预期范围。在内部,FSR2 在许多情况下使用 16 位量来表示运动向量,这意味着虽然运动向量可以具有更高的精度。如果提供,FSR2 将不会受益于增加的精度,除非在创建FfxFsr2Context 时在FfxFsr2ContextDescription 结构的flags 字段中设置了FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS 标志,在这种情况下应等于演示分辨率。 |
反应性面膜 | 使成为 | R8_UNORM | 质地 | 由于渲染图像的某些区域不会在深度缓冲区中留下足迹或包含运动矢量,因此 FSR2 提供了对反应性掩模纹理的支持,该纹理可用于向 FSR2 指示这些区域的位置。很好的例子是粒子或不写入深度或运动矢量的 alpha 混合对象。如果未设置此资源,则 FSR2 的着色变化检测逻辑将尽力处理这些情况,但为了获得最佳结果,应设置此资源。有关反应性面膜的更多信息,请参阅反应性面膜部分。 |
接触 | 1x1 | R32_FLOAT | 质地 | 包含为当前帧计算的曝光值的 1x1 纹理。此资源是可选的,如果在创建FfxFsr2Context 时在FfxFsr2ContextDescription 结构的flags 字段中设置了FFX_FSR2_ENABLE_AUTO_EXPOSURE 标志,则可以省略该资源。 |
以渲染分辨率提供的所有输入(运动矢量除外)都应使用抖动进行渲染。运动矢量不应应用抖动,除非存在FFX_FSR2_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION
标志。
强烈建议将反向无限深度缓冲区与 FSR2 一起使用。但是,支持替代深度缓冲区配置。应用程序应通过在创建FfxFsr2Context
期间设置适当的标志来通知 FSR2 API 其深度缓冲区配置。下表包含适当的标志。
FSR2 标志 | 笔记 |
---|---|
FFX_FSR2_ENABLE_DEPTH_INVERTED | 指示所提供的输入深度缓冲区数据被反转的位[max..0]。 |
FFX_FSR2_ENABLE_DEPTH_INFINITE | 指示所提供的输入深度缓冲区数据正在使用无限远平面的位。 |
时间算法(无论是抗锯齿还是放大)的关键部分是提供运动矢量。 FSR2 接受 2D 运动矢量,对从当前帧中的像素到前一帧中同一像素的位置的运动进行编码。 FSR2 期望应用程序在 [ <-width, -height> .. <width, height> ] 范围内提供运动矢量;这与屏幕空间匹配。例如,屏幕左上角的像素的值为 <width, height> 的运动向量将表示从右下角开始穿过输入表面的整个宽度和高度的运动。
如果您的应用程序在另一个空间(例如标准化设备坐标空间)中计算运动向量,那么您可以使用FfxFsr2DispatchDescription
结构的motionVectorScale
字段来指示 FSR2 调整它们以匹配 FSR2 的预期范围。下面的代码示例说明了如何将运动矢量缩放到屏幕空间。下面的示例 HLSL 和 C++ 代码说明了如何使用 FSR2 主机 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;
在内部,FSR2 在许多情况下使用 16 位量来表示运动矢量,这意味着虽然可以提供更高精度的运动矢量,但 FSR2 目前不会从提高的精度中受益。运动矢量缓冲区的分辨率应等于渲染分辨率,除非在创建FfxFsr2Context
时在FfxFsr2ContextDescription
结构的flags
字段中设置了FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS
标志,在这种情况下,它应等于呈现分辨率。
当更多对象提供其运动矢量时,FSR2 将执行更好的质量升级。因此,建议所有不透明、经过 alpha 测试和 alpha 混合的对象都应为所有覆盖的像素写入其运动向量。如果应用顶点着色器效果(例如滚动 UV),这些计算也应考虑到运动计算中以获得最佳结果。对于 alpha 混合对象,强烈建议将每个覆盖像素的 alpha 值存储到反应掩模中的相应像素。这将使 FSR2 在放大过程中更好地处理 alpha 混合对象。反应掩模对于 alpha 混合对象尤其重要,因为在这些对象中写入运动向量可能会被禁止,例如粒子。
在 FSR2 的上下文中,术语“反应性”是指为当前帧渲染的样本对最终放大图像的产生有多大影响。通常,为当前帧渲染的样本对 FSR2 计算的结果贡献相对较小的量;然而,也有例外。为了为快速移动的 alpha 混合对象产生最佳结果,FSR2 需要重新投影和累积阶段,以便对此类像素更具反应性。由于没有好的方法可以根据颜色、深度或运动矢量确定哪些像素是使用 Alpha 混合渲染的,因此当应用程序明确标记此类区域时,FSR2 的性能最佳。
因此,强烈鼓励应用程序为 FSR2 提供反应掩码。反应掩模指导 FSR2 在合成当前像素时应减少对历史信息的依赖,并允许当前帧的样本对最终结果做出更多贡献。反应性掩码允许应用程序提供 [0.0..1.0] 中的值,其中 0.0 表示像素完全不反应(并且应使用默认的 FSR2 合成策略),值 1.0 表示像素应完全反应反应性的。这是一个浮点范围,可以根据不同的情况进行定制。
虽然反应掩模还有其他应用,但反应掩模的主要应用是产生更好的放大图像(包括 alpha 混合对象)的结果。反应性的一个很好的代理实际上是在将 alpha 混合对象合成到场景中时使用的 alpha 值,因此,应用程序应该将alpha
写入反应性蒙版。应该注意的是,接近 1 的无功值不太可能产生良好的结果。因此,我们建议将最大无功值限制在 0.9 左右。
如果未向 FSR2 提供反应性掩码(通过将FfxFsr2DispatchDescription
的reactive
字段设置为NULL
),则将使用内部生成的具有清除反应性值的 1x1 纹理。
为了帮助应用程序生成反应性蒙版以及透明度和合成蒙版,FSR2 提供了可选的帮助程序 API。在底层,API 启动一个计算着色器,它使用基于亮度的启发式方法计算每个像素的这些值。
希望执行此操作的应用程序可以调用ffxFsr2ContextGenerateReactiveMask
函数,并且应该传递两个版本的颜色缓冲区,一个仅包含不透明几何体,另一个包含不透明和 alpha 混合对象。
除了反应遮罩之外,FSR2 还允许应用程序表示在放大过程中应考虑的其他专业渲染区域。这种特殊渲染的示例包括光线追踪反射或动画纹理的区域。
反应性蒙版调整累积平衡,而透明度和合成蒙版则调整像素历史保护机制。该掩模还消除了亮度不稳定因素的影响。透明度和合成蒙版中值为 0 的像素不会对该像素的锁定执行任何其他修改。相反,值 1 表示应该完全删除对该像素的锁定。
如果未向 FSR2 提供透明度和合成蒙版(通过将FfxFsr2DispatchDescription
的transparencyAndComposition
字段设置为NULL
),则将使用内部生成的具有清除透明度和合成值的 1x1 纹理。
FSR2.2 包括自动生成反应掩模和透明度和合成掩模的实验功能。要启用此功能,需要将FfxFsr2DispatchDescription
的enableAutoReactive
字段设置为“TRUE”,并且需要在“colorOpaqueOnly”中提供后台缓冲区的仅不透明部分的副本。然后,FSR2 将在内部自动生成并使用 Reactive mask 和 Transparency & Composition mask。通过分析具有和不具有透明几何体的颜色缓冲区的差异,并将其与前一帧进行比较,在计算过程中生成蒙版。根据这些计算的结果,每个像素都会分配到反应掩模以及透明度和合成掩模值。要使用遮罩的自动生成,还需要提供以下 4 个值来缩放和限制遮罩的强度(请注意,提到的默认值是建议的起始值,但应根据标题进行调整):
此功能旨在帮助将 FSR2.2 集成到新引擎或游戏中。但是,为了获得最佳质量,我们仍然建议您自己渲染反应性蒙版以及透明度和合成蒙版,因为基于材质生成这些值预计比从最终图像自动生成它们更可靠。
请注意,此功能仍处于实验阶段,将来可能会发生重大变化。
FSR2 提供两个值来控制执行放大时使用的曝光。它们如下:
曝光值应与应用程序执行的任何后续色调映射过程中使用的曝光值相匹配。这意味着 FSR2 的运行方式将与最终色调映射图像中可能可见的内容一致。
在本文档中描述的 FSR2 算法的各个阶段,FSR2 将计算自己的曝光值以供内部使用。值得注意的是,在写入最终输出之前,FSR2 的所有输出都会反转此内部色调映射。这意味着 FSR2 返回与原始输入信号相同域的结果。
选择不当的曝光值可能会对 FSR2 升级的最终质量产生巨大影响。因此,建议应用程序使用FFX_FSR2_ENABLE_AUTO_EXPOSURE
,除非有特殊原因不这样做。当在FfxFsr2ContextDescription
结构的flags
字段中设置FFX_FSR2_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;
}
FSR2 的主要目标是通过使用依赖于大量输入的时间放大算法来提高应用程序渲染性能。因此,它在管道中的放置对于确保最高质量的视觉质量和出色的性能之间的正确平衡至关重要。
对于任何图像放大方法,了解如何相对于放大算法放置其他图像空间算法都很重要。在放大之前放置这些其他图像空间效果的优点是它们以较低的分辨率运行,这当然会给应用程序带来性能优势。然而,它可能不适合某些类别的图像空间技术。例如,许多应用程序可能会在最终图像中引入噪声或颗粒,也许是为了模拟物理相机。在放大器之前执行此操作可能会导致放大器放大噪声,从而在生成的放大图像中产生不希望的伪影。下表将常见的实时图像空间技术分为两列。 “后处理 A”包含通常在 FSR2 升级之前运行的所有技术,这意味着它们都将以渲染分辨率运行。相反,“后处理 B”列包含建议在 FSR2 之后运行的所有技术,这意味着它们将以更大的演示分辨率运行。
后处理A | 后处理B |
---|---|
屏幕空间反射 | 胶片颗粒 |
屏幕空间环境光遮挡 | 色差 |
降噪器(阴影、反射) | 小插图 |
曝光(可选) | 色调映射 |
盛开 | |
景深 | |
运动模糊 |
请注意,此处的建议仅供参考,具体取决于您的应用程序实施的具体特征。
虽然可以生成适当的中间资源、编译着色器代码、设置绑定并提交调度,但使用提供的 FSR2 主机 API 要容易得多。
要使用 API,您应该链接 FSR2 库(稍后会详细介绍哪些库)并包含ffx_fsr2.h
头文件,该文件又具有以下头依赖项:
ffx_assert.h
ffx_error.h
ffx_fsr2_interface.h
ffx_types.h
ffx_util.h
要使用 FSR2 API,您应该链接ffx_fsr2_api_x64.lib
,它将提供面向应用程序的 API 的符号。然而,FSR2 的 API 具有模块化后端,这意味着可以通过使用匹配的后端来针对不同的图形 API 和平台。因此,您应该进一步包含符合您要求的后端库,请参考下表。
目标 | 图书馆名称 |
---|---|
DirectX(R)12 | ffx_fsr2_dx12_x64.lib |
伏尔甘(R) | ffx_fsr2_vk_x64.lib |
请注意,FSR2 API 的模块化架构允许实现自定义后端。有关更多详细信息,请参阅模块化后端部分。
要开始使用 API,应用程序应首先创建一个FfxFsr2Context
结构。这个结构应该位于某个地方,其生命周期大约与您的后缓冲区的生命周期相匹配;应用程序堆上的某个位置通常是一个不错的选择。通过调用ffxFsr2ContextCreate
FfxFsr2Context
结构将填充所需的数据。此外,将从ffxFsr2ContextCreate
到后端进行大量调用,该后端作为FfxFsr2ContextDescription
结构的一部分提供给FfxFsr2Context
。这些调用将执行创建 FSR2 所需的中间资源以及设置着色器及其关联的管道状态等任务。 FSR2 API 不执行任何动态内存分配。
需要升级的应用程序的每个框架,您应该调用ffxFsr2ContextDispatch
。此函数接受在应用程序生命周期早期创建的FfxFsr2Context
结构以及应如何执行升级以及对哪些数据执行升级的精确描述。此描述由填写FfxFsr2DispatchDescription
结构的应用程序提供。
销毁上下文是通过调用ffxFsr2ContextDestroy
来执行的。请注意,在尝试调用ffxFsr2ContextDestroy
之前,GPU 应处于空闲状态,并且该函数不会执行隐式同步以确保 FSR2 正在访问的资源当前不在飞行中。这种选择的原因是避免 FSR2 为那些在可能希望销毁FfxFsr2Context
时已经执行了足够同步的应用程序引入额外的 GPU 刷新,这允许应用程序在以下情况下执行 FSR2 API 的最有效的创建和拆卸:必需的。
还有其他辅助函数作为 FSR2 API 的一部分提供。这些辅助函数执行的任务包括计算子像素抖动偏移,以及基于调度分辨率和 FSR2 提供的默认缩放模式计算渲染分辨率。
有关 FSR2 API 的更详尽文档,您可以参考提供的 API 参考文档。
FSR2 API 的设计意味着 FSR2 算法的核心实现不知道它位于哪个渲染 API 上。相反,FSR2 调用通过接口提供给它的函数,从而允许 FSR2 使用不同的后端。这种设计还允许集成 FSR2 的应用程序提供自己的后端实现,这意味着 FSR2 目前不支持的平台可能会通过实现一些功能而成为目标。此外,拥有自己的渲染抽象的应用程序还可以实现自己的后端,控制FSR2底层功能的各个方面,包括内存管理、资源创建、着色器编译、着色器资源绑定以及将FSR2工作负载提交到图形设备。
在核心 API 和后端之间已经概述的分离之后,FSR2 API 开箱即用,将编译成多个库。这意味着如果您希望使用 FSR2 提供的后端,您应该链接核心 FSR2 API 库以及符合您要求的后端。
FSR2 的公开版本附带 DirectX(R)12 和 Vulkan(R) 后端,但也可根据要求提供其他后端。请与您的 AMD 开发技术代表联系以获取更多信息。
如果 FSR2 API 与提供的后端之一(例如:DirectX(R)12 或 Vulkan(R))一起使用,则直接使用主机应用程序提供的图形设备将 FSR2 所需的所有资源创建为提交资源。然而,通过覆盖后端接口中存在的创建和销毁函数系列,应用程序可以更精确地控制 FSR2 的内存管理。
为此,您可以通过传递给ffxFsr2ContextCreate
函数的FfxFsr2ContextDescription
结构向 FSR2 提供完整的自定义后端,也可以检索所需 API 的后端并覆盖资源创建和销毁函数以自行处理它们。为此,只需覆盖fpCreateResource
和fpDestroyResource
函数指针即可。
// Setup DX12 interface.
const size_t scratchBufferSize = ffxFsr2GetScratchMemorySizeDX12();
void * scratchBuffer = malloc(scratchBufferSize);
FfxErrorCode errorCode = ffxFsr2GetInterfaceDX12(&contextDescription.callbacks, m_pDevice-> GetDevice (), scratchBuffer, scratchBufferSize);
FFX_ASSERT (errorCode == FFX_OK);
// Override the resource creation and destruction.
contextDescription.callbacks.createResource = myCreateResource;
contextDescription.callbacks.destroyResource = myDestroyResource;
// Set up the context description.
contextDescription.device = ffxGetDeviceDX12(m_pDevice-> GetDevice ());
contextDescription.maxRenderSize.width = renderWidth;
contextDescription.maxRenderSize.height = renderHeight;
contextDescription.displaySize.width = displayWidth;
contextDescription.displaySize.height = displayHeight;
contextDescription.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE
| FFX_FSR2_ENABLE_DEPTH_INVERTED
| FFX_FSR2_ENABLE_AUTO_EXPOSURE;
// Create the FSR2 context.
errorCode = ffxFsr2ContextCreate(&context, &contextDescription);
FFX_ASSERT (errorCode == FFX_OK);
对于控制 FSR2 所需的内存管理的应用程序来说,一个有趣的优点是可以执行资源别名,这可以节省内存。内存要求中的表格展示了通过使用此技术可以节省的成本。为了实现此表中所示的节省,应该找到一个适当的内存区域(其中的内容不需要在对 FSR2 调度的调用中保留下来),以便与 FSR2 所需的可别名资源共享。 FSR2 的核心 API 通过 FSR2 后端接口进行的每个FfxFsr2CreateResourceFunc
调用都将包含一组标志,作为FfxCreateResourceDescription
结构的一部分。如果在flags
字段中设置了FFX_RESOURCE_FLAGS_ALIASABLE
,则表示该资源可以安全地与渲染帧中的其他资源建立别名。
时间抗锯齿 (TAA) 是一种使用先前帧的输出从当前帧构建更高质量输出的技术。由于 FSR2 具有类似的目标 - 尽管还有提高渲染图像分辨率的附加目标 - 不再需要在应用程序中包含单独的 TAA 通道。
FSR2 依赖于应用程序在渲染时应用子像素抖动 - 这通常包含在相机的投影矩阵中。为了简化相机抖动的应用,FSR2 API 提供了一小组实用函数,用于计算一系列单独抖动偏移中特定帧的子像素抖动偏移。
int32_t ffxFsr2GetJitterPhaseCount ( int32_t renderWidth, int32_t displayWidth);
FfxErrorCode ffxFsr2GetJitterOffset ( float * outX, float * outY, int32_t jitterPhase, int32_t sequenceLength);
在内部,这些函数实现了 Halton[2,3] 序列 [Halton]。 Halton 序列的目标是提供空间上分离的点,覆盖可用空间。
重要的是要了解从ffxFsr2GetJitterOffset
返回的值位于单位像素空间中,为了将其正确地合成到投影矩阵中,我们必须将它们转换为投影偏移。上图显示了单位像素空间和投影空间中的单个像素。下面的代码清单显示了如何正确地将子像素抖动偏移值合成到投影矩阵中。
const int32_t jitterPhaseCount = ffxFsr2GetJitterPhaseCount(renderWidth, displayWidth);
float jitterX = 0 ;
float jitterY = 0 ;
ffxFsr2GetJitterOffset (&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 透明和光线追踪对象。对于光栅化对象,由ffxFsr2GetJitterOffset
函数计算的子像素抖动值可以应用于相机投影矩阵,该矩阵最终用于在顶点着色期间执行变换。对于光线跟踪渲染,子像素抖动应应用于光线的原点 - 通常是相机的位置。
无论您选择使用推荐的ffxFsr2GetJitterOffset
函数还是您自己的序列生成器,您都必须设置FfxFsr2DispatchDescription
结构的jitterOffset
字段,以通知 FSR2 已应用的抖动偏移量,以便渲染每个帧。此外,如果不使用推荐的ffxFsr2GetJitterOffset
函数,应注意抖动序列永远不会生成空向量;即 X 和 Y 维度上的值均为 0。
下表显示了每种默认质量模式的抖动序列长度。
质量模式 | 比例因子 | 序列长度 |
---|---|---|
质量 | 1.5x(每个维度) | 18 |
均衡 | 1.7x(每个维度) | 23 |
表现 | 2.0x(每个维度) | 32 |
超高性能 | 3.0x(每个维度) | 72 |
风俗 | [1..n]x(每个维度) | ceil(8 * n^2) |
实时渲染的大多数应用都在任何两个连续帧之间具有很大的时间一致性。但是,在某些情况下,对摄像机转换的更改可能会导致渲染内容的突然变化。在这种情况下,FSR2不太可能能够重复使用以前框架积累的任何数据,并且应该清除此数据以将其排除在合成过程中。为了向FSR2表明相机发生了跳转切割,您应该将FfxFsr2DispatchDescription
结构的reset
字段设置为不连续相机转换的第一帧的true
。
使用重置标志时,渲染性能可能比典型的框架操作略低,因为FSR2将清除一些其他内部资源。
应用负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 |
frameTimeDelta
结构提供了FfxFsr2DispatchDescription
API的FSR2 API。该值以毫秒为单位:如果以60fps运行,则通过的值应约为16.6f 。
该值用于FSR 2自动暴露功能的时间分量中。这允许为质量目的调整历史记录积累。
FSR2支持高动态范围图像。要启用此功能,您应该在FfxFsr2ContextDescription
结构的flags
字段中设置FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE
位。图像应在线性颜色空间中提供给FSR2。
FSR2的未来修订版可能会提供对其他颜色空间的支持。
FSR2旨在利用一半的精度(FP16)硬件加速度,以实现最高的性能。但是,为了为应用程序提供最大的兼容性和灵活性,FSR2还包括使用完整的精度(FP32)操作编译着着色器的能力。
建议在支持它的所有硬件上使用FP16版本的FSR2。您可以通过查询Directx(R)12中的D3D12_FEATURE_DATA_SHADER_MIN_PRECISION_SUPPORT
(R)12-您应该检查D3D[11/12]_SHADER_MIN_PRECISION_16_BIT
和FLAFT BEFTED FAFF,您应该查询图形卡对FP16的支持级FSR2。对于Vulkan,如果未设置VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderFloat16
,则您应该后备到FP32版本的FSR2。同样,如果未设置VkPhysicalDevice16BitStorageFeatures::storageBuffer16BitAccess
,则还应该后备到FP32版本的FSR2。
要在FSR2着色器源代码中启用FP32路径,您应该将FFX_HALF
定义为1
。为了在FP16和FP32之间共享该算法的大多数源代码(确保高度的代码共享以支持正在进行的维护),您会注意到FSR2 Shader源代码使用一组类型宏,这有助于在之间轻松切换着色器源中的16位和32位基本类型。
FidelityFX类型 | fp32 | FP16 |
---|---|---|
FFX_MIN16_F | float | min16float |
FFX_MIN16_F2 | float2 | min16float2 |
FFX_MIN16_F3 | float3 | min16float3 |
FFX_MIN16_F4 | float4 | min16float4 |
上表列举了抽象FidelityFX SDK类型之间的映射和固有类型之间的映射,这些类型将根据编译过程中着色器源的配置来代替。
现代GPU以SIMT方式一起执行线程的集合(称为Wavefronts)。构成单个波前的螺纹的精确数量是一个特定于硬件的数量。一些硬件,例如AMD的GCN和基于RDNA的GPU支持,将64个线程聚集到一个波前。根据算法的执行的精确特征,更有优先的波前宽度可能或多或少是有利的。随着着色器型号6.6的引入,Microsoft添加了通过HLSL特定波前宽度的能力。对于硬件,例如支持32和64个宽波前宽度的RDNA,这是一个非常有用的工具,用于优化目的,因为它提供了一种干净可移植的方法,要求驱动器软件堆栈执行具有特定宽度的波兰。
对于基于rDNA和基于rDNA的GPU并使用Microsoft Agility SDK运行的DirectX(R)12个应用程序,FSR2主机API将选择一个64宽的波前宽度。
可以为上下文描述结构提供一个回调函数,以通过FSR 2运行时传递文本警告到基础应用程序。描述的fpMessage
成员是类型FfxFsr2Message
,它是传递各种类型的字符串消息的功能指针。将此变量分配给合适的函数,然后传递FfxFsr2ContextDescription
的标志成员中的FFX_FSR2_ENABLE_DEBUG_CHECKING
FLAG将启用该功能。建议仅在调试开发构建中启用这一点。
当检查员观察可能的问题时可能发生的输出类型的示例如下:
FSR2_API_DEBUG_WARNING: FFX_FSR2_ENABLE_DEPTH_INFINITE and FFX_FSR2_ENABLE_DEPTH_INVERTED present, cameraFar value is very low which may result in depth separation artefacting
FSR2_API_DEBUG_WARNING: frameTimeDelta is less than 1.0f - this value should be milliseconds (~16.6f for 60fps)
FSR2算法在一系列阶段实现,如下:
该算法的每个通过阶段都在此之后的各节中列出,但是完整的FSR2算法的数据流如下图所示。
计算亮度金字塔阶段有两个责任:
下表包含计算亮度金字塔阶段消耗的所有资源。
时间层指示应从哪个框架来源。 “当前框架”意味着应从为接下来要介绍的框架创建的资源中获取数据。 “以前的帧”表明该数据应来自为刚刚呈现的框架创建的资源。分辨率列指示数据是否应为“渲染”分辨率或“表示”分辨率。 “渲染”分辨率表示资源应与应用程序执行其渲染的分辨率匹配。相反,“演示”表明目标的分辨率应匹配要向用户呈现的内容匹配。
姓名 | 时间层 | 解决 | 格式 | 类型 | 笔记 |
---|---|---|---|---|---|
颜色缓冲区 | 当前框架 | 使成为 | APPLICATION SPECIFIED | 质地 | 应用程序提供的当前帧的渲染分辨率颜色缓冲区。如果颜色缓冲区的内容在高动态范围内(HDR),则应在FfxFsr2ContextDescription 结构的FFXFSR2ContextDescription结构的flags 字段中设置FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE 。 |
下表包含通过计算亮度金字塔阶段产生或修改的所有资源。
时间层指示应从哪个框架来源。 “当前框架”意味着应从为接下来要介绍的框架创建的资源中获取数据。 “以前的帧”表明该数据应来自为刚刚呈现的框架创建的资源。分辨率列指示数据是否应为“渲染”分辨率或“表示”分辨率。 “渲染”分辨率表示资源应与应用程序执行其渲染的分辨率匹配。相反,“演示”表明目标的分辨率应匹配要向用户呈现的内容匹配。
姓名 | 时间层 | 解决 | 格式 | 类型 | 笔记 |
---|---|---|---|---|---|
接触 | 当前框架 | 1x1 | R32_FLOAT | 质地 | 1x1纹理,其中包含针对当前帧计算的曝光值。此资源是可选的,如果FFXFSR2ContextDescription在创建FfxFsr2Context 时,在FfxFsr2ContextDescription 结构的flags 字段中设置了FFX_FSR2_ENABLE_AUTO_EXPOSURE FLAG,则可能会省略。 |
当前的亮度 | 当前框架 | Render * 0.5 +麦片链 | R16_FLOAT | 质地 | 渲染分辨率纹理的50%的纹理,其中包含当前框架的亮度。分配完整的MIP链。 |
使用FidelityFX单次降低来实现计算亮度金字塔阶段