Mendapatkan jumlah fragmen yang lolos uji kedalaman

8

Di lingkungan "modern", ekstensi "NV Occlusion Query" menyediakan metode untuk mendapatkan jumlah fragmen yang lulus uji kedalaman. Namun, pada iPad / iPhone menggunakan OpenGL ES, ekstensi tidak tersedia.

Apa pendekatan yang paling berkinerja untuk menerapkan perilaku serupa di fragmen shader?

Beberapa ide saya:

  • Render objek sepenuhnya putih, kemudian hitung semua warna bersama-sama menggunakan shader dua-pass di mana pertama garis vertikal diberikan dan untuk setiap fragmen shader menghitung jumlah di seluruh baris. Kemudian, sebuah simpul tunggal diberikan yang fragmennya menjumlahkan semua jumlah parsial dari pass pertama. Sepertinya tidak terlalu efisien.

  • Jadikan objek sepenuhnya putih di atas latar belakang hitam. Turunkan sampel secara rekursif, menyalahgunakan interpolasi linier perangkat keras di antara tekstur hingga mencapai resolusi yang cukup kecil. Ini mengarah ke fragmen yang memiliki tingkat skala abu-abu tergantung pada jumlah piksel putih di mana di wilayah yang sesuai. Apakah ini cukup akurat?

  • Gunakan mipmaps dan cukup baca piksel pada level 1x1. Lagi-lagi pertanyaan tentang keakuratan dan apakah mungkin menggunakan tekstur non-kekuatan-dua.

Masalahnya dengan pendekatan ini adalah, bahwa pipa akan macet yang menghasilkan masalah kinerja utama. Karena itu, saya mencari cara yang lebih baik untuk mencapai tujuan saya.

Menggunakan ekstensi EXT_OCCLUSION_QUERY_BOOLEAN

Apple memperkenalkan EXT_OCCLUSION_QUERY_BOOLEAN di iOS 5.0 untuk iPad 2.

"4.1.6  Occlusion Queries

Occlusion queries use query objects to track the number of fragments or 
samples that pass the depth test. An occlusion query can be started and 
finished by calling BeginQueryEXT and EndQueryEXT, respectively, with a 
target of ANY_SAMPLES_PASSED_EXT or ANY_SAMPLES_PASSED_CONSERVATIVE_EXT.

When an occlusion query is started with the target 
ANY_SAMPLES_PASSED_EXT, the samples-boolean state maintained by the GL is
set to FALSE. While that occlusion query is active, the samples-boolean 
state is set to TRUE if any fragment or sample passes the depth test. When 
the occlusion query finishes, the samples-boolean state of FALSE or TRUE is
written to the corresponding query object as the query result value, and 
the query result for that object is marked as available. If the target of 
the query is ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, an implementation may 
choose to use a less precise version of the test which can additionally set
the samples-boolean state to TRUE in some other implementation dependent 
cases."

Kalimat pertama mengisyaratkan perilaku yang persis seperti yang saya cari: mendapatkan jumlah piksel yang lulus uji kedalaman secara asinkron tanpa kehilangan banyak kinerja. Namun, sisa dokumen hanya menjelaskan cara mendapatkan hasil boolean.

Apakah mungkin untuk mengeksploitasi ekstensi ini untuk mendapatkan jumlah piksel? Apakah perangkat keras mendukungnya sehingga mungkin ada API tersembunyi untuk mendapatkan akses ke jumlah piksel?

Ekstensi lain yang dapat dieksploitasi adalah fitur debugging seperti berapa kali shader fragmen dipanggil (PSInvocations di DirectX - tidak yakin apakah sesuatu simila tersedia di OpenGL ES). Namun, ini juga akan menghasilkan warung pipa.

Etan
sumber
Apa efek akhirnya yang ingin Anda capai?
Tetrad
Saya perlu jumlah piksel bukan untuk efek render, tetapi untuk perhitungan. Saya ingin menggunakannya untuk menghitung bobot partikel dalam filter partikel.
Etan
Apakah apel mendukung AMD_performance_monitor? Jika ya, Anda mungkin dapat menemukan penghitung yang menunjukkan piksel yang lewat. Perhatikan bahwa ini sangat, sangat spesifik perangkat, bahkan jika Anda membuatnya berfungsi.
Jari Komppa
Masalah dengan AMD_performance_monitor adalah tidak asinkron, sehingga kehilangan kinerja juga akan ada karena saya harus menunggu di antara frame untuk mengetahui bahwa pemanggilan dari frame berikutnya tidak akan berpengaruh pada penghitung kinerja yang sudah ada.
Etan
Juga, AMD_performance_monitor tidak tersedia.
Etan

Jawaban:

1

Apakah mungkin untuk mengeksploitasi ekstensi ini untuk mendapatkan jumlah piksel? Apakah perangkat keras mendukungnya sehingga mungkin ada API tersembunyi untuk mendapatkan akses ke jumlah piksel?

Tidak, dan tidak. Yah, saya kira jika Anda menggambar serangkaian segitiga berukuran satu piksel di ruang jendela, Anda bisa menghitung berapa banyak nilai boolean yang Anda dapatkan. Tetapi itu akan membutuhkan permintaan terpisah untuk masing-masing satu piksel. Mungkin bukan yang tercepat di dunia.

Jika ada "API tersembunyi", Anda tidak akan memiliki akses ke sana (karena disembunyikan), jadi itu tidak masalah. Selain itu, sifat ekstensi sudah menunjukkan bahwa tidak ada. Lagi pula, jika perangkat keras memiliki jumlah fragmen yang sebenarnya, mengapa tidak langsung mengeksposnya, seperti yang dilakukan desktop OpenGL? Jika perangkat keras mendukungnya, mereka bisa saja mengambil ARB_occlusion_query dan menggunakannya.

Tetapi mereka tidak melakukannya. Yang sangat menyarankan bahwa mereka tidak bisa.

Nicol Bolas
sumber
Terima kasih atas jawabannya! Pendekatan dengan segitiga berukuran satu piksel dapat ditingkatkan dengan hanya memberikan titik atau garis kecil, dan bahkan dapat ditingkatkan dengan penskalaan logaritmik di mana garis yang mengembalikan "true" cukup dibagi di tengah dan kemudian kedua bagian diperiksa lagi. Belum yakin tentang kinerja karena model tidak akan memiliki lebih dari 100-200 simpul. Alasan untuk tidak adanya "API tersembunyi" juga valid. Apakah ada cara lain untuk mendapatkan data dari GPU kembali ke CPU secara asinkron tanpa pipa saluran (silakan juga cara hacky)?
Etan
0

Hasilnya dikembalikan dalam GLuint, (juga bisa GLint untuk panggilan yang berbeda) sayangnya, hasilnya selalu 0 atau 1, mungkin mereka akan mengubahnya untuk mendaftarkan frag di masa depan.

juga sepertinya tidak ada satu orang pun di seluruh internet telah memposting tentang ekstensi baru ini ... jadi di sini mereka diatur dengan benar ... yang tidak didokumentasikan di mana pun sejauh yang saya tahu ... Anda dapat membayangkan bagaimana mereka akan masuk dalam kode Anda dari kode sudo kecil ini di sini:

import UIKit/UIKit.h

import GLKit/GLKit.h

import "GLProgram.h"

GLuint testBox,hasBeenTested,theParams;

//...

glGenQueriesEXT(1, &testBox);

glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, testBox);


//... draw an object .......

glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);

glGetQueryObjectuivEXT(testBox, GL_QUERY_RESULT_AVAILABLE_EXT, &hasBeenTested);

if (hasBeenTested) glGetQueryObjectuivEXT(testBox, GL_QUERY_RESULT_EXT, &theParams);

glDeleteQueriesEXT(1, &testBox);

if (!theParams)  object is hidden;  don't draw next time;
honjj
sumber
Hanya karena jenisnya GLinttidak berarti itu adalah bilangan bulat dari jumlah fragmen yang lewat. Spesifikasinya cukup jelas bahwa QUERY_RESULT_EXTnegara adalah nilai boolean; Anda hanya menanyakannya sebagai bilangan bulat. Itu GL_FALSEjika gagal dan tidak GL_FALSEjika berlalu.
Nicol Bolas
Saya baru saja mengimplementasikan kode dan menemukan itu hanya benar atau salah dan mengubah jawaban saya sebelum saya melihat komentar Anda ... karena itu adalah gluint, mungkin mereka akan menambahkan status di masa depan semoga.
honjj
omong-omong, tampaknya ada bug di GKKit, di mana jika Anda menggunakan self.effect2 = [[GLKBaseEffectokasikan] init]; jenis GLKit jenis kode untuk merender objek, daripada pipa GLES2.0 normal, kueri akan gagal memberikan jawaban yang benar ... (tidak pernah disembunyikan) meskipun saya menguji objek pipa menyembunyikan objek GLKBaseEffect, sehingga bisa jadi ada bug yang hanya mencampur keduanya, saya belum menguji lebih lanjut ...
honjj
Ekstensi dijelaskan dengan contoh-contoh dalam video WWDC yang dapat ditemukan di situs Apel dengan akun pengembang aktif.
Etan