Как определить, какие форматы текстур OpenGL изначально поддерживаются?

10

Например, как определить, не поддерживает ли моя видеокарта «bgr8», и преобразовать ее в другой формат, например «rgba8», в программном режиме.

ОБНОВЛЕНИЕ: Извините за путаницу. Этот вопрос больше касается ситуации, когда я установил internalFormat в glTexImage2D на что-то вроде «bgra8», но видеодрайвер внутренне конвертирует данные в другой формат, например «rgba8».

KindDragon
источник

Ответы:

11

Ваш вопрос, кажется, сбивает с толку определенные концепции, поэтому давайте рассмотрим все с самого начала. Это определение функции glTexImage2D:

void glTexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, void *data );

Есть две вещи, которые вы можете назвать «форматы текстур». Первый internalformatпараметр. Это реальный формат изображения, поскольку OpenGL хранит его. formatПараметр описывает часть формата пиксельных данных вы обеспечиваете с dataпараметром.

Другими словами, formatи typeопределите, как будут выглядеть ваши данные. internalformatэто то, как вы говорите OpenGL для хранения ваших данных. Давайте назовем formatи type«формат передачи пикселей», пока internalformatбудет «формат изображения».

Формат изображения текстуры никогда не может быть "bgr8". Нет перечислителя формата изображения GL_BGR8. Там есть GL_BGR перечисление, но это для формата передачи пикселей, а не формат изображения.

Или, другими словами, ваши данные пикселей, которые вы предоставляете OpenGL, могут храниться в порядке BGR. Но реализация OpenGL сама решает, как на самом деле хранить эти данные пикселей. Возможно это хранит это в порядке с прямым порядком байтов. Может быть, он хранит это в порядке байтов. Может быть, это просто произвольно переставляет байты. Вы не знаете, и OpenGL не предоставляет способ выяснить это.

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

Есть способ сказать сейчас. И под «сейчас» я имею в виду OpenGL 4.3 и / или ARB_internalformat_query2. Подходим к видеокарте рядом с вами:

GLenum format, type;
glGetInternalformativ(texture_target, GL_RGBA8, GL_TEXTURE_IMAGE_FORMAT, 1, &format);
glGetInternalformativ(texture_target, GL_RGBA8, GL_TEXTURE_IMAGE_TYPE, 1, &type);

formatи typeтеперь есть предпочтительная реализация formatи typeдля использования glTex(Sub)Imageвызовов к GL_RGBA8изображениям. Есть отдельные formatи typeзапросы на glReadPixelsскачивание.

Есть и другие вопросы, которые вы можете задать .

Если у вас нет доступа к ним, вы можете использовать некоторые общие правила, которых придерживается большинство аппаратных средств:

  • будет хранить данные пикселей для данных 8 бит на канал в порядке BGRA. Поэтому, если вы хотите сопоставить формат с вашими пиксельными данными, чтобы быстрее загружать данные текстуры, вы хотите использовать GL_BGRAдля format, и GL_UNSIGNED_INT_8888или GL_UNSIGNED_BYTEдля type.
  • фактически не будет хранить 24-битные цвета как 24-битные. Он всегда будет дополнять их до 32 бит; альфа будет просто игнорироваться при чтении данных. Так что если вы хотите , чтобы соответствовать форматам, всегда использовать GL_BGRA formatс GL_RGB8форматами изображений, даже если вы должны поместить фиктивные данные в альфа - компоненте.
Николь Болас
источник
4
Я также нашел, что лучше использовать формат GL_BGRA с внутренним форматом GL_RGBA http.download.nvidia.com/developer/Papers/2005/…
KindDragon
Я бы воздержался от ребрендинга параметра internalFormat как «формата изображения», потому что это одинаково сбивает с толку. Возможно, имеет смысл думать о «internalFormat» как о «формате пикселя текстуры». Комбинация параметров «формат» и «тип» - это «формат исходного пикселя» (который часто является изображением, поэтому мой комментарий). И, конечно же, есть формат GPU, который является BGRA для форматов целочисленного типа.
StarShine
6

Как правило, большинство аппаратных средств не поддерживает 3-компонентные форматы текстур, поэтому в этом конкретном примере вы можете сделать достаточно безопасное предположение о том, что он преобразован. Трехкомпонентная текстура OpenGL на самом деле является четырехкомпонентной в аппаратном обеспечении, но альфа-компонент игнорируется / устанавливается на 255 / что угодно.

https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads (Эта страница "распространенных ошибок" - золотая жила - добавьте ее в закладки сейчас!)

В более общем случае производительность glTexSubImage2D может дать вам хорошее представление о том, должна ли загрузка проходить через путь преобразования программного обеспечения. Вы должны сделать это во время запуска программы - просто создайте пустую текстуру (через glTexImage2D с данными NULL), затем выполните несколько вызовов glTexSubImage2D, каждый из которых следует за glFinish, чтобы убедиться, что она завершена. Не обращайте внимания на первый, потому что для него настраиваются кэши / состояния / и другие, а время остальное. Повторите это для нескольких разных форматов и выберите самый быстрый.

Другой вариант - если вы пометили этот вопрос как «Windows», - это создать устройство D3D при запуске (сразу после того, как вы создали окно, но перед тем, как запустить OpenGL), а затем использовать D3D для проверки поддержки формата. В то время как OpenGL допускает преобразование программного обеспечения в допустимый внутренний формат, D3D не делает этого - если это не поддерживается аппаратным обеспечением, вы не сможете это сделать. Затем уничтожьте D3D и откройте OpenGL. (Этот метод также может быть использован для запроса других вещей, которые OpenGL не позволяет вам делать запросы напрямую).

Это действительно полезное правило для перекрестной проверки того, что вы делаете в OpenGL с документацией D3D. Если D3D не может что-то сделать, это может быть хорошим признаком того, что данное устройство не поддерживается аппаратно. Не всегда правда, но полезная отправная точка.

Максимус Минимус
источник