Berapa lama bagi OpenGL untuk benar-benar memperbarui layar?

9

Saya memiliki aplikasi uji OpenGL sederhana dalam C yang menggambar berbagai hal sebagai respons terhadap input kunci. (Mesa 8.0.4, dicoba dengan Mesa-EGL dan dengan GLFW, Ubuntu 12.04LTS pada PC dengan NVIDIA GTX650). Gambarnya cukup sederhana / cepat (rotating triangle stuff of stuff). Kode pengujian saya tidak membatasi framerate dengan cara apa pun, hanya terlihat seperti ini:

while (true)
{
    draw();
    swap_buffers();
}

Saya telah menghitung waktu ini dengan sangat cermat, dan saya menemukan bahwa waktu dari satu eglSwapBuffers()(atau glfwSwapBuffers, hal yang sama) panggilan ke yang berikutnya adalah ~ 16,6 milidetik. Waktu dari setelah panggilan ke eglSwapBuffers()sebelum panggilan berikutnya hanya sedikit kurang dari itu, meskipun apa yang diambil sangat sederhana. Waktu yang dibutuhkan panggilan swap buffer berada di bawah 1ms.

Namun, waktu dari aplikasi mengubah apa yang digambarkan sebagai respons terhadap penekanan tombol terhadap perubahan yang sebenarnya muncul di layar adalah> 150ms (sekitar 8-9 nilai bingkai). Ini diukur dengan rekaman kamera dari layar dan keyboard pada 60fps.

Karena itu, pertanyaannya:

  1. Di mana drawed buffered antara panggilan untuk swap buffer dan benar-benar muncul di layar? Kenapa ditunda? Tampaknya aplikasi ini menggambar banyak bingkai di depan layar setiap saat.

  2. Apa yang dapat dilakukan aplikasi OpenGL untuk menyebabkan undian langsung ke layar? (Yaitu: tidak ada buffering, cukup blok sampai draw selesai; Saya tidak perlu throughput tinggi, saya perlu latensi rendah)

  3. Apa yang bisa dilakukan aplikasi untuk membuat penarikan langsung di atas secepat mungkin?

  4. Bagaimana aplikasi mengetahui apa yang sebenarnya ada di layar sekarang? (Atau, berapa lama / berapa banyak frame penundaan buffering saat ini?)

Alex I
sumber
Bisakah Anda memisahkan waktu yang diperlukan keyboard untuk memberi tahu aplikasi Anda dengan waktu yang diperlukan untuk membuatnya?
ThorinII
@ TuminII: Poin yang adil. Saya mungkin dapat mengatur sesuatu yang hacky menggunakan LED pada port paralel dll untuk mendapatkan indikasi kapan aplikasi benar-benar mendapatkan penekanan tombol. Tetap saja, itu hanya fgetc (stdin), seberapa lambat itu? : /
Alex I
Saya mendapat kesan bahwa glFlush digunakan untuk segera menghapus semua perintah.
Programmdude
1
@AlexI memeriksa gamedev.stackexchange.com/questions/66543/… ini dapat membantu Anda
concept3d
1
@ concept3d: Ya, pada dasarnya dijawab, hanya berpikir Anda ingin beberapa rep ekstra :) Rupanya saya harus menunggu sehari untuk menghadiahkannya.
Alex I

Jawaban:

6

Setiap fungsi menggambar API yang dipanggil dari CPU akan dikirimkan ke buffer cincin perintah GPU untuk dieksekusi nanti oleh GPU. Ini berarti bahwa fungsi OpenGL sebagian besar adalah fungsi non-blocking. Jadi CPU dan GPU akan bekerja secara paralel.

Yang paling penting untuk diperhatikan adalah aplikasi Anda bisa terikat CPU atau GPU. setelah Anda memanggil glFinish, CPU harus menunggu GPU untuk menyelesaikan perintah menggambarnya, jika GPU membutuhkan lebih banyak waktu dan dapat menyebabkan CPU berhenti maka aplikasi Anda terikat GPU. Jika GPU selesai menggambar perintah dan CPU terlalu lama untuk glFinish maka aplikasi Anda terikat CPU.

Dan perhatikan bahwa ada perbedaan antara glFlushdan glFinish.

glFlush: menunjukkan bahwa semua perintah yang sebelumnya telah dikirim ke GL harus diselesaikan dalam waktu yang terbatas.

glFinish: memaksa semua perintah GL sebelumnya untuk menyelesaikan. Selesai tidak kembali sampai semua efek dari perintah yang dikeluarkan sebelumnya pada klien GL dan keadaan server dan framebuffer sepenuhnya direalisasikan. "

glXSwapBuffers melakukan glFlush implisit sebelum kembali. Perintah OpenGL berikutnya dapat dikeluarkan segera setelah memanggil glXSwapBuffers, tetapi tidak dieksekusi sampai pertukaran buffer selesai.

Kerangka waktu yang sebenarnya kemungkinan besar akan ditentukan oleh mana dari dua CPU / GPU ini mengambil lebih banyak waktu untuk menyelesaikan pekerjaannya.

concept3d
sumber
Ini sangat membantu. Beberapa kemungkinan koreksi: opengl.org/sdk/docs/man2/xhtml/glXSwapBuffers.xml "glXSwapBuffers melakukan glFlush implisit sebelum kembali" sepertinya ini tidak benar-benar melakukan glFinish, sehingga perintah buffer dapat memiliki cukup banyak barang di dalamnya ketika swap buffer kembali.
Alex I
... Juga, saya pikir hal yang paling menarik adalah bahwa aplikasi pengujian saya yang sangat sederhana bukanlah CPU atau GPU terbatas - tidak ada banyak pekerjaan yang harus dilakukan di sini - tetapi sesuatu yang lain, entah bagaimana berakhir dengan framerate rendah (persis sama dengan monitor refresh rate ??) dan latency tinggi (karena buffer perintah, sebenarnya Anda menjelaskan bagian itu dengan cukup baik).
Alex I
@AlexI both low framerate (exactly same as monitor refresh rate??tidak, kecuali jika Anda secara eksplisit menggunakan VSync.
concept3d
@AlexI Saya juga ingin menunjukkan bahwa waktu bingkai berbeda dari FPS, gunakan waktu bingkai untuk profil aplikasi Anda karena itu linear. FPS di sisi lain adalah pengukuran yang buruk yang tidak linier.
concept3d
Saya tidak secara eksplisit menggunakan vsync. Saya tidak melakukan apa-apa untuk mengubah pengaturan vsync defauls, saya bahkan tidak tahu di mana harus mengubahnya di OpenGL. Saya hanya mendapatkan 60fps (dalam persen).
Alex I
4

OpenGL tidak pernah memperbarui layar, secara teknis.

Ada sistem API jendela yang terpisah dari GL (misalnya GLX, WGL, CGL, EGL) yang melakukan ini. Buffer swap menggunakan API ini umumnya secara implisit meminta glFlush (...)tetapi dalam beberapa implementasi (misalnya rasterizer GDI pada Windows) ia melakukan penuh glFinish (...):

 

    * Di sisi kiri, adalah jalur ICD (perangkat keras) SwapBuffers (...). Di sisi kanan, jalur GDI (perangkat lunak).

Jika Anda mengaktifkan VSYNC dan buffer ganda, maka perintah apa pun yang akan memodifikasi back buffer sebelum terjadi swap yang tertunda harus berhenti hingga swap. Ada kedalaman terbatas pada antrian perintah, jadi perintah yang macet ini pada akhirnya akan menyebabkan kemacetan di dalam pipa. Ini bisa berarti bahwa alih-alih memblokir SwapBuffers (...)aplikasi Anda sebenarnya memblokir beberapa perintah GL yang tidak terkait sampai VBLANK berputar. Apa yang sebenarnya menjadi intinya adalah berapa banyak buffer yang Anda miliki dalam rantai swap Anda.

Selama semua buffer belakang penuh dengan frame jadi yang belum dipindahkan ke depan, swap buffer secara implisit akan menyebabkan pemblokiran. Sayangnya, tidak ada cara untuk secara eksplisit mengontrol jumlah buffer belakang yang digunakan oleh sebagian besar API sistem jendela GL (selain 0 buffer tunggal atau 1 buffer ganda). Pengemudi bebas menggunakan 2 buffer belakang jika diinginkan (triple buffering), tetapi Anda tidak dapat meminta ini pada tingkat aplikasi menggunakan sesuatu seperti GLX atau WGL.

Andon M. Coleman
sumber
Andon: Info bagus, terima kasih. Saya pikir apa yang saya lihat adalah buffering ganda, tetapi: "usaha untuk memodifikasi back buffer sebelum swap terjadi harus diblokir" - mengapa? sepertinya semuanya bisa dikirim ke buffer perintah, termasuk swap :)
Alex I
"Secara eksplisit mengontrol jumlah buffer belakang yang digunakan oleh sebagian besar API sistem jendela GL (selain dari 0 buffer-tunggal atau 1 buffer-ganda)" - bagaimana seseorang mengontrol buffer tunggal / ganda?
Alex I
@AlexI: Saya mengklarifikasi bahasa sehubungan dengan mengapa perintah dapat menyebabkan pemblokiran. Di API lain ada konsep yang dikenal sebagai render-ahead, yang secara efektif adalah kedalaman antrian perintah. Adapun untuk mengendalikan buffer tunggal / ganda, yang dikendalikan oleh format piksel yang Anda pilih saat Anda membuat konteks render Anda. Di WGL, Anda dapat memilih buffer tunggal atau ganda, tetapi jika Anda memilih buffer ganda, sebenarnya driver tersebut dapat membuat 2 buffer belakang (sehingga buffer ganda menjadi buffering tiga) jika pengguna mengatur driver mereka untuk melakukan ini.
Andon M. Coleman
Anda sebenarnya tidak ingin membuat terlalu banyak bingkai di depan karena sementara ini akan mengurangi pemblokiran, itu juga meningkatkan latensi. Cara terbaik untuk meminimalkan latensi sebenarnya adalah memohon glFinish (...)segera setelah menukar buffer. Ini akan menghapus antrian perintah, tetapi itu juga berarti bahwa GPU dan CPU akan disinkronkan (yang tidak baik jika Anda ingin menjaga GPU tetap bekerja setiap saat).
Andon M. Coleman
1

Saya menganggap Anda terbiasa dengan eksperimen ini ?

Pada dasarnya John Carmack melakukan sesuatu yang serupa, merekam layar dan timing pixel yang dikirim ke layar. Dia menemukan bahwa banyak latensi datang dari layar. Faktor lainnya adalah keterlambatan input dari keyboard, driver video dan atau tentu saja pelaksanaan program itu sendiri.

MichaelHouse
sumber