Я установил некоторый FPS-измерительный код в WebGL (на основе этого SO-ответа ) и обнаружил некоторые странности в производительности моего фрагментного шейдера. Код просто отображает один квад (или, скорее, два треугольника) на холсте 1024x1024, поэтому вся магия происходит в фрагментном шейдере.
Рассмотрим этот простой шейдер (GLSL; вершинный шейдер - просто сквозной):
// some definitions
void main() {
float seed = uSeed;
float x = vPos.x;
float y = vPos.y;
float value = 1.0;
// Nothing to see here...
gl_FragColor = vec4(value, value, value, 1.0);
}
Так что это просто делает белый холст. Это в среднем около 30 кадров в секунду на моей машине.
Теперь давайте увеличим число и вычислим каждый фрагмент на основе нескольких октав зависимого от положения шума:
void main() {
float seed = uSeed;
float x = vPos.x;
float y = vPos.y;
float value = 1.0;
float noise;
for ( int j=0; j<10; ++j)
{
noise = 0.0;
for ( int i=4; i>0; i-- )
{
float oct = pow(2.0,float(i));
noise += snoise(vec2(mod(seed,13.0)+x*oct,mod(seed*seed,11.0)+y*oct))/oct*4.0;
}
}
value = noise/2.0+0.5;
gl_FragColor = vec4(value, value, value, 1.0);
}
Если вы хотите запустить приведенный выше код, я использовал эту реализациюsnoise
.
Это приводит к снижению частоты кадров примерно до 7. Это имеет смысл.
Теперь странная часть ... давайте вычислим только один из каждых 16 фрагментов как шум и оставим остальные белыми, заключив вычисление шума в следующее условие:
if (int(mod(x*512.0,4.0)) == 0 && int(mod(y*512.0,4.0)) == 0)) {
// same noise computation
}
Вы ожидаете, что это будет намного быстрее, но это все равно всего 7 кадров в секунду.
Для еще одного теста давайте вместо этого отфильтруем пиксели с помощью следующего условия:
if (x > 0.5 && y > 0.5) {
// same noise computation
}
Это дает точно такое же количество пикселей шума, как и раньше, но теперь мы вернулись почти к 30 кадрам в секунду.
Что здесь происходит? Разве два способа отфильтровать 16-е пиксели не должны дать одинаковое количество циклов? И почему медленнее, чем рендеринг всех пикселей в виде шума?
Бонусный вопрос: что я могу с этим сделать? Есть ли способ , чтобы работать вокруг ужасной производительности , если я на самом деле действительно хочу спекл моего холста с помощью всего несколько дорогих фрагментов?
(Просто чтобы быть уверенным, я подтвердил, что фактические вычисления по модулю не влияют на частоту кадров, отображая каждый 16-й пиксель черным, а не белым.)