Birden fazla GLSL gölgelendirici arasında kod paylaşma


30

Sık sık kendimi birkaç gölgelendirici arasında kopyala yapıştırma kodu buluyorum. Bu, tek bir boru hattındaki tüm gölgelendiriciler arasında paylaşılan belirli hesaplamaları veya verileri ve tüm köşe gölgelendiricilerimin ihtiyaç duyduğu (veya başka bir aşamada) ortak hesaplamaları içerir.

Tabii ki, bu korkunç bir uygulama: Eğer kodu herhangi bir yerde değiştirmem gerekiyorsa, başka bir yerde değiştirdiğimden emin olmam gerekiyor.

DRY tutmak için kabul edilmiş bir en iyi uygulama var mı ? İnsanlar sadece tüm gölgeleyicilerine ortak bir dosya hazırlarlar mı? #includeYönergeleri ayrıştıran kendi ilkel C-tarzı işlemciler mi yazıyorlar ? Sektörde kabul görmüş kalıplar varsa, onları takip etmek isterim.


4
Bu soru biraz tartışmalı olabilir, çünkü diğer bazı SE siteleri en iyi uygulamalar hakkında sorular istememektedir. Bu, bu topluluğun bu tür sorularla ilgili olarak nasıl durduğunu görmek için kasıtlıdır.
Martin Ender

2
Hmm, bana iyi görünüyor. StackOverflow'tan, sorularımızda büyük ölçüde "daha geniş" / "daha genel" olduğumuzu söyleyebilirim.
Chris, Reinstate Monica’nın

2
StackOverflow a 'dont sürece bize sorun 'bize sorun' olmaktan çıktı zorunda memnun' kurulu.
saat

Konu başlığını belirlemek istiyorsa, o zaman ilişkili bir Meta sorusu ne durumda?
SL Barth - Monica,

Yanıtlar:


18

Bir sürü yaklaşım var, ama hiçbiri mükemmel değil.

glAttachShaderGölgelendiricileri birleştirmek için kod kullanarak paylaşmak mümkündür , ancak bu, yapı bildirimleri veya #define-d sabitleri gibi şeyleri paylaşmayı mümkün kılmaz . İşlevleri paylaşmak için çalışır.

Bazı insanlar glShaderSource, kodunuzdan önce genel tanımları hazırlamanın bir yolu olarak iletilen dizeleri kullanmaktan hoşlanır , ancak bunun bazı dezavantajları vardır:

  1. Gölgelendiriciden nelerin dahil edileceğini kontrol etmek daha zordur (bunun için ayrı bir sisteme ihtiyacınız vardır.)
  2. Bu, gölgelendirici yazarının #versionGLSL spesifikasyonundaki aşağıdaki ifadeden dolayı GLSL'yi belirleyemediği anlamına gelir :

#Version yönergesi, her şeyden önce bir gölgelendiricide meydana yorumlar ve bosluklarla hariç gerekir.

Bu nedenle glShaderSource, #versionbildirimlerden önce metin hazırlamak için kullanılamaz . Bu, #versionhattın glShaderSourceargümanlarınıza dahil edilmesi gerektiği anlamına gelir; bu, GLSL derleyici arayüzünüzün bir şekilde hangi GLSL sürümünün kullanılması beklendiği konusunda bilgilendirilmesi gerektiği anlamına gelir. Ek olarak, bir belirtmek değil #version, GLSL derleyicisini GLSL sürüm 1.10 kullanmak için varsayılan yapacaktır. Gölgelendirici yazarlarının #versionbetiğin içindeki değerini standart bir şekilde belirtmesine izin vermek istiyorsanız #include, #versionifadeden sonra bir şekilde insert'leri eklemeniz gerekir . Bu, #versiondiziyi bulmak için GLSL gölgelendiriciyi açıkça ayrıştırıp, varsa ondan sonra eklemelerinizi yaparak , ancak#includeBu kapanımların yapılması gerektiğinde daha kolay kontrol etmek için yönerge tercih edilebilir. Öte yandan, GLSL #versionsatırdan önceki yorumları görmezden geldiğinden, yorumlarınızın içine eklemek için dosyanızın üst kısmına meta veri ekleyebilirsiniz (yuck.).

Şimdi soru şudur: Standart bir çözüm var mı #include, yoksa kendi önişlemci uzantınızı mı kullanmanız gerekiyor?

Orada GL_ARB_shading_language_includeuzatma, ancak bazı sakıncaları da vardır:

  1. Yalnızca NVIDIA tarafından desteklenir ( http://delphigl.de/glcapsviewer/listreports2.php?listreportsbyextension=GL_ARB_shading_language_include )
  2. Önceden içerme dizelerini belirterek çalışır. Bu nedenle, derlemeden önce, dizenin "/buffers.glsl"(kullanılan şekilde #include "/buffers.glsl") dosyanın içeriğine buffer.glsl(daha önce yüklediğiniz ) karşılık geldiğini belirtmeniz gerekir .
  3. (2) noktasında fark etmiş olabileceğiniz gibi, yollarınızın "/"Linux tarzı mutlak yollar gibi başlaması gerekir . Bu gösterim genellikle C programcılarına yabancıdır ve göreceli yolları belirleyemeyeceğiniz anlamına gelir.

Yaygın bir tasarım kendi #includemekanizmanızı uygulamaktır , ancak bu zor olabilir çünkü #ifkoşullu derlemeyi (başlık korumaları gibi) uygun şekilde ele almak için diğer önişlemci talimatlarını da ayrıştırmanız (ve değerlendirmeniz) gerekir.

Kendinizinkini uygularsanız, #includenasıl uygulamak istediğiniz konusunda da bazı özgürlükleriniz vardır:

  • Dizeleri vaktinden önce geçirebilirsin (gibi GL_ARB_shading_language_include).
  • Bir içerme geri çağrısı belirtebilirsiniz (bu, DirectX'in D3DCompiler kütüphanesi tarafından yapılır.)
  • Tipik C uygulamalarında olduğu gibi her zaman doğrudan dosya sisteminden okuyan bir sistem uygulayabilirsiniz.

Bir sadeleştirme olarak, ön işleme katmanınıza dahil her bir başlık için otomatik olarak başlık korumaları ekleyebilirsiniz, böylece işlemci katmanınız şöyle görünür:

if (#include and not_included_yet) include_file();

(Bana yukarıdaki tekniği gösterdiği için Trent Reed'e teşekkür ederim.)

Sonuç olarak, otomatik, standart ve basit bir çözüm yoktur. Gelecekteki bir çözümde, bazı SPIR-V OpenGL arayüzlerini kullanabilirsiniz, bu durumda GLSL - SPIR-V derleyicisi GL API dışında olabilir. Derleyicinin OpenGL çalışma zamanı dışında olması, #includedosya sistemiyle arabirim kurmak için daha uygun bir yer olduğu için uygulamaların yapılmasını büyük ölçüde basitleştirir . Mevcut yaygın yöntemin, yalnızca herhangi bir C programcısının aşina olması gereken şekilde çalışan özel bir önişlemci uygulamak olduğuna inanıyorum.


Gölgelendiriciler, yalnızca node.js. ile çalışsa da, glslify kullanılarak modüllere ayrılabilir.
Anderson Green,

9

Genelde sadece glShaderSource (...) 'un bir dizgiyi girdi olarak kabul ettiği gerçeğini kullanırım.

Bir gölgelendiricinin (veya daha doğru olması gereken bir programın) nasıl oluşturulduğunu belirten bir json tabanlı gölgelendirici tanım dosyası kullanıyorum ve orada kullanabileceğim önişlemcinin kullanabileceğim üniformaları, tepe / parça gölgelendiricileri dosyasını belirteceğim, ve tüm ek "bağımlılık" dosyaları. Bunlar sadece gerçek gölgelendirici kaynağından önce kaynağa eklenen fonksiyonların koleksiyonlarıdır.

Sadece eklemek için, AFAIK, Unreal Engine 4, önerdiğiniz gibi derlemeden önce tüm ilgili dosyaları çözümleyen ve ekleyen bir #include yönergesi kullanır.


4

Ortak bir sözleşme olduğunu sanmıyorum, ancak bir tahminde bulunursam, hemen hemen herkesin bir ön işleme adımı ( #includeuzantısı) olarak basit bir metinsel içerme biçimi uyguladığını söyleyebilirim , çünkü yapılması çok kolaydır. yani. (JavaScript / WebGL'de, örneğin basit bir normal ifade ile yapabilirsiniz). Bunun tersi, gölgelendirici kodunun artık değiştirilmesi gerekmediğinde, "serbest bırakma" yapıları için çevrimdışı bir adımda ön işleme gerçekleştirebilmenizdir.

Aslında bu yaklaşım yaygın olduğunun bir göstergesidir ARB uzantısı bunun için tanıtıldı olmasıdır: GL_ARB_shading_language_include. Bunun şimdiye kadar temel bir özellik olup olmadığından emin değilim, ancak eklenti OpenGL 3.2'ye karşı yazılmıştı.


2
GL_ARB_shading_language_include temel bir özellik değildir. Aslında, yalnızca NVIDIA desteklemektedir. ( delphigl.de/glcapsviewer/… )
Nicolas Louis Guillemot

4

Bazı insanlar çoktan glShaderSourcebir dizi dizi alabileceğini belirtti .

Bunun üzerine, GLSL'de gölgelendiricinin derlenmesi ( glShaderSource, glCompileShader) ve bağlanması ( glAttachShader, glLinkProgram) ayrıdır.

Bazı projelerde, gölgelendiricileri belirli parça ile çoğu gölgelendiricinin ortak kısımları arasında bölüştürmek için kullandım, bu daha sonra tüm gölgelendirici programları ile derlenip paylaşılıyor. Bu işe yarar ve uygulanması zor değildir: sadece bir bağımlılık listesi tutmanız gerekir.

Sürdürülebilirlik açısından olsa da, bunun bir kazandığından emin değilim. Gözlem aynıydı, çarpanlara ayırmaya çalışalım. Gerçekten de tekrarlamadan kaçınırken, tekniğin ek yükü önemli hissediyor. Dahası, son gölgelendiricinin çıkarılması daha zordur: bildirimler bazı derleyicilerin reddedeceği veya kopyalanacağı bir sırada sona erdiği için gölgelendirici kaynaklarını sadece birleştiremezsiniz. Bu yüzden ayrı bir aletle hızlı bir gölgelendirici testi yapmayı zorlaştırır.

Sonunda bu teknik bazı DRY sorunlarına yöneliktir ancak ideal olmaktan uzaktır.

Bir yandan, bu yaklaşımın derleme zamanı açısından bir etkisi olup olmadığından emin değilim; Bazı sürücülerin sadece gölgelendirici programını bağlantı için derlediğini okudum, ancak ölçüm yapmadım.


Anladığım kadarıyla bunun yapısal tanımları paylaşma problemini çözmediğini düşünüyorum.
Nicolas Louis Guillemot

@NicolasLouisGuillemot: evet haklısın, bildirimler değil, sadece talimatların kodu bu şekilde paylaşılıyor.
Julien Guertault
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.