☰
FidelityFX Blur 1.1 技术详解:Compute Shader 单趟高斯模糊的集成与实现原理(dlssg-to-fsr3 仓库 FidelityFX SDK 依赖篇)
2026/10/4 13:52:11 网站建设 项目流程
  • 图形学
  • 游戏开发

【免费下载链接】dlssg-to-fsr3

Adds AMD FSR 3 Frame Generation to games by replacing Nvidia DLSS Frame Generation (nvngx_dlssg).

项目地址:https://gitcode.com/gh_mirrors/dl/dlssg-to-fsr3
点击查看免费下载

FidelityFX Blur 1.1 是 AMD FidelityFX SDK 中一款基于 Compute Shader 的高性能单趟(single-pass)高斯模糊技术,通过线程组共享内存(LDS)缓存中间结果,将传统两趟可分离高斯模糊合并为一次 compute dispatch 完成。本文以 dependencies/FidelityFX-SDK/docs/techniques/blur.md 为主干,结合当前仓库(gh_mirrors/dl/dlssg-to-fsr3,即 dlssg-to-fsr3 项目中内嵌的 FidelityFX SDK 依赖)中的宿主 API 头文件与 GPU 着色器源码,系统讲解 FfxBlur 的完整集成流程、可自定义回调机制、内核权重/内核尺寸/浮点精度等核心参数,以及"水平模糊缓存 + 垂直模糊输出"三步算法与环形缓冲区共享内存布局。读完本文,你将能够直接把 FidelityFX Blur 集成进自己的渲染管线,或基于自定义 main 函数与回调重写属于自己的模糊计算内核。

一、技术概览与环境要求

FidelityFX Blur 是一款compute-based、高度优化、单趟完成的高斯模糊技术。它在上层 API 层面表现为一个独立的 FfxBlurContext,功能上与标准两趟可分离高斯模糊完全等价,但性能更高——这正是它与其他常规模糊实现的核心差异。

项目要求
HLSLCS_6_0(Compute Shader 6.0)
GLSLversion 450
版本号FFX_BLUR_VERSION_MAJOR 1/MINOR 1/PATCH 0(见 ffx_blur.h)
内部上下文数量FFX_BLUR_CONTEXT_COUNT = 1

宿主头文件 ffx_blur.h 将其描述为"在 compute shader 上实现、针对极致性能手工优化的模糊效果集合",当前包含一种效果:支持最大 21x21 内核的高斯模糊。GPU 侧入口函数为ffxBlurPass(封装于 ffx_blur_blur.h),实际算法主体为ffxBlur(定义于 ffx_blur.h)。

二、C++ SDK 集成指南(宿主侧 API)

使用 FFX SDK C++ API 集成 Blur 是最简单的方式,整体流程分为三步:初始化上下文 → 逐帧执行 Dispatch → 销毁上下文。

2.1 初始化 FfxBlurContext

// Initialize the FFX backend and blur context (do this once) size_t scratchBufferSize = ffxGetScratchMemorySize(FFX_BLUR_CONTEXT_COUNT); void* scratchBuffer = malloc(scratchBufferSize); FfxInterface backendInterface; ffxGetInterface(&backendInterface, GetDevice(), scratchBuffer, scratchBufferSize, FFX_BLUR_CONTEXT_COUNT); FfxBlurContextDescription desc = {}; desc.backendInterface = backendInterface; desc.floatPrecision = FFX_BLUR_FLOAT_PRECISION_32BIT; desc.kernelPermutations = FFX_BLUR_KERNEL_PERMUTATIONS_ALL; // mask to support some Guassian sigma kernels or ALL desc.kernelSizes = FFX_BLUR_KERNEL_SIZE_ALL; // mask to support some kernel sizes or ALL FfxBlurContext blurContext; ffxBlurContextCreate(&blurContext, &desc);

关键点说明:

  • scratch 缓冲:ffxGetScratchMemorySize(FFX_BLUR_CONTEXT_COUNT)返回后端所需 scratch 内存大小,FFX_BLUR_CONTEXT_COUNT为 1(Blur 仅需一个内部效果上下文)。
  • backendInterface:通过ffxGetInterface绑定当前设备的后端实现(DX12 / Vulkan)。
  • 创建/销毁:ffxBlurContextCreate与ffxBlurContextDestroy是上下文生命周期管理的唯二入口,声明见 ffx_blur.h。

2.2 FfxBlurContextDescription 核心参数

依据 ffx_blur.h,上下文描述结构体包含四个字段:

字段类型含义
kernelPermutations位掩码使能的 Gaussian sigma 内核排列(1.6 / 2.8 / 4.0)
kernelSizes位掩码使能的内核尺寸(3x3 … 21x21)
floatPrecision枚举期望的浮点精度(FP32 / FP16)
backendInterface结构体指向 FFX 后端实现的一组函数指针

其中FFX_BLUR_KERNEL_PERMUTATIONS_ALL与FFX_BLUR_KERNEL_SIZE_ALL是"全部使能"的便捷宏:前者为(1 << FFX_BLUR_KERNEL_PERMUTATION_COUNT) - 1(3 种 sigma 全开),后者为(1 << FFX_BLUR_KERNEL_SIZE_COUNT) - 1(10 种内核尺寸全开)。

2.3 逐帧执行:ffxBlurContextDispatch

// Execute blur effect (multiple times) FfxBlurDispatchDescription desc = {}; desc.commandList = ffxGetCommandList(pCmdList); desc.kernelPermutation = FFX_BLUR_KERNEL_PERMUTATION_2; // Guassian sigma (1.6, 2.8, or 4.0) desc.kernelSize = FFX_BLUR_KERNEL_SIZE_15x15; // Kernel sizes (3x3 ... 21x21) desc.input = ffxGetResource(inputResource, L"BLUR_InputSrc", FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ); desc.inputAndOutputSize.width = desc.input.description.width; desc.inputAndOutputSize.height = desc.input.description.height; desc.output = ffxGetResource(outputResource, L"BLUR_Output", FFX_RESOURCE_STATE_UNORDERED_ACCESS); ffxBlurContextDispatch(&blurContext, &desc); // When done using the blur effect, clean up. ffxBlurContextDestroy(&blurContext);

FfxBlurDispatchDescription的完整字段(见 ffx_blur.h):

字段说明
commandList用于记录渲染命令的FfxCommandList
kernelPermutation本次使用的 sigma 排列(必须是 Context 创建时使能的排列之一)
kernelSize本次使用的内核尺寸(必须是 Context 创建时使能的尺寸之一)
inputAndOutputSize输入输出资源的宽高(像素)
input待模糊的输入资源,状态为FFX_RESOURCE_STATE_PIXEL_COMPUTE_READ
output模糊结果输出资源,状态为FFX_RESOURCE_STATE_UNORDERED_ACCESS

2.4 参数取值范围速查(枚举定义)

以下枚举均定义于 ffx_blur.h:

内核排列(sigma 值)——FfxBlurKernelPermutation:

枚举值位含义
FFX_BLUR_KERNEL_PERMUTATION_01<<0sigma = 1.6
FFX_BLUR_KERNEL_PERMUTATION_11<<1sigma = 2.8
FFX_BLUR_KERNEL_PERMUTATION_21<<2sigma = 4.0

内核尺寸——FfxBlurKernelSize(全部为奇数内核,从 3x3 到 21x21,共 10 档):

枚举值位枚举值位
FFX_BLUR_KERNEL_SIZE_3x31<<0FFX_BLUR_KERNEL_SIZE_13x131<<5
FFX_BLUR_KERNEL_SIZE_5x51<<1FFX_BLUR_KERNEL_SIZE_15x151<<6
FFX_BLUR_KERNEL_SIZE_7x71<<2FFX_BLUR_KERNEL_SIZE_17x171<<7
FFX_BLUR_KERNEL_SIZE_9x91<<3FFX_BLUR_KERNEL_SIZE_19x191<<8
FFX_BLUR_KERNEL_SIZE_11x111<<4FFX_BLUR_KERNEL_SIZE_21x211<<9

浮点精度——FfxBlurFloatPrecision:FFX_BLUR_FLOAT_PRECISION_32BIT = 0、FFX_BLUR_FLOAT_PRECISION_16BIT = 1。FP16 变体会在 ffx_blur_callbacks_hlsl.h 中通过FFX_HALF宏选择FfxFloat16类型的 I/O 与内核权重。

三、通过回调与自定义 main 函数定制 Blur

Blur 在 ffx_blur_callbacks_hlsl.h 与 ffx_blur_callbacks_glsl.h 中提供了默认的内核权重与 I/O 函数实现,SDK 使用者可以将其替换,以对接自己的应用资源绑定。

3.1 内核权重回调的重写规则

Blur 要求1D 内核权重在编译时嵌入着色器以获得最大性能,具体要求如下:

  • 函数签名中的权重类型为FfxFloat32或FfxFloat16,由是否启用半精度决定;这两个类型定义于 ffx_core.h;
  • 必须提供一组归一化的高斯权重分布,以静态数组形式定义,元素按递减顺序排列(从中心权重到边缘权重)。

官方示例(5x5 高斯内核覆盖):

#if FFX_HALF #define FFX_BLUR_KERNEL_TYPE FfxFloat16 #else #define FFX_BLUR_KERNEL_TYPE FfxFloat32 #endif inline FFX_BLUR_KERNEL_TYPE GetKernelWeight(int iKernelIndex) { static FFX_BLUR_KERNEL_TYPE kernel_weights[] = { 0.257030201088974, 0.22378581991669, 0.147699079538823 }; // for a 5x5 Gaussian kernel return kernel_weights[iKernelIndex]; } FFX_BLUR_KERNEL_TYPE FfxBlurLoadKernelWeight(FfxInt32 iKernelIndex) { return GetKernelWeight(iKernelIndex); }

从源码层面印证:默认实现 ffx_blur_callbacks_hlsl.h 内嵌了 3 种 sigma(1.6 / 2.8 / 4.0)x 10 种尺寸(FFX_BLUR_KERNEL_RANGE从 2 到 11)的完整权重表,并通过FFX_BLUR_OPTION_KERNEL_PERMUTATION(0/1/2)与FFX_BLUR_OPTION_KERNEL_DIMENSION两个宏在编译期选取具体数组;FFX_BLUR_KERNEL_RANGE = ((FFX_BLUR_OPTION_KERNEL_DIMENSION - 1) / 2) + 1,即"中心 + 半宽"。若未定义FFX_BLUR_OPTION_KERNEL_DIMENSION,编译会直接报错(见 ffx_blur.h),这正是"权重必须编译期确定"的设计体现。

3.2 I/O 回调的重写示例

#if FFX_HALF FfxFloat16x3 FfxBlurLoadInput(FfxInt16x2 inPxCoord) { return texColorInput[inPxCoord].rgb; } void FfxBlurStoreOutput(FfxInt32x2 outPxCoord, FfxFloat16x3 color) { texColorOutput[outPxCoord] = min16float4(color, 1); } #else FfxFloat32x3 FfxBlurLoadInput(FfxInt32x2 inPxCoord) { return texColorInput[inPxCoord].rgb; } void FfxBlurStoreOutput(FfxInt32x2 outPxCoord, FfxFloat32x3 color) { texColorOutput[outPxCoord] = float4(color, 1); } #endif

注意默认实现的资源绑定约定:输入纹理为r_input_src(SRV,FFX_BLUR_BIND_SRV_INPUT_SRC),输出为rw_output(UAV,FFX_BLUR_BIND_UAV_OUTPUT),资源标识符定义见 ffx_blur_resources.h(FFX_BLUR_RESOURCE_IDENTIFIER_INPUT_SRC = 1、FFX_BLUR_RESOURCE_IDENTIFIER_OUTPUT = 2)。重写回调后即可对接自定义纹理名称与格式。

3.3 通过自定义 main 函数集成

除了 C++ 宿主 API,Blur 也支持通过自己的 computemain函数直接集成。核心要求是:必须定义FFX_BLUR_TILE_SIZE_X与FFX_BLUR_TILE_SIZE_Y宏(一般均为 8,源码默认值也如此,见 ffx_blur.h)。

HLSL 入口示例:

#include "blur/ffx_blur_callbacks_hlsl.h" #include "blur/ffx_blur_blur.h" [numthreads(FFX_BLUR_TILE_SIZE_X, FFX_BLUR_TILE_SIZE_Y, 1)] void CS( uint3 LocalThreadId : SV_GroupThreadID, uint3 WorkGroupId : SV_GroupID, uint3 DispatchThreadID : SV_DispatchThreadID) { // Run FidelityFX - Blur ffxBlurPass(int2(DispatchThreadID.xy), int2(LocalThreadId.xy), int2(WorkGroupId.xy)); }

GLSL 入口示例:

#include "blur/ffx_blur_callbacks_glsl.h" #include "blur/ffx_blur_blur.h" layout (local_size_x = FFX_BLUR_TILE_SIZE_X, local_size_y = FFX_BLUR_TILE_SIZE_Y, local_size_z = 1) in; void main() { // Run FidelityFX Blur ffxBlurPass( FfxInt32x2(gl_GlobalInvocationID.xy), FfxInt32x2(gl_LocalInvocationID.xy), FfxInt32x2(gl_WorkGroupID.xy)); }

其中ffxBlurPass会进一步把三个 ID 连同ImageSize()(来自常量缓冲区cbBLUR的imageSize字段)一起传给真正的算法函数ffxBlur。CPU 侧 Dispatch 时 Y 维默认使用FFX_BLUR_DISPATCH_Y = 8,即一个工作组在 Y 方向覆盖 8 个 tile 高度。

四、Under the Hood:三步算法与复杂度分析

4.1 单趟三步骤算法

Blur 采用三步算法,通过线程组共享内存存储中间模糊结果,从而在一次 compute dispatch内完成传统上需要两趟可分离滤波的工作:

  1. Pre-fill(预填充)阶段:从图像源填充缓存,对首批 tile 执行水平模糊;
  2. Loop top-down(自上而下主循环):从图像源填充缓存并做水平模糊 → 基于缓存结果做垂直模糊 → 写入目标资源;
  3. Loop over the last few tiles(尾部收尾循环):仅对最后几个 tile 做垂直模糊并写入目标资源。

4.2 复杂度理论

Dispatch 时间复杂度Wave 执行时间复杂度Group Shared Memory 空间复杂度
O(W * H * K)O(H * K)O(Th * (Tw + K))

其中:

  • W:图像宽度(Image Width)
  • H:图像高度(Image Height)
  • K:1D 内核尺寸(1D Kernel Size)
  • Tw:模糊 tile 宽度(Blur Tile Size X)
  • Th:模糊 tile 高度(Blur Tile Size Y)

从源码注释(ffx_blur.h)可以看到对算法的精确定义:图像在缓存到 LDS 的同时进行水平模糊,当所有 LDS tile 填满后,在 LDS 上执行垂直模糊,结果写入 UAV 作为最终输出。水平模糊的负载量(image_load指令数)会随FFX_BLUR_OPTION_KERNEL_DIMENSION线性增长,这也是大内核(如 21x21)成本的主要来源。

4.3 工作分布(Work Distribution)

Blur 使用8x8 线程组,每个线程组负责图像中的一个 tile(threadgroup 与 tile 一一对应)。工作分布受以下#define影响:

  • FFX_BLUR_TILE_SIZE_X/FFX_BLUR_TILE_SIZE_Y:tile 尺寸,默认 8;
  • FFX_BLUR_DISPATCH_Y:Y 方向 dispatch 维度,默认 8,决定每个工作组纵向覆盖的 tile 数;
  • FFX_BLUR_OPTION_KERNEL_DIMENSION:内核维度,直接决定预填充 tile 数量NUM_PREFILL_TILES_OUTPUT_CACHE = DIV_AND_ROUND_UP(kernel, TILE_SIZE_Y)(例如 3/5/7 内核预填充 1 个 tile,9~15 预填充 2 个,17~21 预填充 3 个,见 ffx_blur.h)。

4.4 共享内存:tile 环形缓冲区

Blur 在共享内存中开辟一块区域作为tile 环形缓冲区(ring buffer)来存放中间结果:

  • 与单个 tile 对应的线程组,先采样源图像并执行水平模糊,把结果写入共享内存;
  • 随后该线程组从共享内存读取中间结果,执行垂直模糊,再把完全模糊后的图像写入目标纹理。

实现层面的优化细节(同样定义于 ffx_blur.h):

  • 环形缓冲 tile 数:NUM_TILES_OUTPUT_CACHE在FFX_BLUR_OPTION_KERNEL_DIMENSION > 7时为 8,否则为 4;
  • 快速取模:借助FAST_MOD(x, y) = x & (y-1)用位与代替取模(要求 tile 数为 2 的幂),降低 ALU 开销;
  • LDS 打包:默认开启BLUR_GROUPSHARED_MEMORY_PK_UINT,将 RG 两通道的 FP16 打包进单个 32 位无符号整数(PackF2/UnpackToF2,见 ffx_blur.h),B 通道单独使用 FP32 以避免 bank conflict;历史遗留选项BLUR_GROUPSHARED_MEMORY_SOA与BLUR_GROUPSHARED_MEMORY_HALF已被标记为 Deprecated;
  • 边界钳制:默认启用clamp(BLUR_DISABLE_CLAMP = 0),图像边缘采样坐标被钳制到[0, ImageSize-1]区间,保证边界像素正确;BLUR_OPTIMIZED_CLAMP为实验性开关。

五、配套示例与调试对照(samples/blur)

仓库同时提供了配套示例文档 dependencies/FidelityFX-SDK/docs/samples/blur.md,该示例(对应 dependencies/FidelityFX-SDK/samples/blur 目录)用于演示与对比单趟高斯模糊相对标准两趟可分离模糊的性能优势,支持 Windows + DirectX 12 与 Vulkan。

示例 UI 提供的可调参数与本文上述 API 参数一一对应:

UI 元素取值控制内容
AlgorithmFidelityFX Blur, Single Pass Filter, Multi-pass Separable Filter, Multi-pass Separable Filter Transpose切换当前使用的算法(FFX Blur / 标准多趟可分离滤波对照)
Gaussian Kernel Sigma1.6, 2.8, 4.0切换生成高斯内核所用的 sigma
Kernel Size3x3, 5x5, ..., 21x21切换模糊内核尺寸
Floating Point MathUse FP32, Use FP16切换 FP32 / FP16 实现
Display the differenceOn/Off开关对比模式
Comparison mode settingsCompare Algorithm, Compare Gaussian Sigma, Compare Kernel Size, Compare FP Math对比模式下对四个维度分别做差
Diff Factor1.0..10.0显示差值时的放大倍数

对比模式的实现逻辑是:把Compare Algorithm下拉框所选算法(连同其 sigma、尺寸、数学精度设置)生成的图像,与Algorithm下拉框所选算法生成的图像相减;由于差异可能极小,Diff Factor滑杆会把差值乘以指定倍数后再显示到屏幕上。该示例是验证本文第 2 节各参数实际效果的最直接工具。

六、进一步阅读与参考资料

  • GDC 2019: A Blend of GCN Optimization & Color Processing,Part I: Store Caching in Separable Filters(本篇文档共享内存环形缓存设计的理论来源,见原文档 Further Reading 一节)
  • GDC 2018: Engine Optimization Hot Lap
  • Rastergrid: Efficient Blur w/ Linear Sampling

仓库内的相关深入材料还包括:FidelityFX SDK 结构说明、FFX API 集成指南,以及 FidelityFX Blur 命名规范;若需在运行时动态切换内核,可参考宿主侧实现 dependencies/FidelityFX-SDK/sdk/src/components/blur/ffx_blur.cpp。

小结

FidelityFX Blur 1.1 的价值在于用一次 compute dispatch 完成传统两趟可分离高斯模糊的全部工作:宿主侧通过ffxBlurContextCreate/ffxBlurContextDispatch/ffxBlurContextDestroy三个 API 即可完整接入;GPU 侧以 8x8 tile 为单位,利用 LDS 环形缓冲区缓存水平模糊结果,配合 2 的幂 tile 数位运算取模、FP16 打包等优化手段压低开销;三种 sigma(1.6/2.8/4.0)与十档内核尺寸(3x3~21x21)通过位掩码灵活组合,FP32/FP16 双精度变体可按需选择。无论你是通过 C++ 宿主 API 快速集成,还是借助回调与自定义 main 函数深度定制,本文给出的参数表与源码路径都能帮助你定位到对应实现。

  • 图形学
  • 游戏开发

【免费下载链接】dlssg-to-fsr3

Adds AMD FSR 3 Frame Generation to games by replacing Nvidia DLSS Frame Generation (nvngx_dlssg).

项目地址:https://gitcode.com/gh_mirrors/dl/dlssg-to-fsr3
点击查看免费下载

相关推荐

上一篇:SilentPatch终极修复指南:让GTA经典三部曲在现代电脑上完美运行
下一篇:OpenCore Legacy Patcher终极指南:3个简单步骤让老Mac免费升级最新macOS

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询