如何在HLSL中计算指令数?

3
当我使用以下代码时:

#define MAX_RADIUS 55
#define KERNEL_SIZE (MAX_RADIUS * 2 + 1)
...
float[] kernel[KERNEL_RADIUS];
...
float4 PS_GaussianBlur(float2 texCoord : TEXCOORD) : COLOR0
{
    float4 color = float4(0.0f, 0.0f, 0.0f, 0.0f);

    //add the right side offset pixels to the color
    for (int i = 0; i < MAX_RADIUS; i++)
    {
        if(kernel[i] != 0) //this will improve performance for lower filter radius's, but increases const register num
            color += tex2D(colorMap, texCoord + offsets[i]) * kernel[i];
    }
    //add the left side offset pixels to the color
    for (int j = 0; j < MAX_RADIUS; j++)
    {
        if(kernel[i] != 0)
            color += tex2D(colorMap, texCoord - offsets[j]) * kernel[j];
    }
    //finally add the weight of the original pixel to the color
    color += tex2D(colorMap, texCoord) * kernel[MAX_RADIUS];

    return color;
}
if(kernel[i] != 0)会大大增加指令使用量!那么我的问题是:什么会增加指令计数?为什么在只有110条指令的循环中使用if语句会使指令计数增加超过400条?
编辑:上述问题已经更正。我错误地认为寄存器被占用,实际上是指令。然而,问题仍然存在。什么会导致两个长度为55的for循环,在循环内添加一个if语句后,指令计数增加超过400条?

如果您反汇编已编译的HLSL代码,会得到什么?它使用了多少额外的寄存器? - Andrew Russell
1
@AndrewRussell 我不知道我怎么错过了这个,但实际上是指令计数超标了,而不是寄存器。我已经适当地重新表述了问题。 - Darkhydro
你使用的着色器模型是什么? - Andrew Russell
刚刚尝试了使用fxc进行编译(使用ps_3_0,因为在此之下由于寄存器限制无法编译)。没有分支时,它给出了165条指令,有分支时则有275条(每次迭代增加2条指令,这是有道理的)。你用什么来编译(以及哪些标志)? - mrvux
@catflier 我也在使用ps_3_0。我已经发布了完整的像素着色器代码,因为似乎我没有提供足够的信息... 当我使用Visual Studio和XNA的默认标志进行编译时,我得到了超过940条指令。 - Darkhydro
2个回答

2

您可以使用FXC.exe来计算指令。以下是一个快速指南。

FXC.exe现在包含在Windows 8 SDK中,该SDK与VS2012一起提供。

在64位PC上,FXC.exe位于此目录中:C:\Program Files (x86)\Windows Kits\8.0\bin\x86\fxc.exe

用法:您可以使用以下命令行将FX文件输入并将汇编代码和头文件输出到文本文件中:

> FXC.exe C:/Shader.fx /T fx_4_0 /Fx C:/Output.txt

或者
> FXC.exe C:/Shader.fx /T fx_4_0 /Cc /Ni /Fc C:/Output.html

为了获得一个酷炫的语法高亮的HTML输出


如果需要,我会下载SDK,但是我有VS2010,所以我想知道是否有其他地方可以找到FXC?此外,当XNA超过时,我可以从XNA获取指令计数。 - Darkhydro
我也有它(Dr. ABT说的那个),但是我同时拥有VS2012和VS2010。对我来说,以下命令行可以奏效:fxc "*.fx" /T ps_3_0 /E PixelShaderFunction /Zi /Cc /Ni /No /Fx C:/output.html非常感谢您的答案!(ps_3_0用于像素着色器版本3.0,“/E”用于标记像素着色器函数名称)在文件末尾,我得到了“// approximately 104 instruction slots used (14 texture, 90 arithmetic)”。 - Lodewijk
这里有可执行文件:(虽然您不应该信任陌生人的可执行文件!) https://mega.co.nz/#!7FZm2ajK!YFgqoVtKgc6bkyzsARwTrTIlrflaMzEfvGBB5jxMwLs - Lodewijk

2

fxc会给你一个指令计数。但实际上,你应该用另一种方式来做这件事。尝试使用双向过滤器,其中一次在U上进行,另一次在V上进行?


抱歉回复晚了,我有一段时间没上SO了。我的着色器代码有点生疏,但如果我没记错的话,这就是这个着色器在做的事情。第一个循环是水平通道,第二个是垂直通道。我只是实现了一些寄存器节省方法,并为了提高性能引入了if语句,跳过了值为0的元素(对于小的滤波半径,有很多0)。也许你可以向我解释一下你的想法? - Darkhydro
我的意思是使用两个不同的着色器(或者使用相同的着色器但参数不同)进行两次独立的渲染,第一次将结果渲染到纹理中,然后在这些结果上运行第二次渲染。 - bjorke
平面二遍纹理映射和扭曲。阿尔维·雷·史密斯,1987年。 - bjorke
好的,我明白你的意思。这很有道理。肯定会减少一次通过中使用的指令数量,但并不能解释为什么if语句会导致指令计数爆炸。这个问题不是为了找到减少指令计数的方法,而是尽可能地理解HLSL。 - Darkhydro
如果我没记错的话,所有GPU编译器都会看到循环内部的“if”语句,并决定展开循环。因此,您将得到许多内联展开的if语句。如果有疑问,请查看fxc的ASM输出... - bjorke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接