1

次のようなシェーダーがあります。

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 でコンパイルすると、最適化が機能せず、シェーダーが長くなるのはなぜですか?

コンパイルされたシェーダーからコメントを削除したことに注意してください。

4

1 に答える 1

1

これは問題に対する本当の答えではないかもしれませんが、もう少し洞察が得られるかもしれません。生成されたアセンブリ コードを少し調べて、高レベル コードに変換し直しました。可能な限り圧縮し、高レベルの操作から暗黙的に続くすべてのコピーと一時ファイルを削除しようとしました。b変数を一時的な bool として使用し、 fs を一時的な 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;

2 つ目 (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;

ほとんどの部分は本質的に同じです。2 番目のプログラムは、いくつかの不要な操作を行います。c変数を直接使用するのではなく、一時変数にコピーします。vValueさらに、べき乗計算でandを切り替える1-vValueので、否定する必要がありますb0(結果として 1 つ以上CMP) が、最初のものは一時的なものをまったく使用しません ( andCMPの代わりに直接使用します)。また、この計算では も使用しますが、これはまったく不要です。これは、が false の場合、テクスチャ アクセスの結果が関係ないためです。これにより、もう 1 つ発生します( で実装)。からへの不要なコピーもありますSLTCMPb4b4&&MULb1b3(最初のプログラムでは必要ですが、2 番目のプログラムでは必要ありません)。そして、b0それ自体への非常に役に立たないコピー (これは に偽装されてABSいますが、値が から取得されるため、値はSLT0.0 または 1.0 にしかならず、 は にABS縮退しますMOV)。

したがって、2 番目のプログラムは最初のプログラムと非常によく似ていますが、追加の命令がいくつかありますが、私見ではまったく役に立たない命令です。オプティマイザーは、以前の (!) バージョンに比べて悪い仕事をしたようです。Cg コンパイラは nVidia 製品であるため (また、他のグラフィックス会社の製品ではありません)、この動作は非常に奇妙です。

于 2011-07-22T21:51:16.907 に答える