DirectX11如何从常量缓冲区中删除未使用的变量?

时间:2014-09-16 01:27:48

标签: c++ directx directx-11

我正在调用D3DReflect()来推断编译着色器使用的常量缓冲区的布局,我注意到它们通常包含未使用的变量。

我已经使用D3DStripShader()去除调试信息,我想知道在调用D3DReflect()之前是否有类似的方法从常量缓冲区中去除那些未使用的变量?


这通常是一种好习惯吗? 因为它意味着大多数时候每个原始cbuffer / stage / program都有一个cbuffer,我不知道剥离未使用变量的好处是否会优于丢失更多(更小)的cbuffers?

1 个答案:

答案 0 :(得分:1)

没有简单的方法可以做到这一点。常量缓冲区的天真视图是每个人都会使用显式结构来保存它们的常量,这些结构将由着色器和调用C ++代码(或C#,无论如何)共享。因此,如果着色器编译器改变了结构的布局,一切都会破坏。

在处理DX示例应用程序时,这在微观视图中是有意义的。对于一个更大的项目,很多人都不这样做。相反,它们具有旧样式着色器,其中常量在全局范围内声明。在DX9和其他类似平台上,常量被映射到寄存器,因此编译器可以去除未使用的常量(并且它确实如此)。对于DX11,编译器会获取所有这些全局常量,并将它们放在一个特殊的" global"恒定缓冲区。然后它决定你真的关心那个缓冲区的结构,所以它拒绝删除任何东西。

因此,通常有两种选择:

  1. 将常量分解为多个常量缓冲区,大致分为一起使用的集合。编译器将剥离一个未使用的整个常量缓冲区,因此您可以使用它来进行粗略剥离。这很费时,你必须维护你的设置分区,但它可能已经足够好了,具体取决于你的情况。

  2. 自己实施持续剥离。这就是我们所做的......在编译了所有着色器之后,我们使用反射API来获取二进制文件中所有常量的列表。该信息包括指示是否使用常量的标志。对于每个使用的常量,我们只需再次声明它,正常情况下。对于未使用的每个常量,我们发出类似的声明,但将变量标记为静态。这具有从任何常量缓冲区中删除它的效果(因为它被着色器编译器视为编译时常量)。然后我们重新编译着色器,新生成的全局常量缓冲区只包含使用过的常量。

  3. 这也是一堆工作(在我们的实现中,我们必须在宏中包装所有常量声明 - 包装器代码构建一个包含所有静态/非静态声明的大字符串,并定义{{1包含该字符串):

    STRIPPED_CONSTANT_DEFINITIONS

    请注意,需要仍然将已剥离的常量声明为静态,因为任何未使用的代码路径或引用这些变量的未调用函数都将导致着色器无法编译,否则。