Почему в более поздней версии компилятора Cg шейдер использует больше инструкций? - PullRequest
1 голос
/ 15 июля 2011

У меня есть шейдер, который выглядит следующим образом:

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?

Обратите внимание, что я удалил комментарии из скомпилированных шейдеров.

1 Ответ

1 голос
/ 23 июля 2011

Возможно, это не реальный ответ на проблему, но, возможно, даст немного больше понимания.Я немного проверил сгенерированный код сборки и преобразовал его обратно в код высокого уровня.Я старался максимально сжать его и удалить все копии и временные данные, которые неявно следуют за операциями высокого уровня.Я использовал b переменные как временные буферы и f s как временные буферы.Первый (с версией 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), в то время как первый вообще не использует временный (он использует * 1014)* напрямую вместо SLT и CMP).В этом вычислении он также использует b4, что совершенно не нужно, потому что когда b4 равно false, результат доступа к текстуре в любом случае не имеет значения.Это приводит к еще одному && (реализовано с MUL).Существует также ненужная копия от b1 до b3 (в первой программе она необходима, но не во второй).И крайне бесполезная копия из b0 в себя (которая замаскирована как ABS, но так как значение приходит от SLT, оно может быть только 0,0 или 1,0, а ABS вырождается в MOV).

Итак, вторая программа очень похожа на первую с некоторыми дополнительными, но ИМХО совершенно бесполезными инструкциями.Похоже, оптимизатор проделал худшую работу по сравнению с предыдущей (!) Версией.Поскольку компилятор Cg является продуктом nVidia (а не какой-то другой, не именуемой графической компанией), это поведение действительно странно.

...