Mengapa geometri shader ini memperlambat program saya?

27

Saya memiliki program OpenGL, dan saya sedang membuat mesh medan. Saya memindahkan simpul dalam buffer vertex dan belum benar-benar mewarnai mereka dalam fragmen shader. Saya menambahkan geometri shader satu bagian pada satu waktu.

Sebelum saya menambahkan geometri shader, ketika saya baru saja memprogram fragmen dan vertex shading step dari pipeline, saya mendapatkan framerates sekitar 30+. Cukup bahwa saya tidak bisa melihat kebodohan apa pun. Setelah menambahkan geometri shader, saya mendapatkan sekitar 5 frame per detik. Mengapa? Ini adalah keseluruhan dari shader geometri:

#version 420

layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;

void main()
{
    for (int i = 0; i < gl_in.length(); i++)
    {
        gl_Position = gl_in[i].gl_Position;
        EmitVertex();
    }
    EndPrimitive();
}

Bukankah ini tepatnya yang dilakukan OpenGL tanpa geometri shader?

Avi
sumber

Jawaban:

40

Bukankah ini tepatnya yang dilakukan OpenGL tanpa geometri shader?

Tidak. GS adalah langkah opsional , bukan langkah yang memiliki standar.

Agar OpenGL dapat menjalankan geometri shader , ia harus melakukan apa yang dikenal sebagai " perakitan primitif ". Ketika Anda membuat serangkaian segitiga melalui GL_TRIANGLE_STRIP, OpenGL akan melakukan hal-hal internal untuk mengkonversi setiap 3 simpul yang berdekatan menjadi segitiga individu, memodifikasi urutan gulungan dengan tepat.

Biasanya, ketika tidak menggunakan GS, proses ini dilakukan sekali. Namun saat Anda menggunakan GS, itu harus dilakukan sebelum GS dijalankan. Tetapi itu juga harus dilakukan setelah GS, karena GS dapat menampilkan tipe primitif yang sama sekali berbeda (misalnya paha depan).

Jadi sekarang Anda membuat sistem pada dasarnya melakukan banyak pekerjaan tambahan tanpa hasil. Lagipula, OpenGL tidak dapat mengasumsikan bahwa GS Anda tidak melakukan apa-apa (itu masalah yang tidak dapat dipastikan).

Selain itu, sejumlah optimasi tidak lagi berfungsi di hadapan GS. Pertimbangkan rendering yang diindeks.

Setiap indeks dari buffer elemen array akan menghasilkan output yang sama dari vertex shader. Jadi GPU akan sering men-cache output ini dalam cache pasca-T & L . Jika melihat indeks yang sudah ada di cache, VS tidak berjalan lagi; itu hanya mengambil data dari cache.

Apa itu"? "Itu" adalah ... unit perakitan primitif . Ya, hal yang dijalankan dua kali saat Anda menggunakan GS. Indeks barang caching? Ini hanya berfungsi untuk input dari GS.

Jadi apa yang terjadi pada output GS? Yah, itu tergantung perangkat keras. Tetapi harus masuk ke beberapa jenis buffer memori. Dan di situlah masalahnya: buffer itu tidak diindeks sama sekali. Ini seperti situasi glDrawArays.

Jadi, jika Anda mengirim buffer indeks 0, 1, 2, 0, 2, 3, ini akan diterjemahkan ke dalam 4 simpul dalam cache post-T & L. Tetapi buffer verteks post-GS sekarang memiliki 6 simpul di dalamnya. Buffer post-GS menggunakan lebih banyak ruang. Jadi, jika Anda mengalami kesulitan membuat daftar atau strip segitiga yang dioptimalkan pasca-T & L dengan benar, dan Anda membalikkan pass-through GS seperti milik Anda, Anda pada dasarnya membunuh sekitar setengah dari keuntungan kinerja Anda dari optimasi itu.

Itu tidak berguna, tetapi itu menyakitkan.

Menambah ini adalah fakta bahwa banyak GL 3.x kelas GPU (alias: DX10) memiliki buffer post-GS yang agak kecil. Semakin kecil buffer, semakin sedikit doa GS yang dapat Anda aktifkan secara bersamaan. Jadi perangkat keras Anda secara efektif menghambat GS. Karena tessellation adalah fitur besar dari perangkat keras kelas 4.x, sebagian besar perangkat keras tersebut memiliki buffer yang cukup untuk membuat penggunaan GS yang lebih berat dapat dilakukan.

Jadi menggunakan GS lebih mungkin untuk membuat pemrosesan kode titik Anda macet. Tentu saja, Anda selalu dapat menggunakannya untuk keuntungan Anda dengan membuat vertex dan fragmen shader Anda lebih kompleks, karena itu hanya kinerja gratis pada saat itu.

Untuk informasi lebih lanjut tentang perlambatan yang disebabkan GS, baca artikel ini .

Berikut ini adalah aturan dasar tentang GS: jangan pernah menggunakan GS karena Anda pikir itu akan membuat rendering lebih cepat . Anda harus menggunakannya ketika membuat apa yang Anda coba lakukan menjadi mungkin. Jika yang Anda coba lakukan adalah pengoptimalan, gunakan yang lain.

Pengecualian umum untuk ini adalah:

Nicol Bolas
sumber
Saya mencoba menghitung kecuraman setiap poligon dengan mengambil ketinggian tertinggi dan mengurangi ketinggian terendah. Namun, jika geometri shader tentu akan memperlambat saya dengan jumlah ini, saya pikir saya mungkin bisa melakukannya secara kreatif di vertex shader.
Avi
1
@ Avi mencatat bahwa titik tertinggi dan terendah dalam segitiga tidak akan memberi Anda kecuramannya; Anda membutuhkan ketiga poin.
sam hocevar
2
Secara pribadi saya selalu menemukan instancing lebih berguna untuk sprite poin daripada GS.
Maximus Minimus
1
Apakah pengecualian untuk sprite titik digeneralisasikan ke bayangan layout(points) in;? Atau apakah itu ukuran output tetap? Atau mungkin keduanya?
Philip