Jak wykryć, które formaty tekstur OpenGL są natywnie obsługiwane?

10

Na przykład, jak wykryć, czy moja karta wideo nie obsługuje „bgr8” i przekonwertować ją na inny format, na przykład „rgba8” w trybie oprogramowania.

AKTUALIZACJA: Przepraszamy za zamieszanie. To pytanie dotyczy więcej sytuacji, gdy ustawiam format wewnętrzny w glTexImage2D na coś takiego jak „bgra8”, ale wideotelefon wewnętrznie konwertuje dane do innego formatu, na przykład „rgba8”.

KindDragon
źródło

Odpowiedzi:

11

Twoje pytanie wydaje się mylić niektóre pojęcia, więc weźmy rzeczy z góry. Oto definicja funkcji glTexImage2D:

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

Istnieją dwie rzeczy, które możesz nazwać „formatami tekstur”. Pierwszy to internalformatparametr. To jest prawdziwy format obrazu, gdy OpenGL go przechowuje. Ten formatparametr opisuje część formatu danych pikseli, które podajesz z dataparametrem.

Ujmując to w inny sposób, formati typeokreślić, co wasze spojrzenia danych podoba. internalformattak mówisz OpenGL, aby zapisywał twoje dane. Nazwijmy formati type„format transferu piksel”, zaś internalformatbędzie „Format obrazu”.

Format obrazu tekstury nigdy nie może być „bgr8”. Nie ma modułu wyliczającego format obrazu GL_BGR8. Jest to enum GL_BGR, ale to jest na formatce przelewu pikseli, a nie format obrazu.

Innymi słowy, dane w pikselach, które podajesz OpenGL, mogą być przechowywane w kolejności BGR. Ale implementacja OpenGL sama decyduje, jak faktycznie przechowywać dane pikseli. Może przechowuje to w porządku little-endian. Może przechowuje to big-endian. Może po prostu arbitralnie porządkuje bajty. Nie wiesz, a OpenGL nie zapewnia sposobu na sprawdzenie.

Nie ma sposobu, aby stwierdzić, czy określony zestaw parametrów formatu transferu pikseli pasuje do sposobu, w jaki implementacja OpenGL będzie je przechowywać, biorąc pod uwagę format obrazu.

Jest teraz sposób, aby powiedzieć. I przez „teraz” mam na myśli w OpenGL 4.3 i / lub ARB_internalformat_query2. Zbliżasz się do karty graficznej w pobliżu:

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

formata typeteraz mają preferowaną implementację formati typeużywają glTex(Sub)Imagewywołań GL_RGBA8obrazów. Istnieją osobne formati typezapytania dotyczące glReadPixelspobierania.

Istnieją inne zapytania, które możesz zadać .

Jeśli nie masz do nich dostępu, możesz zastosować ogólne zasady, których będzie przestrzegać większość sprzętu:

  • będzie przechowywać dane pikselowe dla danych 8-bit-na kanał w kolejności BGRA. Jeśli więc chcesz dopasować format do danych w pikselach, aby szybciej przesyłać dane tekstur, chcesz użyć GL_BGRAdla format, i GL_UNSIGNED_INT_8888lub GL_UNSIGNED_BYTEdla type.
  • w rzeczywistości nie będzie przechowywać 24-bitowych kolorów jako 24-bitowych. Zawsze będzie je uzupełniał do 32 bitów; alfa zostanie po prostu zignorowane podczas odczytu danych. Więc jeśli chcesz dopasować formatów, zawsze korzystać GL_BGRA formatz GL_RGB8formatów graficznych, nawet jeśli trzeba umieścić dane manekina w składowej alfa.
Nicol Bolas
źródło
4
Znalazłem również lepszy sposób użycia formatu GL_BGRA z formatem wewnętrznym GL_RGBA http.download.nvidia.com/developer/Papers/2005/…
KindDragon
Powstrzymałbym się od rebrandingu parametru InternalFormat jako „format obrazu”, ponieważ jest on równie mylący. Być może sensowne jest myślenie o „InternalFormat” jako „formacie pikseli tekstur”. Kombinacja parametrów „format” i „typ” to „format pikseli źródłowych” (który często jest obrazem, stąd mój komentarz). No i oczywiście jest format GPU, który jest BGRA dla formatów liczb całkowitych.
StarShine
6

Zasadniczo większość sprzętu nie obsługuje 3-komponentowych formatów tekstur, więc w tym konkretnym przykładzie możesz przyjąć dość bezpieczne założenie, że jest konwertowany. 3-komponentowa tekstura OpenGL jest właściwie 4-komponentowa sprzętowo, ale z komponentem alfa zignorowanym / ustawionym na 255 / cokolwiek.

https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads (Ta strona „typowych błędów” jest kopalnią złota - dodaj ją teraz do zakładek!)

W bardziej ogólnym przypadku wydajność glTexSubImage2D może dać dobre wskazanie, czy przesyłanie musi przechodzić ścieżkę konwersji oprogramowania. Poradziłbyś sobie z tym podczas uruchamiania programu - po prostu utwórz pustą teksturę (za pomocą glTexImage2D z danymi NULL), a następnie wydaj kilka wywołań glTexSubImage2D, a po każdym z nich glFinish, aby upewnić się, że się zakończy. Zignoruj ​​pierwszy, ponieważ konfigurowane są dla niego pamięci podręczne / stany / etc, a resztę czasu. Powtórz to dla kilku różnych formatów i wybierz najszybszy.

Inną alternatywą - widząc, jak otagowałeś to pytanie „Windows” - jest utworzenie urządzenia D3D podczas uruchamiania (zaraz po utworzeniu okna, ale przed uruchomieniem OpenGL), a następnie użycie D3D do sprawdzenia obsługi formatu. Podczas gdy OpenGL pozwala na konwersję oprogramowania do prawidłowego formatu wewnętrznego, D3D tego nie robi - jeśli nie jest obsługiwany przez sprzęt, nie możesz tego zrobić. Następnie zniszcz D3D i uruchom OpenGL. (Tej techniki można także użyć do zapytania o inne rzeczy, których OpenGL nie pozwala na bezpośrednie zapytania).

Przydatna jest praktyczna zasada, aby sprawdzić, co robisz w OpenGL z dokumentacją D3D. Jeśli D3D nie może czegoś zrobić, może to być dobry znak, że dana rzecz nie jest obsługiwana sprzętowo. Nie zawsze prawda, ale przydatne miejsce startowe.

Maximus Minimus
źródło