Yaklaşan WebGPU'ya geçmek, grafik API'lerini değiştirmekten daha fazlası anlamına gelir. Bu aynı zamanda web grafiklerinin geleceğine doğru atılmış bir adımdır. Ancak bu geçiş, hazırlık ve anlayışla daha iyi sonuçlanacaktır ve bu makale sizi buna hazırlayacaktır. Herkese merhaba, adım Dmitrii Ivashchenko ve MY.GAMES'te yazılım mühendisiyim. Bu makalede WebGL ile gelecek WebGPU arasındaki farkları tartışacağız ve projenizi geçişe nasıl hazırlayacağınızı anlatacağız. İçeriğe Genel Bakış WebGL ve WebGPU'nun Zaman Çizelgesi WebGPU'nun mevcut durumu ve gelecek Üst Düzey Kavramsal Farklılıklar Başlatma • WebGL: Bağlam Modeli • WebGPU: Cihaz Modeli Programlar ve İşlem Hatları • WebGL: Program • WebGPU: İşlem Hattı Üniformalar • WebGL 1'deki üniformalar • WebGL 2'deki üniformalar • WebGPU'daki üniformalar Gölgelendiriciler • Gölgelendirici Dili: GLSL ve WGSL • Veri Türlerinin Karşılaştırılması • Yapılar • İşlev Bildirimleri • Yerleşik işlevler • Gölgelendirici Dönüşümü Konvansiyon Farklılıkları Dokular • Görünüm Alanı • Klip Alanları WebGPU İpuçları ve Püf Noktaları • Kullandığınız boru hattı sayısını en aza indirin. • Önceden ardışık düzenler oluşturun • RenderBundles'ı kullanın Özet WebGL ve WebGPU'nun Zaman Çizelgesi diğer birçok web teknolojisi gibi kökleri oldukça eskilere dayanmaktadır. WebGPU'ya geçişin ardındaki dinamikleri ve motivasyonu anlamak için öncelikle WebGL geliştirme geçmişine hızlıca göz atmak faydalı olacaktır: WebGL'nin OpenGL'nin masaüstü sürümü çıktı. OpenGL masaüstü (1993) : Bu, 2007'de tanıtılan OpenGL ES 2.0'ı temel alan WebGL'nin ilk kararlı sürümüydü. Web geliştiricilerine, ek eklentilere ihtiyaç duymadan, 3D grafikleri doğrudan tarayıcılarda kullanma olanağı sağladı. WebGL 1.0 (2011) : İlk sürümden altı yıl sonra tanıtılan WebGL 2.0, OpenGL ES 3.0 (2012) temel alınarak geliştirildi. Bu sürüm, web'deki 3D grafikleri daha da güçlü hale getiren bir dizi iyileştirme ve yeni özelliği beraberinde getirdi. WebGL 2.0 (2017) Son yıllarda geliştiricilere daha fazla kontrol ve esneklik sağlayan yeni grafik API'lerine olan ilgide artış yaşandı: : Khronos grubu tarafından oluşturulan bu platformlar arası API, OpenGL'nin "halefidir". Vulkan, grafik donanımı kaynaklarına daha düşük düzeyde erişim sağlayarak, grafik donanımı üzerinde daha iyi kontrole sahip yüksek performanslı uygulamalara olanak tanır. Vulkan (2016) : Bu API, Microsoft tarafından oluşturulmuştur ve yalnızca Windows ve Xbox içindir. D3D12, D3D10/11'in halefidir ve geliştiricilere grafik kaynakları üzerinde daha derin kontrol sağlar. D3D12 (2015) : Apple tarafından oluşturulan Metal, Apple cihazları için özel bir API'dir. Apple donanımında maksimum performans göz önünde bulundurularak tasarlandı. Metal (2014) WebGPU'nun mevcut durumu ve gelecek Bugün WebGPU, sürüm 113'ten başlayarak Google Chrome ve Microsoft Edge tarayıcıları aracılığıyla Windows, Mac ve ChromeOS gibi birden fazla platformda mevcuttur. Yakın gelecekte Linux ve Android desteği bekleniyor. WebGPU'yu halihazırda destekleyen (veya deneysel destek sunan) motorlardan bazıları şunlardır: : WebGPU için tam destek. Babylon JS : Şu anda deneysel destek. ThreeJS : Geliştirme aşamasında, ancak çok umut verici beklentilere sahip. PlayCanvas : Çok erken ve deneysel WebGPU desteği 2023.2 alfa sürümünde duyuruldu. Unity : Resmi olarak WebGPU'yu destekliyor ve bu da onu bu alandaki öncülerden biri yapıyor. Cocos Creator 3.6.2 : şu anda yalnızca Windows, macOS ve ChromeOS için v113+ sürümünde desteklenmektedir. Construct Bunu göz önüne aldığımızda WebGPU'ya geçiş ya da en azından böyle bir geçişe yönelik projeler hazırlamak yakın gelecekte atılmış bir adım gibi görünüyor. Üst Düzey Kavramsal Farklılıklar Şimdi uzaklaştıralım ve başlatmadan başlayarak WebGL ile WebGPU arasındaki bazı üst düzey kavramsal farklılıklara bir göz atalım. Başlatma Grafik API'leriyle çalışmaya başladığınızda ilk adımlardan biri, ana nesneyi etkileşim için başlatmaktır. Bu süreç, her iki sistem için de bazı özelliklerle birlikte WebGL ve WebGPU arasında farklılık gösterir. WebGL: Bağlam Modeli WebGL'de bu nesne "bağlam" olarak bilinir ve esasen bir HTML5 tuval öğesi üzerinde çizim yapmaya yönelik bir arayüzü temsil eder. Bu bağlamı elde etmek oldukça basittir: const gl = canvas.getContext('webgl'); WebGL'nin içeriği aslında belirli bir tuvale bağlıdır. Bu, birden fazla tuval üzerinde görüntü oluşturmanız gerekiyorsa birden fazla bağlama ihtiyacınız olacağı anlamına gelir. WebGPU: Cihaz Modeli WebGPU "cihaz" adı verilen yeni bir konsepti tanıtıyor. Bu cihaz etkileşim kuracağınız bir GPU soyutlamasını temsil eder. Başlatma süreci WebGL'ye göre biraz daha karmaşıktır ancak daha fazla esneklik sağlar: const adapter = await navigator.gpu.requestAdapter(); const device = await adapter.requestDevice(); const context = canvas.getContext('webgpu'); context.configure({ device, format: 'bgra8unorm', }); Bu modelin avantajlarından biri, bir cihazın birden fazla tuval üzerinde görüntü oluşturabilmesi, hatta hiçbirinde görüntü oluşturamamasıdır. Bu, ek esneklik sağlar; örneğin, bir cihaz birden fazla pencerede veya bağlamda görüntü oluşturmayı kontrol edebilir. Programlar ve İşlem Hatları WebGL ve WebGPU, grafik hattını yönetmeye ve organize etmeye yönelik farklı yaklaşımları temsil eder. WebGL: Program WebGL'de ana odak gölgelendirici programıdır. Program köşe ve parça gölgelendiricileri birleştirerek köşelerin nasıl dönüştürülmesi gerektiğini ve her pikselin nasıl renklendirilmesi gerektiğini tanımlar. const program = gl.createProgram(); gl.attachShader(program, vertShader); gl.attachShader(program, fragShader); gl.bindAttribLocation(program, 'position', 0); gl.linkProgram(program); WebGL'de program oluşturma adımları: : Gölgelendiricilerin kaynak kodu yazılır ve derlenir. Gölgelendirici Oluşturma : Derlenen gölgelendiriciler programa eklenir ve ardından bağlanır. Program Oluşturma : Program render alınmadan önce aktif hale getirilir. Programın Kullanılması : Veriler etkinleştirilen programa iletilir. Veri İletimi Bu süreç esnek grafik kontrolüne izin verir, ancak aynı zamanda özellikle büyük ve karmaşık projelerde karmaşık olabilir ve hatalara açık olabilir. WebGPU: Boru Hattı WebGPU, ayrı bir program yerine "boru hattı" kavramını sunar. Bu işlem hattı yalnızca gölgelendiricileri değil aynı zamanda WebGL'de durumlar olarak oluşturulan diğer bilgileri de birleştirir. Dolayısıyla WebGPU'da bir işlem hattı oluşturmak daha karmaşık görünüyor: const pipeline = device.createRenderPipeline({ layout: 'auto', vertex: { module: shaderModule, entryPoint: 'vertexMain', buffers: [{ arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }] }], }, fragment: { module: shaderModule, entryPoint: 'fragmentMain', targets: [{ format, }], }, }); WebGPU'da bir işlem hattı oluşturma adımları: : Gölgelendirici kaynak kodu, WebGL'de yapıldığına benzer şekilde yazılır ve derlenir. Gölgelendirici tanımı : Gölgelendiriciler ve diğer oluşturma parametreleri bir işlem hattında birleştirilir. İşlem hattı oluşturma : İşlem hattı, oluşturma işleminden önce etkinleştirilir. İşlem hattı kullanımı WebGL, oluşturmanın her yönünü ayırırken, WebGPU daha fazla özelliği tek bir nesnede kapsüllemeye çalışarak sistemi daha modüler ve esnek hale getirir. WebGL'de yapıldığı gibi gölgelendiricileri ve görüntü oluşturma durumlarını ayrı ayrı yönetmek yerine, WebGPU her şeyi tek bir ardışık düzen nesnesinde birleştirir. Bu, süreci daha öngörülebilir ve hatalara daha az eğilimli hale getirir: Üniformalar Tek tip değişkenler, tüm gölgelendirici örneklerinin kullanabileceği sabit veriler sağlar. WebGL 1'deki üniformalar Temel WebGL'de, değişkenleri doğrudan API çağrıları yoluyla ayarlama olanağımız vardır. uniform : GLSL uniform vec3 u_LightPos; uniform vec3 u_LightDir; uniform vec3 u_LightColor; : JavaScript const location = gl.getUniformLocation(p, "u_LightPos"); gl.uniform3fv(location, [100, 300, 500]); Bu yöntem basittir ancak her değişken için birden fazla API çağrısı gerektirir. uniform WebGL 2'deki üniformalar WebGL 2'nin gelişiyle artık değişkenleri arabellekler halinde gruplama olanağına sahibiz. Yine de ayrı tek tip gölgelendiriciler kullanabilseniz de, daha iyi bir seçenek, tek tip arabellekler kullanarak farklı tek tip gölgelendiricileri daha büyük bir yapıda gruplandırmaktır. Daha sonra tüm bu tek tip verileri, WebGL 1'de köşe arabelleği yüklemeye benzer şekilde GPU'ya aynı anda gönderirsiniz. Bunun, API çağrılarını azaltmak ve modern GPU'ların çalışma şekline daha yakın olmak gibi çeşitli performans avantajları vardır. uniform : GLSL layout(std140) uniform ub_Params { vec4 u_LightPos; vec4 u_LightDir; vec4 u_LightColor; }; : JavaScript gl.bindBufferBase(gl.UNIFORM_BUFFER, 1, gl.createBuffer()); WebGL 2'de büyük bir tekdüze arabelleğin alt kümelerini bağlamak için, olarak bilinen özel bir API çağrısını kullanabilirsiniz. WebGPU'da, API'sini çağırırken bir uzaklık listesi iletebileceğiniz, dinamik tekdüze arabellek uzaklıkları adı verilen benzer bir şey vardır. bindBufferRange setBindGroup WebGPU'daki üniformalar WebGPU bize daha da iyi bir yöntem sunuyor. Bu bağlamda, bireysel değişkenler artık desteklenmemektedir ve iş yalnızca tamponlar aracılığıyla yapılmaktadır. uniform uniform : [[block]] struct Params { u_LightPos : vec4<f32>; u_LightColor : vec4<f32>; u_LightDirection : vec4<f32>; }; [[group(0), binding(0)]] var<uniform> ub_Params : Params; : JavaScript const buffer = device.createBuffer({ usage: GPUBufferUsage.UNIFORM, size: 8 }); Modern GPU'lar, verilerin birçok küçük blok yerine büyük bir blok halinde yüklenmesini tercih eder. Her seferinde küçük arabellekleri yeniden oluşturmak ve yeniden bağlamak yerine, büyük bir arabellek oluşturmayı ve farklı çizim çağrıları için bunun farklı bölümlerini kullanmayı düşünün. Bu yaklaşım performansı önemli ölçüde artırabilir. WebGL daha zorunludur; her çağrıda küresel durum sıfırlanır ve mümkün olduğu kadar basit olmaya çabalanır. WebGPU ise daha nesne odaklı olmayı ve kaynakların yeniden kullanımına odaklanmayı hedefliyor, bu da verimliliğe yol açıyor. WebGL'den WebGPU'ya geçiş yöntem farklılıkları nedeniyle zor görünebilir. Ancak ara adım olarak WebGL 2'ye geçişle başlamak hayatınızı kolaylaştırabilir. Gölgelendiriciler WebGL'den WebGPU'ya geçiş yalnızca API'de değil aynı zamanda gölgelendiricilerde de değişiklik yapılmasını gerektirir. WGSL spesifikasyonu, modern GPU'ların verimliliğini ve performansını korurken bu geçişi sorunsuz ve sezgisel hale getirmek için tasarlanmıştır. Gölgelendirici Dili: GLSL ve WGSL WGSL, WebGPU ile yerel grafik API'leri arasında bir köprü olacak şekilde tasarlanmıştır. GLSL ile karşılaştırıldığında WGSL biraz daha ayrıntılı görünüyor ancak yapısı tanıdık geliyor. Doku için örnek bir gölgelendirici: : GLSL sampler2D myTexture; varying vec2 vTexCoord; void main() { return texture(myTexture, vTexCoord); } : [[group(0), binding(0)]] var mySampler: sampler; [[group(0), binding(1)]] var myTexture: texture_2d<f32>; [[stage(fragment)]] fn main([[location(0)]] vTexCoord: vec2<f32>) -> [[location(0)]] vec4<f32> { return textureSample(myTexture, mySampler, vTexCoord); } Veri Türlerinin Karşılaştırılması Aşağıdaki tablo GLSL ve WGSL'deki temel ve matris veri türlerinin karşılaştırmasını göstermektedir: GLSL'den WGSL'ye geçiş, kod okunabilirliğini artırabilecek ve hata olasılığını azaltabilecek veri boyutlarının daha sıkı yazılması ve açık bir şekilde tanımlanmasına yönelik isteği gösterir. Yapılar Yapıları bildirmenin sözdizimi de değişti: GLSL: struct Light { vec3 position; vec4 color; float attenuation; vec3 direction; float innerAngle; float angle; float range; }; - WGSL: struct Light { position: vec3<f32>, color: vec4<f32>, attenuation: f32, direction: vec3<f32>, innerAngle: f32, angle: f32, range: f32, }; WGSL yapılarında alanların bildirilmesi için açık sözdiziminin getirilmesi, daha fazla netlik isteğini vurgular ve gölgelendiricilerdeki veri yapılarının anlaşılmasını basitleştirir. İşlev Bildirimleri : GLSL float saturate(float x) { return clamp(x, 0.0, 1.0); } : fn saturate(x: f32) -> f32 { return clamp(x, 0.0, 1.0); } WGSL'deki işlevlerin sözdiziminin değiştirilmesi, bildirimlere ve dönüş değerlerine yönelik yaklaşımın birleştirilmesini yansıtarak kodu daha tutarlı ve öngörülebilir hale getirir. Yerleşik işlevler WGSL'de birçok yerleşik GLSL işlevi yeniden adlandırıldı veya değiştirildi. Örneğin: WGSL'deki yerleşik işlevleri yeniden adlandırmak yalnızca adlarını basitleştirmekle kalmaz, aynı zamanda onları daha sezgisel hale getirir; bu da diğer grafik API'lerine aşina olan geliştiriciler için geçiş sürecini kolaylaştırabilir. Gölgelendirici Dönüşümü Projelerini WebGL'den WebGPU'ya dönüştürmeyi planlayanlar için, GLSL'yi otomatik olarak WGSL'ye dönüştürmeye yönelik **[Naga](https://github.com/gfx-rs/naga gibi) araçların bulunduğunu bilmek önemlidir. /)**, GLSL'yi WGSL'ye dönüştürmek için kullanılan bir Rust kütüphanesidir. WebAssembly'ın yardımıyla doğrudan tarayıcınızda bile çalışabilir. Naga'nın desteklediği uç noktalar şunlardır: Konvansiyon Farklılıkları Dokular Geçiş sonrasında ters çevrilmiş görseller şeklinde bir sürprizle karşılaşabilirsiniz. Uygulamaları OpenGL'den Direct3D'ye (veya tersi) aktaranlar bu klasik sorunla zaten karşı karşıya kalmışlardır. OpenGL ve WebGL bağlamında dokular genellikle başlangıç pikseli sol alt köşeye karşılık gelecek şekilde yüklenir. Ancak pratikte birçok geliştirici görselleri sol üst köşeden başlayarak yüklüyor ve bu da ters çevrilmiş görsel hatasına yol açıyor. Bununla birlikte, bu hata diğer faktörlerle telafi edilebilir ve sonuçta sorun ortadan kaldırılabilir. OpenGL'den farklı olarak Direct3D ve Metal gibi sistemler geleneksel olarak dokuların başlangıç noktası olarak sol üst köşeyi kullanır. Bu yaklaşımın birçok geliştirici için en sezgisel yaklaşım olduğunu göz önünde bulundurarak WebGPU'nun yaratıcıları bu uygulamayı izlemeye karar verdi. Görünüm Alanı WebGL kodunuz çerçeve arabelleğinden piksel seçiyorsa WebGPU'nun farklı bir koordinat sistemi kullanmasına hazırlıklı olun. Koordinatları düzeltmek için basit bir "y = 1,0 - y" işlemini uygulamanız gerekebilir. Klip Alanları Bir geliştirici, nesnelerin beklenenden daha erken kırpılması veya kaybolması gibi bir sorunla karşılaştığında, bu genellikle derinlik alanındaki farklılıklarla ilgilidir. WebGL ile WebGPU arasında, klip alanının derinlik aralığını tanımlama şekilleri açısından bir fark vardır. WebGL -1 ile 1 arasında bir aralık kullanırken WebGPU, Direct3D, Metal ve Vulkan gibi diğer grafik API'lerine benzer şekilde 0 ile 1 arasında bir aralık kullanır. Bu karar, diğer grafik API'leriyle çalışırken belirlenen 0'dan 1'e kadar bir aralık kullanmanın çeşitli avantajları nedeniyle verildi. Modelinizin konumlarını klip alanına dönüştürmenin ana sorumluluğu projeksiyon matrisine aittir. Kodunuzu uyarlamanın en basit yolu, projeksiyon matrisinizin çıktılarının 0 ila 1 aralığında olmasını sağlamaktır. gl-matrix gibi kitaplıkları kullananlar için basit bir çözüm var: işlevini kullanmak yerine, ; diğer matris işlemleri için de benzer işlevler mevcuttur. perspective perspectiveZO if (webGPU) { // Creates a matrix for a symetric perspective-view frustum // using left-handed coordinates mat4.perspectiveZO(out, Math.PI / 4, ...); } else { // Creates a matrix for a symetric perspective-view frustum // based on the default handedness and default near // and far clip planes definition. mat4.perspective(out, Math.PI / 4, …); } Ancak bazen elinizde mevcut bir projeksiyon matrisiniz olabilir ve onun kaynağını değiştiremezsiniz. Bu durumda, bunu 0'dan 1'e kadar bir aralığa dönüştürmek için projeksiyon matrisinizi, derinlik aralığını düzelten başka bir matrisle önceden çarpabilirsiniz. WebGPU İpuçları ve Püf Noktaları Şimdi WebGPU ile çalışmaya yönelik bazı ipuçlarını ve püf noktalarını tartışalım. Kullandığınız boru hattı sayısını en aza indirin. Ne kadar çok işlem hattı kullanırsanız, o kadar çok durum değişimine sahip olursunuz ve performans da o kadar az olur; Varlıklarınızın nereden geldiğine bağlı olarak bu önemsiz olmayabilir. İşlem hatlarını önceden oluşturun Bir işlem hattı oluşturmak ve bunu hemen kullanmak işe yarayabilir ancak bu önerilmez. Bunun yerine hemen geri dönen işlevler oluşturun ve farklı bir iş parçacığı üzerinde çalışmaya başlayın. İşlem hattını kullandığınızda yürütme kuyruğunun, bekleyen işlem hattı oluşturma işlemlerinin tamamlanmasını beklemesi gerekir. Bu, önemli performans sorunlarına neden olabilir. Bunu önlemek için işlem hattını oluşturma ile ilk kullanma arasında biraz zaman bıraktığınızdan emin olun. Veya daha da iyisi, değişkenlerini kullanın! Söz, herhangi bir duraklama olmadan boru hattı kullanıma hazır olduğunda çözüme kavuşur. create*PipelineAsync device.createComputePipelineAsync({ compute: { module: shaderModule, entryPoint: 'computeMain' } }).then((pipeline) => { const commandEncoder = device.createCommandEncoder(); const passEncoder = commandEncoder.beginComputePass(); passEncoder.setPipeline(pipeline); passEncoder.setBindGroup(0, bindGroup); passEncoder.dispatchWorkgroups(128); passEncoder.end(); device.queue.submit([commandEncoder.finish()]); }); RenderBundles'ı kullanın İşleme paketleri önceden kaydedilmiş, kısmi, yeniden kullanılabilir işleme geçişleridir. Çoğu işleme komutunu içerebilirler (görüntü alanını ayarlama gibi şeyler hariç) ve daha sonra gerçek bir işleme geçişinin parçası olarak "tekrar oynatılabilirler". const renderPass = encoder.beginRenderPass(descriptor); renderPass.setPipeline(renderPipeline); renderPass.draw(3); renderPass.executeBundles([renderBundle]); renderPass.setPipeline(renderPipeline); renderPass.draw(3); renderPass.end(); İşleme paketleri, normal işleme geçiş komutlarıyla birlikte yürütülebilir. İşleme geçiş durumu, her paket yürütmesinden önce ve sonra varsayılanlara sıfırlanır. Bu öncelikle çizimin JavaScript yükünü azaltmak için yapılır. Yaklaşımdan bağımsız olarak GPU performansı aynı kalır. Özet WebGPU'ya geçiş, grafik API'lerini değiştirmekten daha fazlası anlamına gelir. Bu aynı zamanda çeşitli grafik API'lerinin başarılı özelliklerini ve uygulamalarını birleştirerek web grafiklerinin geleceğine doğru atılmış bir adımdır. Bu geçiş, teknik ve felsefi değişikliklerin kapsamlı bir şekilde anlaşılmasını gerektirir, ancak faydaları önemlidir. Yararlı Kaynaklar ve Bağlantılar: WebGPU — Tüm çekirdekler, tuvalin hiçbiri Construct'ta WebGL'den WebGPU'ya Alain Galvan'dan ham WebGPU eğitimi Brandon Jones'tan WebGPU En İyi Uygulamaları WebGL + WebGPU Buluşması - Temmuz 2023 Bağlantısı