NVIDIA OptiX, CUDA ile GPU hızlandırmalı ışın izleme işlemleri için bir API’dir ve genellikle çeşitli nesne ve malzeme içerikleri barındıran sahnelerin render edilmesinde kullanılır. OptiX’i başlatırken, bir ışın geometrik bir primitif ile kesiştiğinde, o kesişim için bir hit shader çalıştırılır. Hangi shader’ın hangi kesişim için çalıştırılacağı ise Shader Binding Table (SBT) tarafından belirlenir. SBT, ayrıca girdi verilerini gölgelendirme işlemi ile eşleştirmek için de kullanılabilir.
Bu yazıda, SBT’yi uygulamanızda düzenlemek için birkaç farklı yaklaşım tanıtılmaktadır. Hem SBT hem de gölgelendirme verilerini mümkün olan en küçük boyutta tutarak, bellek tasarrufu, performans artışı ve SBT’nin yönetimini kolaylaştırabilirsiniz.
Shader Binding Table Tasarım Yöntemleri
Ray izleme uygulamaları genellikle her bir mesh nesnesi için iki ana veri türü depolar: geometrik bilgiler, örneğin gölgeleme normalleri ve malzeme parametreleri, örneğin bir difüz yansıtma veya bir pürüzlülük parametresi. Bu veriler, malzeme shader’ı tarafından mevcut kesişim noktasında ışıklandırma hesaplamaları yapmak için kullanılır.
Aşağıdaki bölümlerde, SBT kullanımına ve veri arama işleminin uygulanmasına iki yaklaşım geliştirilecektir. İlk yaklaşım, SBT’yi shader programlarını ve veri aramalarını depolamak için basit bir şekilde kullanır. Bu yöntem uygulanması kolaydır, ancak bellek kullanımı açısından verimsizdir. İkinci yaklaşım, bu temel yaklaşımı geliştirerek, SBT kayıtlarındaki ve gölgelendirme verilerindeki tekrarı azaltarak verimliliği artırır.
Bu iki tasarım, sahnede birçok nesnenin aynı malzeme setini paylaştığı yaygın durumları hedef alır. Örnek olarak, tüm geometrinin OptiX’in yerleşik üçgen kesişimini kullandığını ve uygulamanın tek bir ışın türü kullandığını varsayıyoruz. Bu kısıtlamaların gevşetilmesi oldukça kolaydır ve aşağıda daha detaylı bir şekilde tartışılacaktır.
Naif Yaklaşım: Her Örnekte Geometri ve Malzeme Özellikleri
Shader’ları ve verileri bir örneğe eşlemenin en kolay yolu, her örnek için ayrı bir SBT kaydı üzerinde tüm shader’lara ve verilere referanslar saklamaktır (her ışın türü için). Shader’lar, SBT kaydının başlık kısmında referanslanırken, geometrik veri ve gölgelendirme parametrelerine ait referanslar kullanıcı tanımlı veri bloğunda saklanır. Küçük parametreler doğrudan saklanabilir.
Bir örnek, basit difüz ve parlak malzemeleri destekleyen ve per-vertex normalleriyle düzgün gölgeleme gerçekleştirerek bir yüzey izleme işlemcisidir. Ağırlıklı veri olan vertex öznitelikleri ayrı bir küresel bellek tahsisi içinde saklanır ve yalnızca bu veriye bir referans doğrudan veri bloğunda saklanır. Şekil 1, her bileşen için ilişkili veriyi göstermektedir.
Aşağıdaki yapı, bunu bir SBT kaydında karşılamak için kullanılabilir:
struct ShadingParams { Float3* normals; Float3 reflectance; Float roughness; }
Burada yansıtma parametresi difüz ve parlak malzemeler arasında paylaşılabilir, ancak pürüzlülük parametresi, gerekli olmasa bile saklanmalıdır. Bu, bu yaklaşımın dezavantajlarından biridir. Veri bölümü, tüm malzemelerin en büyük parametre setinin ayak izine en az büyük olmalıdır.
Şimdi bu düzenin varsayımsal bir sahneye uygulamasına bakalım:
- 100.000 örnek
- 50.000 benzersiz üçgen mesh (GAS)
- İki malzeme shader’ı (düzgün ve difüz)
- 10.000 benzersiz malzeme parametre seti
Malzeme sayısı genellikle örnek sayısından daha küçüktür çünkü bazı nesneler aynı malzeme tanımını paylaşabilir.
Bu şemanın gerekli depolama alanı, örnek sayısı ile SBT kaydının boyutunun çarpımıdır. Bu durumda, SBT veri bölümü boyutu 24 bayt; ancak 16 baytlık hizalama 32 milyara yuvarlanmasına neden olur. Başlık bölümü her zaman 32 bayt olup, API tarafından gereklidir. Bu, toplam SBT vurgu grubu listesinin yaklaşık 6 MB kadar bir sekme hafıza yüküne sahiptir.
Bu yaklaşım, hafıza açısından ağırdır ve birçok defa aynı SBT başlıklarını ve veri bölümlerini saklar. Bu bellek şişkinliği, yalnızca değerli GPU depolamasını almakla kalmaz, aynı zamanda tutarsız bellek erişimleri nedeniyle GPU tarafı performansında azalmaya ve büyük boyutlu bir SBT dizisini doldurmanın ve bakımının host tarafındaki aşırılıklara neden olabilir. Ancak, bu teknik basit uygulamalar ve sahne kurulumları için yine de makul bir seçim olabilir.
Ayrıca, veri bölümünün her zaman minimum sıfırdan büyük boyutu olan 16 bayt olarak tutulabileceğini de belirtelim. Tüm gölgeleme ve geometri verileri global bir tahsiste toplu olarak saklanabilir ve kayıtta yalnızca bu verilere bir işaretçi saklanabilir. Ancak, bu ek bir işaretçi ve ek bir bellek dolaylı maliyetine neden olur.
Optimize Edilmiş Yaklaşım: Tekrarı Azaltmak İçin Örnek Depolama
Bu bölümde, SBT ve veri düzenini optimize ederek bu sorunları azaltmayı hedefleyeceğiz. SBT’nin ve tüm gölgelendirme verilerinin bellek ayak izini azaltmanın anahtarı, tekrarı azaltmaktır.
Öncelikle, SBT kaydının veri bölümünü tamamen kaldırarak başlayalım. Bunun yerine, gölgelendirme verilerini küresel bellekte saklayarak OptiX hiyerarşasını kullanarak erişmek mümkündür. Tek bir SBT kaydı ile her bir GAS’yi kullanıyorsak, bu eşleme oldukça basittir. Gölgelendirme parametreleri, sahnede bulunan her benzersiz malzeme parametreleri ve geometrik veriler kombinasyonu için bir girişin yer aldığı küresel bellek dizisine taşınır.
Bu dizideki ShadingParams girişlerinin sayısı en fazla her bir örnek için bir adet olabilir, ancak pratikte aynı malzeme parametreleri ile birden fazla örnek olduğundan çok daha küçük olabilir. Her sahnedeki örneğin, gölgelendirme parametrelerinin dizininde ayarlanmış bir örnek kimliği bulunur.
Aşama kodunda mevcut gölgelendirme verilerine şu şekilde erişilir:
ShadingParams& params = shading_data_array[optixGetInstanceId()];
Burada, örnek kimliklerinin benzersiz olması gerekmez. Birden fazla örnek gölgelendirme ve geometrik verileri paylaştığında, gölgelendirme parametreleri listesine dizinleme için aynı örnek kimliği kullanılabilir.
Şimdi, geometri parametrelerinin tekrarlarını ele alalım. Belirli bir GAS çok kez örneklenirse, her örnekte depolanmış şading-normal dizisi referansı tutulur; bu da naif düzen ile bir örnek başına bir kez ve mevcut yaklaşım ile benzersiz geometri/gölgeleme parametre seti başına tutulur. İdeal olarak, normallar yalnızca her GAS için bir kez saklanmalıdır, çünkü her örnekte bu veriler değişmez.
GAS’ye ilişkin verilerin depolanması, OptiX 8.1 ile tanıtılan yeni optixGetGASPointerFromHandle fonksiyonu ile kolayca uygulanabilir. Bu fonksiyon, belirli bir GAS ile ilişkili ikili hızlandırma yapı verisinin bellekteki adresini alır. Uygulama, hafıza tahsisatı oluştururken, bu hızlandırma yapı verilerinin önüne bir kullanıcı verisi parçasını ekleyebilir. Cihaz fonksiyonu, optixGetGASPointerFromHandle fonksiyonu çağrıldıktan sonra kullanıcı verisi segmentinin boyutunu düşürerek kullanıcı verisini alabilir.
Artık veriler aşağıdaki gibi organize edilmiştir:
MaterialParams { float3 reflectance; float roughness; } GeometryParams { float3* normals; }
Bu, her benzersiz GeometryParams’dan birden fazla örneği ortadan kaldırıyor, aynı zamanda malzeme parametreleri içindeki tekrarları da azaltıyor, çünkü parametrelerin benzersizliği artık her bir malzeme ve geometri parametre setinin benzersiz bir setine ihtiyaç duymuyor.
Son optimizasyon, SBT başlığında malzeme programlarının tekrarını ortadan kaldırır. Sadece iki benzersiz malzeme programı bulunmaktadır: bir parlak ve bir difüz, ancak bunlar birçok kez saklanmaktadır. Her örnek için bir SBT kaydı saklamak yerine, malzeme türüne göre bir SBT kaydı saklamak mümkündür; bu örnekte, yalnızca iki adet SBT kaydı vardır. Artık her örneğin, difüz mü yoksa parlak mı olduğuna bağlı olarak SBT ofseti sıfıra veya bir’e ayarlanır.
Şekil 5, son veri düzenini gösterir. Geometri ve malzeme parametre düzeni Şekil 4’ten farklı değildir.
Gölgelendirme verileri için son kullanım şu şekildedir:
num-GASs*sizeof(GeometryParams) +
num-unique-material-instances*sizeof(MaterialParams) +
num material-shaders*OPTIX_SBT_RECORD_HEADER_SIZE
Bu miktar bir megabayttan azdır. Depolama boyutu artık sahnedeki örnek sayısıyla bağlı değildir. Bu, karmaşık gerçek dünya sahneleri için büyük bir kazanım olabilir, çünkü çok sayıda instance ve her biri için on veya yüzlerce parametreye sahip shader’lar içerir.
Alternatif Gölgelendirme Düzenleri için Genişletme
OptiX iç fonksiyonları, daha karmaşık veri arama işlemlerine olanak tanır. Bu durumdaki sorgulama fonksiyonları şunları içerir:
- optixGetSBTDataPointer: Geçerli primitifin mevcut SBT kaydının veri bloğunun adresi. Bu, [Denklem 1] ile hesaplanan adresin opak kayıt başlığı boyutuyla offsetlenmesiyle elde edilir.
- optixGetInstanceId: Uygulama tarafından mevcut örneğe atanan kimlik (OptixInstance::instanceId). Bu değer, örnekler arasında benzersiz olmak zorunda değildir ve [0 – 2^28) aralığında keyfi olarak seçilebilir.
- optixGetInstanceIndex: Örneğin kendi hızlandırma yapısı içindeki sıfıra dayalı indeksini döndürür.
- optixGetPrimitiveIndex: Geçerli kesişen üçgen, küre, kavis veya özel geometri için primitif indeksini döndürür. Daha fazla ayrıntı için OptiX Programlama Kılavuzu‘na bakabilirsiniz.
- optixGetSbtGASIndex: Geçerli GAS içindeki SBT ofsetini döndürür (girişin sbtIndexOffsetBuffer’ına göre belirtilmiştir).
- optixGetGASPointerFromHandle: Bir GAS’deki geometri hızlandırma yapısının bellekteki başlangıç adresini geri döndürür. Uygulama daha sonra bu GAS belleğini belirli bir geometri için önceden işaretlenmiş bir veri kısmı ile öne alabilir.
Örnek Gölgelendirme Düzenleri
Bu bölüm, bazı örnek gölgeleme düzenlerini sunar ve nasıl yaklaşılabileceğini gösterir.
Birden Fazla Geometri Türü
Geliştirilmiş düzen, birden fazla farklı geometri türünü kolayca barındırabilir. Ancak SBT girişlerinin sayısı, geometri türleri ve malzeme shader’larının kombinasyonuna göre değişir; çünkü bir hit grubu, kesişim programı aracılığıyla geometriyi ve hit programları aracılığıyla malzemeleri kapsar. Üç geometri türü ve iki malzeme için, en fazla altı SBT hit-grup girişi olur.
BİRden Fazla Işın Türü
Işın türlerinin sayısı tekrar olarak SBT hit-grup girişlerinin sayısını etkiler. Gerçek dünya örnekleri için, toplam ışın türleri, geometri türleri ve malzeme türlerinin çarpımı genellikle 10 ila 100 arasında değişir.
Tek GAS İçinde Birden Fazla Malzeme
Bu durumu yönetmek için birkaç yol vardır, ancak en kolay yöntem, shader parametre dizinlerine yönlendiren ek bir arama tablosu oluşturmaktır. Bu tablo, örnek kimliğine artı SBT GAS indeksine göre indekslenebilir.
Özet
NVIDIA OptiX kütüphanesi, gölgelerin ve verilerin ışın izleme uygulamalarına bağlanması için esnek mekanizmalar sunar. SBT’yi kullanarak verilerin ve shader’ların örnek düzeyinde depolanması, basit uygulamalar için uygun bir yöntem olabilir. Ancak, tekrarlı bağlamaları ve veri depolamayı azaltan optimize edilmiş bir yaklaşım, performansı artırabilir ve bellek şişkinliğinin önüne geçebilir.
Başlamak için NVIDIA OptiX SDK‘sını indirip belgelere göz atabilirsiniz.