- Son 10 yılda DirectX 12, Vulkan, Metal gibi düşük seviyeli grafik API’leri GPU performansını artırdı, ancak karmaşıklık ve bakım maliyeti de hızla yükseldi
- Modern GPU’lar tam bir önbellek hiyerarşisi, 64 bit pointer’lar, bindless kaynaklar desteklediği için eski karmaşık durum nesneleri ve binding modelleri gereksiz hale geliyor
- Önerilen tasarım, C/C++ pointer tabanlı bellek erişimi ve tek bir 64 bit kök pointer kullanarak render pipeline’ını büyük ölçüde sadeleştiriyor
- PSO patlaması, resource barrier’lar, karmaşık binding API’leri kaldırılıyor ve GPU belleği ile shader dilini doğrudan bağlayan bir yapı öneriliyor
- Bu yaklaşım, modern GPU mimarilerine optimize edilmiş yeni nesil bir API olarak DirectX 13 veya Vulkan 2.0’ın yönelmesi gereken istikameti ortaya koyuyor
Düşük seviyeli grafik API’lerinin dönüşümü
- 2013’te Xbox One ve PS4’ün AMD GCN mimarisi AAA oyun geliştirmede standart haline gelirken Mantle, DirectX 12, Vulkan ve Metal gibi düşük seviyeli API’ler ortaya çıktı
- Yani bunlar, 2013 civarındaki GPU mimarileri temel alınarak tasarlandı
- Eski DirectX 11/OpenGL, tek iş parçacıklı rendering ve yüksek driver overhead’i nedeniyle sınırlarına ulaşmıştı
- Bu API’ler, önceden derlenmiş pipeline object’ler (PSO) ile draw call maliyetini düşürdü, ancak oyun motorlarının yapısıyla uyuşmadığı için karmaşıklık arttı
- Sonuç olarak motorların içinde ikinci bir “low-level driver katmanı” oluştu ve grafik programcılarının rolü daha da ayrıştı
Tarihsel arka plan: Neden bu kadar karmaşık hale geldi
- İlk GPU’lar, ayrık bellek ve sabit işlevli pipeline ağırlıklı bir yapıya sahipti
- OpenGL ve DirectX, donanım çeşitliliğini soyutlamak için durum tabanlı ve nesne tabanlı bir tasarım benimsedi
- DirectX 11’e kadar texture ve buffer’lar opak descriptor’lar üzerinden yönetiliyordu
- Bu tasarım daha sonraki API’lerde de ataletle korunmaya devam etti
Modern GPU’lar ile API’ler arasındaki uyumsuzluk
- Güncel GPU’lar tutarlı bir önbellek hiyerarşisi, PCIe ReBAR, 64 bit pointer’lar, bindless texture’lar destekliyor
- CPU’nun GPU belleğine doğrudan yazıp GPU’nun bunu anında okuyabildiği bir yapı artık mümkün
- Böyle bir ortamda PSO, descriptor set ve binding table gibi yapılar gereksiz hale geliyor
- PSO cache’in kontrolden çıkması yüzlerce GB önbellek gerektiriyor; bu da yükleme gecikmeleri ve takılmaların nedeni oluyor
- Yeni bir API, bu eski yapılardan kurtulup basit pointer tabanlı erişime geçebilir
GPU bellek yönetiminin sadeleşmesi
- Mevcut Vulkan/DirectX 12’de resource oluşturduktan sonra heap uyumluluğunu sorgulamak gerektiği için verimsizlik oluşuyor
- Önerilen yaklaşım, GPU belleğini gpuMalloc/gpuFree benzeri basit bir API ile doğrudan ayırıyor
- CPU, GPU belleğini doğrudan map edip başlatabiliyor
- Büyük veriler kopyalama komutlarıyla taşınarak DCC sıkıştırması ve swizzle işlemleri uygulanabiliyor
- CPU mapping adresi ile GPU adresi ayrılıyor ve aralarında gpuHostToDevicePointer ile dönüşüm yapılıyor
Veri ve shader dilinin modernleştirilmesi
- CUDA, Metal ve OpenCL’de olduğu gibi C/C++ pointer tabanlı bir shader dili kullanılıyor
- Struct düzeyinde wide load’lar (128 bit ve üstü) ile verimli bellek erişimi mümkün oluyor
- DirectX’in ByteAddressBuffer ya da texel buffer yapıları artık en iyi seçenek değil
- GLSL/HLSL pointer desteklemediği için yeniden kullanılabilir shader kütüphanesi ekosistemi oluşmadı; buna karşılık CUDA zengin bir kütüphane dünyasına dönüştü
Kök argümanlar ve veri yapıları
- GPU kernel’ı giriş olarak tek bir 64 bit pointer alıp bunu bir struct’a cast ediyor
- CPU ile GPU aynı C/C++ header’ı paylaşarak veri yapılarında tutarlılık sağlıyor
- const/restrict anahtar sözcükleriyle compiler optimizasyonu teşvik ediliyor, gereksiz UBO/SSBO ayrımı kaldırılıyor
- Modern GPU’ların scalar register preload ve dynamic uniform optimization yeteneklerinden yararlanılıyor
Texture binding’in sadeleşmesi
- Tüm texture’lar 256 bit descriptor dizileri (heap) içinde yönetiliyor; CPU ve GPU bunlara doğrudan yazabiliyor
- 32 bit index tabanlı erişimle non-uniform texture sampling destekleniyor
- Bu yapı, DirectX 12 SM 6.6’daki descriptor heap’ten daha basit ve Vulkan VK_EXT_descriptor_buffer ile benzer
- Texture object oluşturma, yükleme ve sampling süreçleri tamamen GPU bellek pointer’ı tabanlı tek bir modelde birleşiyor
Shader pipeline’ı ve sabitler
- Pipeline oluşturma, yalnızca shader IR yüklenip ardından gpuCreatePipeline çağrılmasıyla yapılıyor
- Root signature, descriptor set ve binding tanımları gerekmiyor
- Statik sabitler (struct tabanlı) shader specialization constant’larının yerini alıyor ve PSO kombinasyon patlaması sorunu hafifliyor
- Sabit struct’ları GPU pointer’ları da içerebildiği için çalışma zamanı adresleri doğrudan hardcode edilebiliyor
Barrier ve senkronizasyonun sadeleşmesi
- Mevcut API’lerdeki resource bazlı barrier listeleri, modern GPU yapısıyla uyuşmuyor
- Önerilen model yalnızca queue/stage düzeyinde bitfield flag’ler kullanıyor
- Her şey gpuBarrier(before, after, hazard) biçiminde sadeleşiyor; resource takibi gerekmiyor
- gpuSignalAfter / gpuWaitBefore komutlarıyla timeline semaphore benzeri GPU→GPU senkronizasyonu uygulanabiliyor
Command buffer ve rendering
- Yalnızca tek kullanımlık (transient) command buffer’lar kullanılıyor; Vulkan’ın karmaşık yeniden kullanım modeli kaldırılıyor
- gpuBeginRenderPass / gpuEndRenderPass ile render target kurulumu ve clear işlemleri yapılıyor
- Render pass’ler arasında otomatik barrier yok; bu da paralel rendering ve depth pre-pass optimizasyonuna imkan tanıyor
Raster pipeline’ının sadeleşmesi
- Vertex/pixel shader’lar pointer tabanlı veri erişimi kullandığı için binding API’si ortadan kalkıyor
- GpuDepthStencilState ve GpuBlendState, PSO’dan ayrılarak kombinasyon sayısını azaltıyor
- Mobil GPU’lar framebuffer fetch intrinsic ile programmable blending destekliyor
- PSO yalnızca en az gerekli durumları içeriyor: topoloji, format, örnek sayısı vb.
Indirect draw ve GPU güdümlü rendering
- Tüm argümanlar (data, arguments) GPU pointer’ları üzerinden aktarılıyor
- gpuDrawIndexedInstancedIndirectMulti ile multi-draw destekleniyor
- GPU, kök veriyi ve draw argümanlarını doğrudan üretebildiği için tam anlamıyla GPU-driven rendering mümkün oluyor
Araçlar ve uyumluluk
- Pointer tabanlı yapı, CUDA/Metal debugger’larında olduğu gibi sembol bilgisi üzerinden izlenebiliyor
- Sanal bellek ile korunduğu için güvenlik sorunu yaratmıyor; hatalı erişimde page fault oluşuyor
- MoltenVK, Proton örneklerinde olduğu gibi mevcut DirectX/Vulkan/Metal API’leri bir çeviri katmanı üzerinden uyumlu kalabiliyor
Minimum gereksinimler ve sonuç
- Nvidia Turing(2018), AMD RDNA1(2019), Intel Xe1(2022), Apple M1(2020) gibi platformların tamamı önerilen özellikleri destekliyor
- Günümüz GPU’ları zaten bindless, 64 bit pointer ve tutarlı önbellek yapısına geçmiş durumda
- Geçmişin soyutlamalarına takılı kalan tek şey API’lerin kendisi
- Yeni API, DirectX 11’den daha basit, Vulkan’dan daha hızlı ve Metal’den daha esnek olabilir
- Yeni nesil Vulkan 2.0 / DirectX 13, bu tür bir tam bindless tasarıma geçmeli ve HLSL/GLSL yerine C/C++ pointer tabanlı shader dili ile ekosistemi büyütmeli
1 yorum
Hacker News yorumları
Bu yazı, Vulkan ve DX12'nin gereksiz kısımlarını çok iyi gösteren harika bir yazı
Bugünlerde DX12, buffer pointer'ları bile desteklemiyor; bu da fiilen kaderine terk edilmiş gibi hissettiriyor. Vulkan da 2.0 ile toparlanmadığı için extension'ları düzgün uygulamayan çok sayıda sürücü var
Eğer böyle yeni bir API var olsaydı, OpenGL bunun üstünde çok daha hızlı emüle edilebilirdi ve SDL3 GPU gibi şeyler de 3-4 kat performans artışı elde edebilirdi gibi geliyor
Frank Luna'nın kitabı da en yeni özellikleri kapsamıyor; Learn sitesini, GitHub örneklerini ve referans dokümanlarını didiklemek gerekiyor
Vulkan da benzer şekilde karmaşık; 2.0 çıksa bile, özellikle Android gibi ana platformlarda bunun pratikte nasıl kullanılabileceği belirsiz
Intel Arc dışında çoğu GPU, reBAR olmadan da çalışıyor; ama Microsoft ya da Intel bunu UEFI'de zorunlu kılarsa bindless texture gibi özellikler daha güvenilir kullanılabilir gibi duruyor
Yine de bu durumda desteklenen donanım için bir alt sınır oluşur ve 2020 öncesi anakartlarda destek oldukça tutarsız
Yazının temel motivasyonu eksik kalmış
Blog dizinine göre amaç, “son 10 yılda grafik API'leri ve shader dillerinin karmaşıklığı keskin biçimde arttı; artık soyutlama katmanını basitleştirerek geliştirme verimliliğini ve performansı artırmak, ayrıca gelecekteki GPU iş yüklerine hazırlanmak gerekiyor” demek
SSD'ler ilk başta IDE/SATA arayüzlerini yeniden kullandı; ama döner disk varsayımını bırakıp yeni bir aktarım yöntemi tasarlamak gerçek performansa ulaşmak için gerekliydi
Grafik API'lerinin de benzer legacy kısıtları geride bırakması gereken bir noktaya gelindiği benzetmesi yapılıyor gibi
Sebastian Aaltonen'in çalışmalarını uzun zamandır takip ettiğim için önyargılı olabilirim ama bu yazı gerçekten çok iyi
İleriye dönük yönün, software rendering'e geri dönüş olduğunu düşünüyorum
Ama bu kez fark, algoritmaların ve veri yapılarının donanım hızlandırması alacak olması
VFX sektöründe bu yönelim zaten başlamış durumda; yaklaşık 5 yıl önce OTOY'un OctaneRender'ı CUDA tabanına taşıması da bunun bir örneği
Shader türleri, bu pipeline'lar arasındaki boşlukları dolduruyor; dolayısıyla tamamen yazılımsal bir modele geçmek gerçekçi değil
Örneğin Unreal Engine'in Nanite sistemi, küçük üçgenleri işlerken GPU üzerinde compute shader ile çalışan bir software rasterizer kullanıyor
Yazıdaki detay seviyesi etkileyiciydi
Sadece bir kısmını anlayabildim ama gelecekteki grafik API tasarımı için bir başvuru metni gibi duruyor
Çoğu oyuncu için Vulkan/DX12 büyük bir kazanç olmadı ve birçok oyun PSO sorunları yüzünden zorlandı
Vulkan gelişiyor olsa da WebGPU, Vulkan'ın ilk tasarımındaki kısıtları aynen devraldı
Donanımın bu kadar hızlı evrildiği bir dönemde API'leri fazla düşük seviyeye indirmek bir hata olmuş olabilir
Belki de CUDA gibi genel amaçlı hesaplama merkezli bir yaklaşım daha iyi bir yön olabilir
Mantle'ı özlediğimi fark ettim
Kusurları vardı ama donanımı gerçekten doğrudan kullanıyormuşsun hissi veriyordu ve Xbox 360 geliştirdiğim dönem en keyif aldığım zamandı
Nvidia ve Nintendo tarafından tasarlanmış; konsollar arasındaki en sezgisel API olduğunu düşünüyorum
Bu yazıyı okuyunca sanki tarihi bir ana tanıklık etmişim gibi hissettim
İlgili bir proje gibi görünen Google Toucan aklıma geldi
Bu yazı eski anıları epey canlandırdı
API tasarımcılarının dikkate aldığı ek unsurlar arasında şunlar var
Microsoft'un neden yeni bir DirectX sürümü çıkarmadığını merak ediyorum
DirectX Ultimate ya da 12.2 de fiilen DX12 ile aynı
Unreal Engine gibi middleware'in etkisiyle kendi API'lerinin önemi mi azaldı, yoksa EPIC'in yeni bir API önermesi mi gerekir diye düşünüyorum
Gerçek oyun geliştiricileri RHI (Rendering Hardware Interface) kurup oyun geliştirmeye odaklanıyor
Ray tracing ve mesh shader en büyük yeniliklerdi ama hâlâ sınırlı kullanıldıkları için daha ileri gidilmiyor gibi görünüyor
Unreal ve Unity gibi motorların yarattığı merkezileşme, API yeniliğine ilgiyi azalttı; gelişim daha çok GPU tarafında sürdü
CPU API'leri ise hâlâ basit buffer mapping düzeyinde
Geçmişte tessellation shader ortaya çıktığında olduğu gibi, ilerleme için yeni bir donanım değişimi gerekebilir
Valve'ın SteamOS için kendi grafik API'sini geliştirme ihtimali olup olmadığını merak ediyorum
Duyduğuma göre Valve, Vulkan'ın ilk geliştirme aşamalarında başlıca itici güçlerden biriydi