Apakah memodifikasi tekstur (melukis di atasnya) dianggap sebagai "perubahan keadaan"?

11

Konvensi dalam grafik adalah bahwa melakukan lebih sedikit perubahan keadaan lebih baik daripada melakukan lebih banyak perubahan negara (mengganti shader, buffer yang mengikat, tekstur yang mengikat, dll.). Untuk tekstur, lebih cepat membuat banyak poligon menggunakan atlas tunggal (untuk rendering sprite / teks) daripada secara individual mengikat tekstur baru untuk setiap poligon.

Apakah ini berlaku jika saya terus melukis ke tekstur melalui glTexSubImage2D? Saya memiliki aliran data yang masuk (melalui jaringan) yang mengalami pemrosesan dan kemudian dicat dengan tekstur satu baris setiap kali. Data disajikan secara visual dalam gulir tanpa akhir.

Apakah saya akan lebih baik melukis ke satu tekstur yang diberikan pada satu persegi panjang besar (menggulir data yang dicat ke tampilan)? Idenya di sini adalah bahwa saya akan memiliki satu (atau dua) tekstur terikat pada waktu tertentu sementara saya terus melukisnya.

Atau haruskah saya melukis banyak persegi panjang kecil (hanya mengungkapkan persegi panjang ketika lukisan sudah selesai)? Saya berasumsi saya akan mengikat satu tekstur per persegi panjang.

TheBuzzSaw
sumber

Jawaban:

11

Memperbarui area memori di perangkat grafis (tekstur, buffer, dan sejenisnya) tidak sama dengan mengubah keadaan rendering.

Apa yang membuat perubahan status render menjadi mahal adalah jumlah pekerjaan yang harus dilakukan pengemudi untuk memvalidasi keadaan baru dan memesan ulang pipa. Ini kemungkinan besar juga akan menimbulkan sinkronisasi antara CPU dan perangkat grafis. Namun, jumlah data yang ditransfer antara perangkat harus kecil untuk perubahan status (mungkin hanya beberapa perintah).

Untuk pembaruan tekstur / buffer di sisi lain, biaya utama terletak pada transfer data itu sendiri. Secara teori, kecuali jika Anda membaca data tekstur kembali ke CPU setelah pembaruan, seharusnya tidak ada sinkronisasi atau warung pipa. Namun, aspek lain harus dipertimbangkan: overhead API. Sekalipun jumlah data yang Anda kirim ke perangkat grafis kecil, jika Anda cukup sering melakukannya, pada akhirnya biaya komunikasi dengan driver / perangkat akan menjadi lebih besar daripada biaya transfer data. Itulah alasan lain mengapa batching sangat penting ketika mengoptimalkan penyaji.

Jadi dalam kasus Anda, pendekatan terbaik, menurut saya, adalah menyimpan salinan sistem-memori dari tekstur yang Anda perbarui setiap kali ada data baru. Atur bendera kotor dan gabungkan sebanyak mungkin pembaruan menjadi satu glTexSubImageuntuk seluruh tekstur (atau sebagian besar urutannya). Anda juga dapat bermain dengan Pixel Buffer Objects dan mencoba melakukan transfer data asinkron untuk mengurangi warung pipa sebanyak mungkin. Jika Anda dapat menerapkan beberapa jenis buffering ganda, maka Anda dapat menulis ke satu salinan tekstur sementara yang lainnya sedang dirender. Tutorial inimengeksplorasi skenario itu. Itu pendekatan intuitif saya, saya akan mencoba untuk mengurangi jumlah panggilan API dan "batch" pembaruan tekstur. Yang sedang berkata, ini sangat spekulatif, dan Anda harus membuat profil dan membandingkannya dengan pendekatan lain, seperti melakukan beberapa pembaruan kecil, untuk mengetahui dengan pasti mana yang paling berkinerja dalam kasus penggunaan Anda.

Sebagai catatan tambahan, presentasi oleh NVidia ini juga relevan dan memberikan banyak wawasan yang bagus: Mendekati Zero Driver Overhead di OpenGL .

Glampert
sumber
5
Saya tidak tahu pasti, tapi saya pasti akan curiga bahwa glTexSubImage pada tekstur yang telah diberikan dalam satu atau dua frame terakhir akan menunda pipa, karena driver PC sering mencoba untuk buffer satu atau dua frame, dan tidak mungkin ingin membuat salinan dari seluruh tekstur karena pembaruan kecil. Jadi saya akan mengharapkan dua atau tiga-buffering tekstur (atau objek penyangga piksel) diperlukan untuk kinerja maksimum.
John Calsbeek