我有一个着色器,看起来像这样:
void main( in float2 pos : TEXCOORD0,
in uniform sampler2D data : TEXUNIT0,
in uniform sampler2D palette : TEXUNIT1,
in uniform float c,
in uniform float th0,
in uniform float th1,
in uniform float th2,
in uniform float4 BackGroundColor,
out float4 color : COLOR
)
{
const float4 dataValue = tex2D( data, pos );
const float vValue = dataValue.x;
const float tValue = dataValue.y;
color = BackGroundColor;
if ( tValue <= th2 )
{
if ( tValue < th1 )
{
const float vRealValue = abs( vValue - 0.5 );
if ( vRealValue > th0 )
{
// determine value and color
const float power = ( c > 0.0 ) ? vValue : ( 1.0 - vValue );
color = tex2D( palette, float2( power, 0.0 ) );
}
}
else
{
color = float4( 0.0, tValue, 0.0, 1.0 );
}
}
}
我像这样编译它:
cgc -profile arbfp1 -strict -O3 -q sh.cg -o sh.asm
现在,不同版本的Cg编译器产生不同的输出。
cgc版本2.2.0006正在使用18条指令将着色器编译成汇编代码:
!!ARBfp1.0 PARAM c[6] = { program.local[0..4],{ 0, 1, 0.5 } }; TEMP R0; TEMP R1; TEMP R2; TEX R0.xy, fragment.texcoord[0], texture[0], 2D; ADD R0.z, -R0.x, c[5].y; CMP R0.z, -c[0].x, R0.x, R0; MOV R0.w, c[5].x; TEX R1, R0.zwzw, texture[1], 2D; SLT R0.z, R0.y, c[2].x; ADD R0.x, R0, -c[5].z; ABS R0.w, R0.x; SGE R0.x, c[3], R0.y; MUL R2.x, R0, R0.z; SLT R0.w, c[1].x, R0; ABS R2.y, R0.z; MUL R0.z, R2.x, R0.w; CMP R0.w, -R2.y, c[5].x, c[5].y; CMP R1, -R0.z, R1, c[4]; MUL R2.x, R0, R0.w; MOV R0.xzw, c[5].xyxy; CMP result.color, -R2.x, R0, R1; END # 18 instructions, 3 R-regs
cgc版本3.0.0016正在使用23条指令将着色器编译成汇编代码:
!!ARBfp1.0 PARAM c[6] = { program.local[0..4], { 0, 1, 0.5 } }; TEMP R0; TEMP R1; TEMP R2; TEX R0.xy, fragment.texcoord[0], texture[0], 2D; ADD R1.y, R0.x, -c[5].z; MOV R1.z, c[0].x; ABS R1.y, R1; SLT R1.z, c[5].x, R1; SLT R1.x, R0.y, c[2]; SGE R0.z, c[3].x, R0.y; MUL R0.w, R0.z, R1.x; SLT R1.y, c[1].x, R1; MUL R0.w, R0, R1.y; ABS R1.z, R1; CMP R1.y, -R1.z, c[5].x, c[5]; MUL R1.y, R0.w, R1; ADD R1.z, -R0.x, c[5].y; CMP R1.z, -R1.y, R1, R0.x; ABS R0.x, R1; CMP R0.x, -R0, c[5], c[5].y; MOV R1.w, c[5].x; TEX R1, R1.zwzw, texture[1], 2D; CMP R1, -R0.w, R1, c[4]; MUL R2.x, R0.z, R0; MOV R0.xzw, c[5].xyxy; CMP result.color, -R2.x, R0, R1; END # 23 instructions, 3 R-regs
奇怪的是,cg 3.0的优化水平似乎没有影响任何事情。
谁能解释一下这是怎么回事?为什么优化不起作用,为什么当我用cg 3.0编译时着色器更长?请注意,我从编译的着色器中删除了注释。
这可能不是问题的真正答案,但可能会提供一些更多的见解。我检查了一下生成的汇编代码,并将其转换回高级代码。我试图尽可能地压缩它,并删除所有的副本和隐含地跟随高级操作的临时文件。我使用b
变量作为临时bool,使用f
变量作为临时float。第一个(2.2版本)是:
power = ( c > 0.0 ) ? vValue : ( 1.0 - vValue );
R1 = tex2D( palette, float2( power, 0.0 ) );
vRealValue = abs( vValue - 0.5 );
b1 = ( tValue < th1 );
b2 = ( tValue <= th2 );
b3 = b1;
b1 = b1 && b2 && ( vRealValue > th0 );
R1 = b1 ? R1 : BackGroundColor;
color = ( b2 && !b3 ) ? float4( 0.0, tValue, 0.0, 1.0 ) : R1;
,第二个(带3.0)是:
vRealValue = abs( vValue - 0.5 );
f0 = c;
b0 = ( 0 < f0 );
b1 = ( tValue < th1 );
b2 = ( tValue <= th2 );
b4 = b1 && b2 && ( vRealValue > th0 );
b0 = b0;
b3 = b1;
power = ( b4 && !b0 ) ? ( 1.0 - vValue ) : vValue;
R1 = tex2D( palette, float2( power, 0.0 ) );
R1 = b4 ? R1 : BackGroundColor;
color = ( b2 && !b3 ) ? float4( 0.0, tValue, 0.0, 1.0 ) : R1;
大多数部分本质上是相同的。第二个程序做一些不必要的操作。它将c
变量复制到临时变量中,而不是直接使用它。而且它在算力的时候把vValue
和1-vValue
切换了,所以需要否定b0
(导致多出一个CMP
),而第一个根本不使用临时(直接使用CMP
而不是SLT
和CMP
)。它还在此计算中使用b4
,这是完全不必要的,因为当b4
为假时,纹理访问的结果无论如何都是无关的。这导致了多一个&&
(用MUL
实现)。还有从b1
到b3
的不必要的复制(在第一个程序中是必要的,但在第二个程序中不是)。以及从b0
复制到自身的极其无用的复制(伪装成ABS
,但由于值来自SLT
,它只能是0.0或1.0,并且ABS
退化为MOV
)。
所以第二个程序与第一个程序非常相似,只是有一些额外的,但IMHO完全无用的指令。与之前的(!)版本相比,优化器似乎做得更差。由于Cg编译器是nVidia的产品(而不是来自其他未命名的图形公司),这种行为真的很奇怪。