如何仅通过对某些像素执行复杂代码来优化SM3 HLSL像素着色器?

问题描述 投票:0回答:2

我有一个非常复杂的HLSL着色器,使用Direct3D9中的着色器模型3进行大量纹理读取。复杂代码仅在某些像素处使用,因此我在该代码块周围放置了if语句。令我惊讶的是,这丝毫没有提高性能。如果我使用clip(-1),我确实会看到性能的极大提高,因此此着色器确实是程序的瓶颈。如果没有clip(-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中优化像这样的着色器?

shader hlsl direct3d9
2个回答
1
投票

问题是您的if将被展平(都被执行,错误分支的结果将被丢弃),因为您在其中一个分支(doc)中使用了诸如tex2D之类的梯度函数。如果从分支中删除这些功能或将其替换为非渐变功能(例如tex2Dlod或tex2Dgrad),则应该会看到性能提升。如果在if之前添加[branch],则编译器将有助于查找有问题的行。如果使用梯度函数,这将提示编译器您想要一个真正的分支,否则将在编译时失败。

据我的经验来看,GPU用2x2片段计算输出。这是计算用于纹理查找的正确Miplevel所必需的,因此需要邻居的信息。这样可以防止tex2D功能分支,因为相邻操作需要它们。如果通过传递miplevel来为gpu提供所需的信息,则不再需要其他片段,因此可以实际跳过该分支。


0
投票

使用Z / Stencil缓冲区遮盖不想在其上运行着色器的区域。

© www.soinside.com 2019 - 2024. All rights reserved.