我有一个非常复杂的HLSL着色器,使用Direct3D9中的着色器模型3进行大量的纹理读取。复杂的代码仅用于某些像素,因此我在该代码块周围添加了一个if语句。令我惊讶的是,这根本没有带来任何性能提升。如果我使用clip(-1)代替我确实看到了巨大的性能提升,那么这个着色器确实是我程序的瓶颈。如果没有剪辑(-1)行,为什么分支不能提高我的性能?
我找到了这个主题:How much performance do conditionals and unused samplers/textures add to SM2/3 pixel shaders?这个主题说明在着色器模型3中可以用分支进行优化,但性能是每批像素中最差的。在可能的情况下,慢分支主要在屏幕的边缘处进行,并且快速分支主要在屏幕的中心。我认为这意味着批量像素通常采用相同的分支,因此我希望通过这种方式获得性能提升。
在伪代码中,像素着色器看起来像这样:
float4 colour = tex2D(texture, uv);
if (colour.a < 0.5f)
{
//I only get a performance boost if I replace this line with clip(-1);
oColour = colour;
}
else
{
complexSlowCodeWithTonsOfTextureReadsGoesHere;
oColour = result;
}
oColour *= 2;
这给了我与删除分支时完全相同的性能,并始终使用慢速else分支中的代码。如果我用clip(-1)替换第五行,我会看到一个巨大的性能提升(并且主要是黑屏),所以if语句实际上正在运行。
我在这里做错了什么,或者不能在着色器模型3中优化这样的着色器?
答案 0 :(得分:1)
问题是你的if会被压平(两次都被执行,丢弃了错误的分支的结果),因为你在你的一个分支(doc)中使用像tex2D这样的梯度函数。如果从分支中删除这些函数或用非渐变函数(如tex2Dlod或tex2Dgrad)替换它们,您应该会看到性能提升。如果在if之前添加[branch]
,编译器将有助于找到有问题的行。这将提示编译器你想要一个真正的分支if,如果你正在使用渐变函数,它将在编译时失败。
根据我的经验,gpu使用2x2片段计算输出。这需要计算用于纹理查找的正确的miplevel,因此需要邻居的信息。这可以防止tex2D函数分离,因为相邻操作需要它们。如果通过传递miplevel为gpu提供所需的信息,则不再需要其他片段,因此可以实际跳过分支。
答案 1 :(得分:0)
使用Z / Stencil缓冲区遮盖不想在其上运行着色器的区域。