Пытаясь в целях изучения перенести некоторые OpenGL-программы на Direct3D 10, я обнаружил, что одна из них работает неправильно. Долго описывать все злоключения, которые я испытал за последние три дня, отлаживая и выверяя код между GL- и D3D-версией, поэтому не буду. Как человек отчаявшийся, я предположил последний вариант - неправильно работает геометрический шейдер (расcчитавающий penumbra wedges). Код шейдера был скопипастен из Cg-шейдера, за исключением простых правок для HLSL10. Компилировался он без ошибок, что подсказывало мне, что всё должно быть правильно. Шейдер работал, но выдывал, к моему большому сожалению, неправильный результат.
В конце-концов, не найдя больше очевидных причин для неправильной работы, я полез в справку по D3DX10CreateEffectFromFile() и стал изучать флаги, с которыми шейдер можно комплировать (типично - D3D10_SHADER_DEBUG для отладки). В моём коде было много if-oв, и я решил попробовать флаг D3D10_SHADER_PREFER_FLOW_CONTROL. И мои надежды оправдались - шейдер заработал правильно! Правда, в описании флага написано "Tell compiler to use flow-control (when possible)". Почему компилятор сам не догадался использовать везде где нужно динамические переходы - для меня загадка.
И уже после этого нашёл ещё один подводный камень. Вот такой код работает неправильно:
for (int i = 0; i < 10; ++i)
{
float Array[10] = {0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
// Тут читаем элемент Array[i];
}
А такой - правильно:
float Array[10] = {0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
for (int i = 0; i < 10; ++i)
{
// Тут читаем элемент Array[i];
}
В чём разница, я так и не понял. Компилятор должен расположить такой массив в константных регистрах, независимо от того, где я собственно его объявил, и разницы в работе быть не должно. И даже если бы asm-код от этого поменялся и стал бы менее оптимальным, он всё равно обязан был работать правильно. Можно было бы посмотреть asm-листинг, но я в нём пока не разбираюсь. По крайней мере для ARB-кода, что генерирует Cg, разницы нет никакой.
Ссылка