像素着色器中动态常量缓冲区索引的性能



我有一个用HLSL编写的像素着色器,它声明了以下常量缓冲区:

cbuffer RenderParametersData : register(b2) 
{
    float4 LineColor[16];
};

在其中一个着色器函数中,我根据索引"颜色"查找输出颜色(这不是真正的颜色,只是将索引放入LineColors数组的方便位置):

output.Color = Colors[input.Color.b * 255];

这将导致生成的汇编代码中的指令槽数量急剧增加。保持其他所有内容不变,但执行恒定的数组查找- output.Color = LineColor[0]; -算术运算的数量从10增加到37。几乎所有的附加操作都是这样的:

cmp r2, -r1.x, c0, r0.w
cmp r2, -r1.y, c1, r2
cmp r2, -r1.z, c2, r2
cmp r1, -r1.w, c3, r2

其中c增加到15,与LineColor中的元素数量相匹配。将LineColor的大小调整为8个元素导致的代码与第二种情况非常相似,但是c仅为7,再次匹配数组中的元素数量。回到常量查找,操作的数量下降到10。

因此,动态常量缓冲区数组查找似乎会带来相当大的额外成本,为数组中的每个元素添加一条比较指令,再加上一些开销。我真的很惊讶这个数组查找是多么昂贵,并且考虑到我的数组大小很快就会增加一个数量级,这将使我超过64个算术指令的限制。

这是预期的行为吗?是我做错了什么,还是这是动态数组索引的必然结果?

谢谢!

编辑:只是添加一些额外的细节,我之后的效果是根据顶点着色器和纹理坐标的数据给一些四边形上色。我会在顶点着色器中做这项工作,但纹理坐标的插值必须首先发生。

我已经解决了这个问题。我指定到FXC,我的目标是ps_4_0_level_9_1,这导致它生成两个着色器模型2.0和4.0组装。我发现,每个元素的额外比较问题只发生在模型2.0汇编代码中。将编译器目标切换到PS_4_0导致只获得模型4.0代码,并且由于我不受限于级别9_1,所以现在工作得很好。

我通过指定shader model 2.0 assembly不应该由编译器生成来解决这个问题。更多细节见问题末尾。

最新更新