GLSL - Mendeklarasikan variabel global di luar lingkup fungsi utama

12

Apakah itu membantu untuk mendeklarasikan variabel di luar lingkup fungsi utama Anda di GLSL? Apakah variabel-variabel ini benar-benar digunakan kembali dan lebih efisien?

Berikut ini kode yang dimaksud:

varying vec2 vposition;
uniform float seed;
uniform float top;
uniform float bottom;
uniform float phi;
uniform float theta;
uniform float scaledPI;
uniform float yn;
uniform float ym;
uniform float rx;
uniform float ry;
uniform float radius;

const float PI = 3.141592653589793238462643383;

float left;
float right;
float mscaled;
float xn;
float xm;
void main() {
    float t = vposition.y * yn + ym;

    if(t <= 0.0 || t >= PI){
        left = phi - PI;
        right = phi + PI;
    }else{
        mscaled = scaledPI / (1 - abs(Math.cos(theta)));
        mscaled = mscaled < PI ? mscaled : PI;
        left = phi - mscaled;
        right = phi + mscaled;
    }
    xn = (left - right) / ((-rx / 2.0) - (rx / 2.0));
    xm = left - ((-rx/2.0) * xn);
    float p = vposition.x * xn + xm;

    vec3 coords = vec3( sin(p) * sin(t), cos(t), cos(p) * sin(t) );
    float nv = surface( vec4( coords, seed ) );
    gl_FragColor = vec4( vec3( nv, nv, nv ), 1.0 );
}
RodgerDodger
sumber
3
Pertanyaan ini membingungkan. GLSL tidak memiliki loop utama. Apakah maksud Anda main()fungsinya? Apakah nilai Anda sebenarnya variabel global (seragam atau atribut dalam bahasa GLSL) atau nilai konstan?
Sean Middleditch
Bisakah Anda memposting beberapa kode sebagai contoh dari apa yang Anda bicarakan?
Nathan Reed
Saya memperbarui pertanyaan dengan kode.
RodgerDodger
@ user1286792: Itu tidak mengubah fakta bahwa GLSL tidak memiliki loop utama . Tidak jelas apa yang Anda bicarakan. Apa yang sebenarnya Anda pikirkan akan diselamatkan dengan melakukan ini?
Nicol Bolas
@NicolBolas Saya telah memperbarui pertanyaan agar lebih jelas. Semoga bermanfaat bagi seseorang di masa depan.
RodgerDodger

Jawaban:

33

Saya pikir saya mendapatkan apa yang Anda coba tanyakan. Saya menganggap perhatian utama Anda adalah variabel tidak seragam yang didefinisikan di luar main():

float left;
float right;
float mscaled;
float xn;
float xm;

Mari kita lihat bagaimana GPU dan GLSL bekerja. GPU tidak memiliki tumpukan atau catatan aktivasi panggilan. Tidak ada cara untuk mensimulasikan lingkup atau variabel lokal dalam GLSL seperti yang dapat dilakukan oleh kompiler C pada kebanyakan CPU. Semua yang ada adalah register, yang merupakan register seragam, input stage shader, output, dan file register lokal yang unik untuk permintaan shader itu.

Dengan kata lain, karena tidak ada yang namanya fungsi atau stack atau heap, semua variabel yang dideklarasikan di mana saja tinggal dalam register. Apakah mereka lokal ke beberapa ruang lingkup di GLSL atau global ke seluruh file tidak ada bedanya. Mereka hanya mendaftar.

Namun, pengalokasi register bukan bagian dari standar GLSL. Implementasi OpenGL yang berbeda dapat memiliki tingkat kualitas yang berbeda ketika datang untuk mengubah kode GLSL tingkat tinggi menjadi kode mesin tingkat rendah yang dipahami oleh GPU. Salah satu bagian yang lebih rumit dari kompiler (GLSL atau lainnya) adalah alokasi register . Ini adalah bagian dari kompiler yang menentukan register mana yang ditempati variabel tertentu. C memiliki sedikit lebih sulit karena biasanya harus berurusan dengan file register yang sangat kecil (terutama pada x86) dan harus berurusan dengan mendaftar tumpah (memindahkan variabel ke stack) dan aliasing (menyimpan variabel kembali ke RAM sebelum memanggil fungsi) dan instruksi aneh yang menuntut output berada dalam register tertentu (x86'sidivcontohnya). GPU memiliki file register berukuran besar karena tidak memiliki tumpukan atau tumpukan, sehingga pengalokasi dapat lebih sederhana.

Namun, file register tidak terbatas. Jika Anda memiliki lebih banyak variabel daripada register yang didukung oleh perangkat keras Anda, kompiler harus mencoba menyesuaikan semua variabel Anda dalam register. Ini biasanya memerlukan beberapa bentuk pengecekan kisaran lives . Artinya, jika Anda menggunakan variabel xnuntuk satu perhitungan lalu tidak pernah menggunakannya lagi, kompiler dapat menentukan ini dan kemudian tahu bahwa register yang ditempati xndapat digunakan oleh variabel lain di kemudian hari, sehingga memungkinkan lebih banyak variabel daripada register yang ada (begitu lama karena tidak ada terlalu banyak variabel langsung sekaligus).

Kompiler mungkin tidak melakukan ini. Tidak punya. Atau mungkin melakukannya hanya dalam beberapa kasus. Lingkup yang diberikan penyusun yang lebih sederhana masalah yang jauh lebih mudah untuk dipecahkan. Semua register yang dialokasikan untuk variabel fungsi lokal dapat digunakan kembali setelah fungsi itu keluar karena ia tahu variabelnya sudah mati. Variabel global tidak memiliki jaminan semudah itu. Oleh karena itu, beberapa kompiler yang kurang mampu mungkin tidak mengoptimalkan masa pakainya juga, dan variabel global akan selalu memakan register. Ini tidak akan membuat apa pun lebih lambat tetapi mungkin pada beberapa driver membatasi ukuran shader yang dapat Anda tulis.

Secara umum, saya akan sangat menyarankan agar semua variabel terlokalisasi. Pertahankan definisi sedekat mungkin dengan penggunaan variabel. Ini berlaku untuk semua bahasa pemrograman, bukan hanya GLSL. Saya juga merekomendasikan membuat setiap "variabel" const dalam setiap kasus yang Anda bisa. Ini sekali lagi dapat menjadi petunjuk bagi kompiler yang kurang mampu tertentu bahwa optimasi tertentu dimungkinkan, dan yang lebih penting, itu membuat kode Anda lebih banyak mendokumentasikan diri dan mudah untuk dipelihara.

Dan tentu saja, inilah saran Anda "hanya profil untuk menguji dan mencari tahu pasti" saran. Tulis shader Anda dengan dan tanpa global Anda dan profil itu. Setiap dan semua saran kinerja daring harus tidak dipercaya dan diasumsikan dicurigai atau kedaluwarsa.

Sean Middleditch
sumber
Itulah yang saya maksudkan. Anda menjawab pertanyaan saya dengan sempurna dan juga menjelaskan apa yang saya tanyakan.
RodgerDodger
1
Sebenarnya terkadang mendeklarasikan array sebagai const bukan non-const membuat keseluruhan shader lebih lambat (A LOT lebih lambat). Saya perhatikan masalah itu pada GTX 460 saya.
Tara
Saya baru saja menyingkirkan kesalahan aneh dan sangat curiga itu adalah GPU Adreno (OpenGL ES 3.1) gagal mengkompilasi shader karena variabel dinyatakan di luar utama.
comodoro
Salah satu jawaban SO paling menyeluruh yang pernah saya lihat - bagus sekali!
duhaime
Hari ini saya belajar sesuatu yang baru. Hari ini, saya belajar, saya tidak benar-benar tahu atau mengerti glsl. Hanya karena saya dapat menggunakannya untuk membuat ruang cyllindrical diubah geometri gif tidak berarti saya mengerti cara kerjanya.
cmarangu