Bagaimana mendeteksi format tekstur OpenGL mana yang didukung secara asli?

10

Misalnya, bagaimana mendeteksi jika kartu video saya tidak mendukung "bgr8" dan mengubahnya ke format lain, seperti "rgba8" dalam mode perangkat lunak.

UPDATE: Maaf atas kebingungan. Pertanyaan ini lebih lanjut tentang situasi ketika saya menetapkan internalFormat di glTexImage2D untuk sesuatu seperti "bgra8" tetapi videodriver secara internal mengkonversi data ke format lain, seperti "rgba8".

KindDragon
sumber

Jawaban:

11

Pertanyaan Anda tampaknya membingungkan konsep-konsep tertentu, jadi mari kita ambil hal-hal dari atas. Ini adalah definisi fungsi glTexImage2D:

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

Ada dua hal yang Anda sebut "format tekstur". Yang pertama adalah internalformatparameter. Ini adalah format nyata dari gambar ketika OpenGL menyimpannya. The formatparameter menggambarkan bagian dari format data pixel yang Anda berikan dengan dataparameter.

Dengan kata lain, formatdan typetentukan seperti apa data Anda . internalformatadalah cara Anda memberi tahu OpenGL untuk menyimpan data Anda. Mari kita panggil formatdantype "format transfer piksel", sementara internalformatakan menjadi "format gambar".

Format gambar suatu tekstur tidak pernah bisa menjadi "bgr8". Tidak ada enumerator format gambar GL_BGR8. ada adalah sebuah enum GL_BGR, tapi itu adalah untuk format transfer pixel, bukan format gambar.

Atau dengan kata lain, data piksel Anda yang Anda berikan OpenGL dapat disimpan dalam urutan BGR. Tetapi implementasi OpenGL memutuskan sendiri bagaimana sebenarnya menyimpan data piksel itu. Mungkin menyimpannya dalam urutan little-endian. Mungkin itu menyimpannya big-endian. Mungkin itu hanya sewenang-wenang mengatur ulang byte. Anda tidak tahu, dan OpenGL tidak menyediakan cara untuk mengetahuinya.

Tidak ada cara untuk mengetahui apakah serangkaian parameter format transfer piksel cocok dengan bagaimana implementasi OpenGL akan menyimpannya dengan format gambar.

Ada cara untuk mengatakannya sekarang. Dan dengan "sekarang", maksud saya di OpenGL 4.3 dan / atau ARB_internalformat_query2. Datang ke kartu grafis di dekat Anda:

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

formatdan typesekarang memiliki implementasi yang disukai formatdan typeuntuk menggunakan glTex(Sub)Imagepanggilan ke GL_RGBA8gambar. Ada pertanyaan formatdan terpisah typeuntukglReadPixels unduhan.

Ada pertanyaan lain yang bisa Anda buat .

Jika Anda tidak memiliki akses ke ini, Anda dapat menggunakan beberapa aturan umum yang dipatuhi oleh sebagian besar perangkat keras:

  • akan menyimpan data piksel untuk data 8-bit-per-saluran dalam urutan BGRA. Jadi jika Anda ingin mencocokkan format dengan data piksel Anda, sehingga untuk lebih cepat mengunggah data tekstur, Anda ingin menggunakan GL_BGRAuntuk format, dan GL_UNSIGNED_INT_8888atau GL_UNSIGNED_BYTEuntuktype .
  • tidak akan benar-benar menyimpan warna 24-bit sebagai 24-bit. Itu akan selalu membuat mereka menjadi 32-bit; alpha hanya akan diabaikan ketika membaca data. Jadi jika Anda ingin mencocokkan format, selalu gunakan GL_BGRA formatdengan GL_RGB8format gambar, bahkan jika Anda harus meletakkan data dummy dalam komponen alfa.
Nicol Bolas
sumber
4
Saya menemukan juga lebih baik menggunakan format GL_BGRA dengan internalFormat GL_RGBA http.download.nvidia.com/developer/Papers/2005/…
KindDragon
Saya akan menahan diri dari rebranding parameter internalFormat sebagai "format gambar", karena sama-sama membingungkan. Mungkin masuk akal untuk menganggap "internalFormat" sebagai "format piksel tekstur". Kombinasi parameter "format" dan "tipe" adalah "format piksel sumber" (yang sering berupa gambar, karenanya komentar saya). Dan tentu saja ada format GPU, yaitu BGRA untuk format tipe integer.
StarShine
6

Umumnya sebagian besar perangkat keras tidak mendukung format tekstur 3-komponen sehingga dalam contoh khusus ini Anda dapat membuat asumsi yang cukup aman bahwa itu dikonversi. Tekstur OpenGL 3 komponen sebenarnya 4 komponen dalam perangkat keras tetapi dengan komponen alfa diabaikan / diatur ke 255 / apa pun.

https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_upload_and_pixel_reads (Halaman "kesalahan umum" itu adalah tambang emas - buat bookmark sekarang!)

Untuk kasus yang lebih umum, kinerja glTexSubImage2D dapat memberi Anda indikasi yang baik apakah pengunggahan harus melalui jalur konversi perangkat lunak atau tidak. Anda akan melakukan ini selama startup program - cukup buat tekstur kosong (via glTexImage2D dengan data NULL), lalu keluarkan sekelompok panggilan glTexSubImage2D, masing-masing diikuti oleh glFinish untuk memastikannya selesai. Abaikan yang pertama karena cache / status / etc sedang disiapkan untuk itu, dan waktunya sisanya. Ulangi ini untuk beberapa format berbeda dan pilih yang tercepat.

Alternatif lain - mengingat Anda telah menandai pertanyaan ini "Windows" - adalah membuat perangkat D3D saat startup (tepat setelah Anda membuat jendela tetapi sebelum Anda init OpenGL) kemudian gunakan D3D untuk memeriksa dukungan format. Sementara OpenGL memungkinkan konversi perangkat lunak ke format internal yang valid, D3D tidak - jika itu tidak didukung oleh perangkat keras Anda tidak dapat melakukannya. Kemudian hancurkan D3D dan bawa OpenGL. (Teknik ini juga dapat digunakan untuk menanyakan hal-hal lain yang tidak memungkinkan OpenGL meminta Anda secara langsung).

Sebenarnya ini adalah aturan praktis yang berguna untuk memeriksa ulang apa yang Anda lakukan di OpenGL dengan dokumentasi D3D. Jika D3D tidak dapat melakukan sesuatu maka itu bisa menjadi indikasi yang baik bahwa sesuatu yang dimaksud tidak didukung dalam perangkat keras. Tidak selalu benar, tetapi tempat awal yang bermanfaat.

Maximus Minimus
sumber