Быстрое отображение экрана с палитрой с помощью OpenGL

В игре используется программный рендеринг для рисования полноэкранного (8-битного) изображения с палитрой в памяти.

Какой самый быстрый способ вывести это изображение на экран с помощью OpenGL?

Что я пробовал:

  • glDrawPixels с glPixelMap, чтобы указать палитру, и позволить OpenGL выполнить сопоставление палитры. Производительность была ужасной (~5 FPS).
  • Выполнение сопоставления палитры (индексировано -> BGRX) в программном обеспечении, а затем рисование с использованием glDrawPixels. Производительность была лучше, но загрузка ЦП по-прежнему намного выше, чем при использовании 32-разрядной версии DirectDraw с тем же отображением программной палитры.

Должен ли я вместо этого использовать какую-то текстуру?


person Vladimir Panteleev    schedule 21.09.2012    source источник
comment
Определенно. Загрузите изображение как объект текстуры, затем нарисуйте четырехугольник (или два треугольника) с текстурой этого изображения.   -  person Ben Zotto    schedule 21.09.2012
comment
Даже если изображение будет меняться каждый кадр?   -  person Vladimir Panteleev    schedule 21.09.2012
comment
@CyberShadow: Что еще ты собираешься делать? Данные вашего изображения находятся в памяти клиента, а не на графическом процессоре. Прежде чем графический процессор сможет отобразить его, он должен получить доступ к графическому процессору. Например, поместив его в текстуру.   -  person Nicol Bolas    schedule 21.09.2012
comment
Спасибо. Я предполагаю, что мне просто нелогично, что создание текстуры (со всеми ее накладными расходами) будет быстрее, чем простой вызов функции, специально предназначенной для этой задачи.   -  person Vladimir Panteleev    schedule 21.09.2012
comment
И все же вы можете ускорить загрузку текстур с помощью асинхронной передачи DMA с пинг-понгом PBO. Google для этого. Вот один из ресурсов: songho.ca/opengl/gl_pbo.html. Вы можете увеличить время загрузки x10-x16 (ваша текстура должна считываться из памяти, а не из IO)   -  person Michael IV    schedule 21.09.2012
comment
@CyberShadow Вы не создаете текстуру в каждом кадре (что действительно приводит к дополнительным накладным расходам). Вы просто обновляете его изображение, используя glTexSubImage2DSub там важно). И, конечно же, Майкл прав насчет использования PBO в своих интересах. Но glDrawPixels — это, безусловно, самое медленное, что вы можете сделать.   -  person Christian Rau    schedule 21.09.2012


Ответы (1)


  • glDrawPixels с glPixelMap, чтобы указать палитру, и позволить OpenGL выполнить сопоставление палитры. Производительность была ужасной (~5 FPS).

Это не сюрприз. glDrawPixels не очень быстр для начала, и glPixelMap будет выполнять преобразование индекса/палитры → RGB на ЦП с явно не очень оптимизированным кодовым путем.

  • Выполнение отображения палитры (индексировано -> BGRX) в программном обеспечении, а затем рисование с помощью glDrawPixels.

glDrawPixels — одна из самых медленных функций в OpenGL. У этого есть две основные причины: во-первых, это патч кода, не очень оптимизированный, во-вторых, он записывает непосредственно в целевой буфер кадра, поэтому конвейер синхронизируется каждый раз, когда он вызывается. Кроме того, на большинстве графических процессоров он не поддерживается каким-либо кешем.

Я предлагаю вам поместить индексированное изображение в одноканальную текстуру, например. GL_R8 (для OpenGL-3 или более поздних версий) или GL_LUMINANCE8, а вашу палитру в одномерную текстуру RGB, чтобы индекс, используемый в качестве координаты текстуры, искал цвет. Использование текстуры в качестве LUT совершенно нормально. С этой комбинацией вы используете фрагментный шейдер для преобразования индекса палитры на месте в цвет.

Фрагментный шейдер будет выглядеть так

#version 330

uniform sampler2D image;
uniform sampler1D palette;

in vec2 texcoord;

void main()
{
    float index = tex2D(image, texcoord).r * 255.f; // 255 for a 8 bit palette
    gl_FragColor = texelFetch(palette, index, 0);
}
person datenwolf    schedule 21.09.2012