Вершинный шейдер OpenGL работает быстро в Linux, но крайне медленно в Windows - PullRequest
0 голосов
/ 05 октября 2018

Чтобы нарисовать спектральную плотность мощности сигнала (которая очень похожа на тепловую карту), я использую эту программу вершинного шейдера.Он получает значение мощности в каждой вершине, принимает логарифм для отображения результата в дБ, нормализует в диапазоне массива цветовой карты и назначает цвет для вершины.

#version 130

uniform float max_val;
uniform float min_val;
uniform int height;

attribute float val; // power-spectral-density value assigned to each vertex

// colormap values
const float r[512] = float[]( /* red values come here */ );
const float g[512] = float[]( /* green values come here */ );
const float b[512] = float[]( /* blue values come here */ );

void main() {
  // set vertex position based on its ID
  int x = gl_VertexID / height;
  int y = gl_VertexID - x * height;
  gl_Position = gl_ModelViewProjectionMatrix * vec4(x, y, -1.0, 1.0);

  float e = log(max_val / min_val);
  float d = log(val / min_val);

  // set color
  int idx = int(d * (512 - 1) / e); // find normalized index that falls in range [0, 512)
  gl_FrontColor = vec4(r[idx], g[idx], b[idx], 1.0); // set color
}

Соответствующий код C ++ находится здесь:

QOpenGLShaderProgram glsl_program;
// initialization code is omitted

glsl_program.bind();
glsl_program.setUniformValue(vshader_max_uniform, max_val);
glsl_program.setUniformValue(vshader_min_uniform, min_val);
glsl_program.setUniformValue(vshader_height_uniform, max_colormap_height);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, colormap); // colormap is a vector that contains value of power at each vertex
glDrawElements(GL_TRIANGLE_STRIP, vertices_length, GL_UNSIGNED_INT, nullptr); // vertex_length is size of colormap
glDisableVertexAttribArray(0);

glsl_program.release();

Эта программа работает достаточно быстро в Linux.Но в Windows это очень медленно и занимает много процессорного времени.Если я изменю эту строку GLSL:

// int idx = int(d * (512 - 1) / e);
int idx = 0;

, тогда приложение будет работать быстро и на Windows.Итак, проблема должна быть в коде GLSL.

Как это исправить?

1 Ответ

0 голосов
/ 05 октября 2018

То, что вы там делаете, относится к фрагментному шейдеру, а не к вершинному шейдеру.И вы отправляете таблицу соответствия цветов и данные спектральной плотности в виде текстуры.Хотя установка вершин не стоит , что стоит , она сопряжена с определенными накладными расходами, и, как правило, вы хотите покрыть как можно больше пикселей с наименьшим возможным числом вершин.

Также изучите правила вычисления логарифма (например, log(a/b) = log(a) - log(b)) и избегайте выполнения расчетов, которые являются единообразными по всему вызову отрисовки и предварительно рассчитываются на хосте.

/* vertex shader */
#version 130

varying vec2 pos;    

void main() {
  // set vertex position based on its ID
  // To fill the viewport, we need just three vertices
  // of a rectangular triangle of with and height 2
  pos.x = gl_VertexID % 2;
  pos.y = gl_VertexID / 2;

  // screen position is controlled using glViewport/glScissor
  gl_Position = vec4(2*pos, 0, 1.0);
}

-

/* fragment shader */
#version 130

varying vec2 pos;

uniform sampler2D values;
uniform sampler1D colors;

uniform float log_min;
uniform float log_max;

void main() {
  float val = texture2D(values, pos).x;
  float e = log_max - log_min;
  float d = (log(val) - log_min) / e;

  gl_FragColor = vec4(texture1D(colors, d).rgb, 1.0); // set color
}

В более поздних версиях GLSL некоторые ключевые слова имеютизменилось.Изменения определяются с использованием in и out вместо varying, а функции доступа к текстуре были объединены для охвата всех типов сэмплеров.

glsl_program.bind();
glsl_program.setUniformValue(vshader_log_max_uniform, log(max_val));
glsl_program.setUniformValue(vshader_log_min_uniform, log(min_val));

// specify where to draw in window pixel coordinates.
glEnable(GL_SCISSOR_TEST);
glViewport(x, y, width, height);
glScissor(x, y, width, height);

glBindTexture(GL_TEXTURE_2D, values_texture);
glTexSubImage2D(GL_TEXTURE_2D, ..., spectral_density_data);
glDrawArrays(GL_TRIANGLES, 0, 3);

glsl_program.release();
...