Быстрый рисование линии в OpenGL

Я работаю над проектом, который требует рисования большого количества данных, поскольку он приобретается АЦП... что-то вроде 50 000 строк на кадр на мониторе с разрешением 1600 пикселей в ширину. Он отлично работает на системе с Quadro FX 570 2007 года, но в принципе не может справиться с данными на машинах с чипами класса Intel HD 4000. Нагрузка данных составляет 32 канала с 200 Гц данными, полученными партиями по 5 отсчетов на канал 40 раз в секунду. Таким образом, другими словами, карта должна достигать 40 кадров в секунду или лучше.

Я использую один VBO для всех 32 каналов с пространством для 10000 вершин каждый. VBO по существу обрабатывается как серия кольцевых буферов для каждого канала. Когда данные поступают, я делюминирую их на основе используемого временного масштаба. Таким образом, в основном, он отслеживает мин/макс для каждого канала. Когда для столбца с одним пикселем получено достаточно данных, он устанавливает следующие две вершины в VBO для каждого канала и отображает новый кадр.

Я использую glMapBuffer() для доступа к данным один раз, обновления всех каналов, использования glUnmapBuffer, а затем рендеринга при необходимости.

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

#version 120

varying vec4 _outColor;

uniform vec4 _lBound=vec4(-1.0);
uniform vec4 _uBound=vec4(1.0);
uniform mat4 _xform=mat4(1.0);

attribute vec2 _inPos;
attribute vec4 _inColor;

void main()
{
    gl_Position=clamp(_xform*vec4(_inPos, 0.0, 1.0), _lBound, _uBound);
    _outColor=_inColor;
}

Униформа _lBound, _uBound и _xform обновляется один раз на канал. Итак, 32 раза за кадр. Зажим используется для ограничения некоторых каналов на диапазон y-координат на экране.

Фрагментный шейдер просто:

#version 120

varying vec4 _outColor;

void main()
{
    gl_FragColor=_outColor;
}

Есть другие вещи, которые отображаются на экране; канальные метки, например, с использованием квадроциклов и текстурного атласа; но профилирование в gDEBugger, по-видимому, указывает на то, что рендеринг строк занимает подавляющее большинство времени на кадр.

Тем не менее, 50 000 строк не кажутся мне ужасно большим числом.

Итак, после всего этого возникает вопрос: есть ли уловки для ускорения рисования линии? Я попытался сделать их в буфер трафарета, а затем обрезать один квад, но это было медленнее. Я думал о том, как рисовать линии текстуры, рисовать квадрат с текстурой. Но это не кажется масштабируемым или даже более быстрым из-за постоянной загрузки больших текстур. Я видел технику, которая хранит значения y в текстуре одной строки, но это больше похоже на оптимизацию памяти, а не на оптимизацию скорости.

Ответ 1

Спасибо, всем. Я, наконец, остановился на blitting между фреймбуферами, поддерживаемыми renderbuffers. Хорошо работает. Многие предложили использовать текстуры, и я могу пойти по этому пути в будущем, если мне в конечном итоге придется зарисовать данные.

Ответ 2

Отображение VBO может замедлить работу из-за того, что драйверу может потребоваться синхронизация GPU с CPU. Более эффективный способ - просто выбросить данные на GPU, чтобы процессор и графический процессор могли работать более независимо.

  • Воссоздайте VBO каждый раз, создайте его с помощью STATIC_DRAW
  • Если вам нужно сопоставить свои данные, НЕ НАЙТИ как читаемые (GL_WRITE_ONLY)

Ответ 3

Если вы просто прокручиваете линейный график (стиль GDI), просто нарисуйте новый столбец на CPU и используйте glTexSubImage2D для обновления одного столбца в текстуре. Нарисуйте его как пару квадроциклов и обновите st-координаты для обработки прокрутки/обертки.

Если вам нужно постоянно обновлять все строки, используйте VBO, созданный с помощью GL_DYNAMIC_DRAW, и используйте glBufferSubData для обновления буфера.