Производительность GLSL — возвращаемое значение/тип функции

StackOverflow https://stackoverflow.com//questions/20052381

Вопрос

Я использую бикубическую фильтрацию для сглаживания карты высот, я реализовал ее в GLSL:

Бикубическая интерполяция: (видеть interpolate() функция ниже)

float interpolateBicubic(sampler2D tex, vec2 t) 
{

vec2 offBot =   vec2(0,-1);
vec2 offTop =   vec2(0,1);
vec2 offRight = vec2(1,0);
vec2 offLeft =  vec2(-1,0);

vec2 f = fract(t.xy * 1025);

vec2 bot0 = (floor(t.xy * 1025)+offBot+offLeft)/1025;
vec2 bot1 = (floor(t.xy * 1025)+offBot)/1025;
vec2 bot2 = (floor(t.xy * 1025)+offBot+offRight)/1025;
vec2 bot3 = (floor(t.xy * 1025)+offBot+2*offRight)/1025;

vec2 mbot0 = (floor(t.xy * 1025)+offLeft)/1025;
vec2 mbot1 = (floor(t.xy * 1025))/1025;
vec2 mbot2 = (floor(t.xy * 1025)+offRight)/1025;
vec2 mbot3 = (floor(t.xy * 1025)+2*offRight)/1025;

vec2 mtop0 = (floor(t.xy * 1025)+offTop+offLeft)/1025;
vec2 mtop1 = (floor(t.xy * 1025)+offTop)/1025;
vec2 mtop2 = (floor(t.xy * 1025)+offTop+offRight)/1025;
vec2 mtop3 = (floor(t.xy * 1025)+offTop+2*offRight)/1025;

vec2 top0 = (floor(t.xy * 1025)+2*offTop+offLeft)/1025;
vec2 top1 = (floor(t.xy * 1025)+2*offTop)/1025;
vec2 top2 = (floor(t.xy * 1025)+2*offTop+offRight)/1025;
vec2 top3 = (floor(t.xy * 1025)+2*offTop+2*offRight)/1025;

float h[16];

h[0] = texture(tex,bot0).r;
h[1] = texture(tex,bot1).r;
h[2] = texture(tex,bot2).r;
h[3] = texture(tex,bot3).r;

h[4] = texture(tex,mbot0).r;
h[5] = texture(tex,mbot1).r;
h[6] = texture(tex,mbot2).r;
h[7] = texture(tex,mbot3).r;

h[8] = texture(tex,mtop0).r;
h[9] = texture(tex,mtop1).r;
h[10] = texture(tex,mtop2).r;
h[11] = texture(tex,mtop3).r;

h[12] = texture(tex,top0).r;
h[13] = texture(tex,top1).r;
h[14] = texture(tex,top2).r;
h[15] = texture(tex,top3).r;

float H_ix[4];

H_ix[0] = interpolate(f.x,h[0],h[1],h[2],h[3]);
H_ix[1] = interpolate(f.x,h[4],h[5],h[6],h[7]);
H_ix[2] = interpolate(f.x,h[8],h[9],h[10],h[11]);
H_ix[3] = interpolate(f.x,h[12],h[13],h[14],h[15]);

float H_iy = interpolate(f.y,H_ix[0],H_ix[1],H_ix[2],H_ix[3]);

return H_iy;
}

Это моя версия, размер текстуры (1025) все еще жестко запрограммирован.Использование этого в вершинном шейдере и/или в шейдере оценки тесселяции очень сильно влияет на производительность (20-30 кадров в секунду).Но когда я меняю последнюю строку этой функции на:

return 0;

производительность увеличивается так же, как если бы я использовал билинейную или ближайшую фильтрацию/без фильтрации.

То же самое происходит с:(Я имею в виду, что производительность остается хорошей)

return h[...]; //...
return f.x; //...
return H_ix[...]; //...

Функция интерполяции:

float interpolate(float x, float v0, float v1, float v2,float v3)
{
    double c1,c2,c3,c4; //changed to float, see EDITs

    c1 = spline_matrix[0][1]*v1;
    c2 = spline_matrix[1][0]*v0 + spline_matrix[1][2]*v2;
    c3 = spline_matrix[2][0]*v0 + spline_matrix[2][1]*v1 + spline_matrix[2][2]*v2 + spline_matrix[2][3]*v3;
    c4 = spline_matrix[3][0]*v0 + spline_matrix[3][1]*v1 + spline_matrix[3][2]*v2 + spline_matrix[3][3]*v3;

    return(c4*x*x*x + c3*x*x +c2*x + c1);
};

Фпс падает только когда возвращаю финал, H_iy ценить.Как возвращаемое значение влияет на производительность?

РЕДАКТИРОВАТЬ Я только что понял, что использовал double в interpolate() функция для объявления c1, c2... и т.д.Я изменил это на float, и теперь производительность остается хорошей с правильным возвращаемым значением.Поэтому вопрос немного меняется:

Как double переменная точности влияет на производительность оборудования, и почему другая функция интерполяции не вызвала эту потерю производительности, только последнюю, поскольку H_ix[] массив был float тоже, как и H_iy?

Это было полезно?

Решение

Чтобы ускорить этот процесс, вы можете использовать texelFetch() вместо floor()/texture(), поэтому оборудование не тратит время на фильтрацию.Хотя аппаратная фильтрация работает довольно быстро, отчасти поэтому я связал драгоценные камни графического процессора статья.Теперь также есть textureSize() функция, которая сохраняет передачу значений самостоятельно.

GLSL имеет очень агрессивный оптимизатор, который отбрасывает все, что только можно.Допустим, вы потратили много времени на вычисление действительно дорогостоящего значения освещения, но в конце просто скажите: colour = vec4(1), все ваши вычисления игнорируются и выполняются очень быстро.К этому может потребоваться некоторое привыкание при попытке сравнить вещи.Я считаю, что это проблема, с которой вы сталкиваетесь, возвращая разные значения.Представьте, что каждая переменная имеет дерево зависимостей, и если какая-либо переменная не используется в выходных данных, включая униформы и атрибуты, и даже на этапах шейдера, GLSL полностью игнорирует ее.Я видел, что компиляторы GLSL терпят неудачу в копировании аргументов функции, когда в этом нет необходимости.

Что касается двойной точности, аналогичный вопрос здесь: https://superuser.com/questions/386456/why-does-a-geforce-card-perform-4x-slower-in-double-precision-than-a-tesla-card.В общем, графика должна быть быстрой и почти всегда использует только одинарную точность.Для вычислительных приложений более общего назначения, например, для научного моделирования, двойные значения, конечно, дают более высокую точность.Вероятно, вы найдете гораздо больше об этом, связанном с CUDA.

Другие советы

вы можете использовать аппаратную билинейную интерполяцию в своих интересах.Бикубическую интерполяцию можно в основном записать как билинейную интерполяцию из билинейно интерполированных входных точек.Так:

uniform sampler2D texture;
uniform sampler2D mask;
uniform vec2 texOffset;
varying vec4 vertColor;
varying vec4 vertTexCoord;
void main() {
  vec4 p0 = texture2D(texture, vertTexCoord.st).rgba;
  vec2 d  = texOffset * 0.125;
  vec4 p1 = texture2D(texture, vertTexCoord.st+vec2( d.x, d.y)).rgba;
  vec4 p2 = texture2D(texture, vertTexCoord.st+vec2(-d.x, d.y)).rgba;
  vec4 p3 = texture2D(texture, vertTexCoord.st+vec2( d.x,-d.y)).rgba;
  vec4 p4 = texture2D(texture, vertTexCoord.st+vec2(-d.x,-d.y)).rgba;
  gl_FragColor = (  2.0*p0   + p1 + p2 + p3 + p4)/6.0;
 }

и это результат

  • первое изображение — стандартная интерполяция Hradware
  • второе изображение представляет собой бикубическую интерполяцию с использованием приведенного выше кода.
  • та же бикубическая интерполяция, но с дискретным цветом, чтобы видеть контурные линии

First ima

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top