¿Cómo detectar qué formatos de textura OpenGL son compatibles de forma nativa?

10

Por ejemplo, cómo detectar si mi tarjeta de video no es compatible con "bgr8" y convertirla a otro formato, como "rgba8" en modo software.

ACTUALIZACIÓN: Perdón por la confusión. Esta pregunta es más acerca de la situación cuando configuro internalFormat en glTexImage2D a algo así como "bgra8" pero el controlador de video internamente convierte los datos a otro formato, como "rgba8".

TipoDragon
fuente

Respuestas:

11

Su pregunta parece confundir ciertos conceptos, así que tomemos las cosas desde arriba. Esta es la definición de la función glTexImage2D:

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

Hay dos cosas que podría llamar "formatos de textura". El primero es el internalformatparámetro. Este es el formato real de la imagen a medida que OpenGL la almacena. El formatparámetro describe parte del formato de los datos de píxeles que proporciona con el dataparámetro.

Para decirlo de otra manera, formaty typedefinir cómo se ven sus datos. internalformatasí es como le estás diciendo a OpenGL que almacene tus datos. Llamemos formaty typeel "formato de transferencia de píxeles", mientras internalformatque será el "formato de imagen".

El formato de imagen de una textura nunca puede ser "bgr8". No hay un enumerador de formato de imagen GL_BGR8. No es una enumeración GL_BGR, pero eso es para el formato de transferencia de píxeles, no el formato de imagen.

O para decirlo de otra manera, sus datos de píxeles que le da a OpenGL pueden almacenarse en orden BGR. Pero la implementación de OpenGL decide por sí misma cómo almacenar esos datos de píxeles. Tal vez lo almacena en orden little-endian. Tal vez lo almacena big-endian. Tal vez solo reorganiza arbitrariamente los bytes. No lo sabe, y OpenGL no proporciona una forma de averiguarlo.

No hay forma de saber si un conjunto particular de parámetros de formato de transferencia de píxeles coincide con cómo la implementación de OpenGL los almacenará dado el formato de imagen.

Hay una manera de saberlo ahora. Y por "ahora", quiero decir en OpenGL 4.3 y / o ARB_internalformat_query2. Llegando a una tarjeta gráfica cerca de usted:

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);

formaty typeahora tiene la implementación preferida formaty typepara usar glTex(Sub)Imagellamadas a GL_RGBA8imágenes. Hay consultas separadas formaty typepara glReadPixelsdescargas.

Hay otras consultas que puede hacer .

Si no tiene acceso a estos, puede usar algunas reglas generales a las que se adherirá la mayoría del hardware:

  • almacenará datos de píxeles para datos de 8 bits por canal en orden BGRA. Por lo tanto, si desea hacer coincidir el formato con sus datos de píxeles, a fin de cargar más rápidamente los datos de textura, desea usarlos GL_BGRApara format, GL_UNSIGNED_INT_8888o GL_UNSIGNED_BYTEpara type.
  • en realidad no almacenará colores de 24 bits como 24 bits. Siempre los rellenará a 32 bits; el alfa solo será ignorado cuando lea los datos. Por lo tanto, si desea hacer coincidir formatos, use siempre GL_BGRA formatcon GL_RGB8formatos de imagen, incluso si tiene que poner datos ficticios en el componente alfa.
Nicol Bolas
fuente
44
También encontré un mejor formato de uso GL_BGRA con internalFormat GL_RGBA http.download.nvidia.com/developer/Papers/2005/…
KindDragon
Me abstendría de cambiar el nombre del parámetro internalFormat como "formato de imagen", porque es igualmente confuso. Quizás tenga sentido pensar en "internalFormat" como el "formato de píxeles de textura". La combinación de parámetros "formato" y "tipo" son el "formato de píxel de origen" (que a menudo es una imagen, de ahí mi comentario). Y luego, por supuesto, está el formato GPU, que es BGRA para formatos de tipo entero.
StarShine
6

En general, la mayoría del hardware no admite formatos de textura de 3 componentes, por lo que en este ejemplo específico puede hacer una suposición razonablemente segura de que está convertido. Una textura OpenGL de 3 componentes es en realidad de 4 componentes en hardware pero con el componente alfa ignorado / configurado en 255 / lo que sea.

https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads (Esa página de "errores comunes" es una mina de oro - ¡márquela ahora!)

Para un caso más general, el rendimiento de glTexSubImage2D puede darle una buena indicación de si la carga debe pasar por una ruta de conversión de software. Debería hacer esto durante el inicio del programa: simplemente cree una textura vacía (a través de glTexImage2D con datos NULOS), luego emita un montón de llamadas glTexSubImage2D, cada una seguida de un glFinish para asegurarse de que se complete. Ignora el primero porque se están configurando cachés / estados / etc. para ello, y cronometra el resto de ellos. Repita esto para algunos formatos diferentes y elija el más rápido.

Otra alternativa, ya que ha etiquetado esta pregunta como "Windows", es crear un dispositivo D3D al inicio (justo después de haber creado su ventana pero antes de iniciar OpenGL) y luego usar D3D para verificar la compatibilidad con el formato. Si bien OpenGL permite la conversión de software a un formato interno válido, D3D no lo hace; si el hardware no lo admite, no puede hacerlo. Luego destruya D3D y abra OpenGL. (Esta técnica también se puede utilizar para consultar otras cosas que OpenGL no le permite consultar directamente).

En realidad, es una regla práctica útil verificar lo que está haciendo en OpenGL con la documentación de D3D. Si D3D no puede hacer algo, puede ser una buena indicación de que el hardware en cuestión no es compatible. No siempre es cierto, pero es un punto de partida útil.

Maximus Minimus
fuente