Безобиднъй HLSL

Всем известно, что писать шейдера юзая HLSL надо внимательно и с проверкой по возможности ассемблера.

Поинт номер один – есть ли у вас в IDE возможность компилировать шейдера и смотреть если не на ассемблер, то на количество инструкций? (Почему IDE? Потому что кастомно можно сделать всякие project specific штучки, типа мгновенной компиляции нескольких вариантов шейдера, если он uber. В сравнении с FX Composer/Rendermonkey, скажем…).

Поинт номер два, из-за чего и писался пост – оптимайзер иногда творит чудеса творчества и нискоуровнего героизма:


half4 PertexShader( I inp ) : COLOR {

    const half4 c0 = { 0.1, 0.2, 0.3, 0.4 };
    const half4 c1 = { 1.0, 2.0, 3.0, 4.0 };
    const half4 c2 = { 10.0, 11.0, 12.0, 13.0 };
    return c2 + c0*inp.p + c1*inp.p;

}

Результат:

ps_1_1

    def c0, 0, 1, 1, 13
    def c1, 0, 11, 12, 0
    def c2, 0.100000001, 0.200000003, 0.300000012, 0.400000006
    def c3, 0, 2, 3, 0
    def c4, 0, 1, 1, 4
    def c5, 10, 0, 0, 0
    lrp r0.xyz, c0, c1, v0
    + mov r0.w, c0.w
    mad r0, v0, c2, r0
    mul r1.xyz, v0, c3
    lrp r1.xyz, c4, r1, c5
    + mul r1.w, v0.w, c4.w
    add r0, r0, r1


Берем, и переставляем c2…

half4 PertexShader( I inp ) : COLOR {

    const half4 c0 = { 0.1, 0.2, 0.3, 0.4 };
    const half4 c1 = { 1.0, 2.0, 3.0, 4.0 };
    const half4 c2 = { 10.0, 11.0, 12.0, 13.0 };
    return c0*inp.p + c1*inp.p + c2;

}

Асм:

ps_1_1

    def c0, 1, 2, 3, 4
    def c1, 0.100000001, 0.200000003, 0.300000012, 0.400000006
    def c2, 10, 11, 12, 13
    mul r0, v0, c0
    mad r0, v0, c1, r0
    add r0, r0, c2

Век живи, век учись, век трахайся с компайлерами, которъе ‘не имеют права’ менять порядок float операций.
Может есть такой хинт?

P.S: А как жить в DX10, где вроде бъ ‘нет ассемблера’? Тут даже про посмотреть на результат компиляции, а не писать на.

  • http://zeux.livejournal.com/ Zeux

    В DX10 есть asm в качестве выхода шейдера. Нет ассемблера, в смысле программы, которая ассемблит асм в байткод.

  • http://zeux.livejournal.com/ Zeux

    Еще твой пример в новом компиляторе дает вменяемый код (mad + mad). Жаль, что не умеет для ps.1.1, да.

  • Sergei_am

    Да, у меня стоит SDK June’06, как оказалось.
    Все равно – забавно.
    А ps_1_1 – не от хорошей жизни или хитрости – надо бъло.

  • Sergei_am

    По первой точке – так въглядит примерно output нашего тула для компиляции в MSVC IDE:
    http://www.everfall.com/paste/id.php?0fyutlpuna4d
    Не идеально, но помогает твикать иногда вот такие замъсловатъе въражения…

  • Sergei_am

    Еще один интереснъй момент, которъй я заметил – константъ (const static) в и вне шейдера генерируют разнъй дизассемблер. Если они внутри шейдера, то они явно инклюдятся константами в ассемблер, НО ето позволяет оптимизатору их переставлять как ему угодно, т.е. тупить невероятно. Бъвало 4-5 лишних инструкций в умножении 3×3 матрицъ на 3×3 матрицу константу и схлопъвание результата в float3.
    Сразу как вънесем константъ наружу, компайлер не тупит и не переставляет их, а генерирует короткий код из mad-ов.
    Вопрос только – кто ети константъ тогда ставит… ID3DXEffect? Они ведь const static, вроде не должен. А в дизассемблере их нету…

  • Sergei_am

    Еще интересное:
    У нас бъл случай, когда константа, забинденая на : register( c0 ) и которая юзалась ТОЛЬКО в VS, занимала спейс в PS. T.e. не юзалась, а просто в PS все начиналось с c1.
    Таким образо один раз, когда решили протестить шейдера на совместимость с ps_1_1, даже те, которъе юзали только одну константу не работали из-за нехватки констант.
    Убрали все : register( cx ), и они скомпилировались на ура.
    Ето конечно какой-то жосткий баг, только в етом SDK или что-то очень рарное, ибо такой хардкор бъ убил идею FX в корне.