Como detectar quais formatos de textura OpenGL são suportados nativamente?

10

Por exemplo, como detectar se minha placa de vídeo não suporta "bgr8" e convertê-la para outro formato, como "rgba8" no modo de software.

ATUALIZAÇÃO: Desculpe pela confusão. Esta pergunta é mais sobre a situação quando defino internalFormat no glTexImage2D para algo como "bgra8", mas o videodriver converte internamente os dados para outro formato, como "rgba8".

KindDragon
fonte

Respostas:

11

Sua pergunta parece confundir certos conceitos, então vamos pegar as coisas de cima. Esta é a definição da função glTexImage2D:

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

Há duas coisas que você pode chamar de "formatos de textura". O primeiro é o internalformatparâmetro Este é o formato real da imagem quando o OpenGL a armazena. O formatparâmetro descreve parte do formato dos dados de pixel que você está fornecendo com o dataparâmetro

Em outras palavras, formate typedefina a aparência dos seus dados. internalformaté assim que você está dizendo ao OpenGL para armazenar seus dados. Vamos chamar formate typeo "formato de transferência de pixels", enquanto internalformatserá o "formato de imagem".

O formato da imagem de uma textura nunca pode ser "bgr8". Não há enumerador de formato de imagem GL_BGR8. Não é um enum GL_BGR, mas isso é para o formato de transferência de pixel, não o formato de imagem.

Ou, dito de outra forma, os dados de pixel que você fornece ao OpenGL podem ser armazenados na ordem BGR. Mas a implementação do OpenGL decide por si própria como realmente armazenar esses dados de pixel. Talvez o armazene em ordem little-endian. Talvez ele armazene big-endian. Talvez apenas reorganize arbitrariamente os bytes. Você não sabe, e o OpenGL não fornece uma maneira de descobrir.

Não há como saber se um conjunto específico de parâmetros do formato de transferência de pixels corresponde a como a implementação do OpenGL os armazenará, dado o formato da imagem.

Existe uma maneira de dizer agora. E por "agora", quero dizer no OpenGL 4.3 e / ou ARB_internalformat_query2. Chegando a uma placa gráfica perto de você:

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

formate typeagora tenha a implementação preferida formate typepara usar glTex(Sub)Imagechamadas para GL_RGBA8imagens. Existem consultas formate downloads separados .typeglReadPixels

Existem outras consultas que você pode fazer .

Se você não tiver acesso a eles, poderá usar algumas regras gerais que a maioria dos hardwares seguirá:

  • armazenará dados de pixel para dados de 8 bits por canal na ordem BGRA. Portanto, se você deseja combinar o formato com os dados de pixel, para carregar mais rapidamente os dados de textura, você deseja usar GL_BGRApara formate / GL_UNSIGNED_INT_8888ou GL_UNSIGNED_BYTEpara type.
  • na verdade, não armazenará cores de 24 bits como 24 bits. Ele sempre aumentará para 32 bits; o alfa será ignorado apenas quando ler os dados. Portanto, se você deseja combinar formatos, sempre use GL_BGRA formatcom GL_RGB8formatos de imagem, mesmo que seja necessário inserir dados fictícios no componente alfa.
Nicol Bolas
fonte
4
Eu também achei melhor usar o formato GL_BGRA com internalFormat GL_RGBA http.download.nvidia.com/developer/Papers/2005/…
KindDragon
Eu evitaria renomear o parâmetro internalFormat como "formato de imagem", porque é igualmente confuso. Talvez faça sentido pensar em "internalFormat" como o "formato de pixel de textura". A combinação de parâmetros "formato" e "tipo" é o "formato de pixel de origem" (que geralmente é uma imagem, daí meu comentário). E, claro, existe o formato GPU, que é BGRA para formatos de tipo inteiro.
StarShine
6

Geralmente, a maioria dos hardwares não suporta formatos de textura de três componentes; portanto, neste exemplo específico, você pode supor com segurança que ele foi convertido. Uma textura OpenGL de 3 componentes é na verdade de 4 componentes no hardware, mas com o componente alfa ignorado / definido como 255 / o que for.

https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads (Essa página de "erros comuns" é uma mina de ouro - marque-a agora!)

Para um caso mais geral, o desempenho do glTexSubImage2D pode fornecer uma boa indicação sobre se o upload deve ou não passar por um caminho de conversão de software. Você faria isso durante a inicialização do programa - basta criar uma textura vazia (via glTexImage2D com dados NULL) e emitir um monte de chamadas glTexSubImage2D, cada uma seguida por um glFinish para garantir a conclusão. Ignore o primeiro porque os caches / estados / etc estão sendo configurados para ele e cronometre o restante deles. Repita isso para alguns formatos diferentes e escolha o mais rápido.

Outra alternativa - como você marcou esta pergunta como "Windows" - é criar um dispositivo D3D na inicialização (logo após criar sua janela, mas antes de iniciar o OpenGL) e usar o D3D para verificar o suporte ao formato. Enquanto o OpenGL permite a conversão de software para um formato interno válido, o D3D não - se não for suportado pelo hardware, você não poderá fazê-lo. Em seguida, destrua o D3D e abra o OpenGL. (Essa técnica também pode ser usada para consultar outras coisas que o OpenGL não permite consultar diretamente).

Na verdade, é uma regra útil verificar o que você está fazendo no OpenGL com a documentação do D3D. Se o D3D não puder fazer algo, pode ser uma boa indicação de que o algo em questão não é suportado no hardware. Nem sempre é verdade, mas um ponto de partida útil.

Maximus Minimus
fonte