WebGL से WebGPU तक

François Beaufort
François Beaufort

WebGL डेवलपर के तौर पर, आपको WebGPU का इस्तेमाल शुरू करने में डर भी लग सकता है और उत्साह भी हो सकता है. WebGPU, WebGL का नया वर्शन है. यह वेब पर मॉडर्न ग्राफ़िक्स एपीआई की नई सुविधाएं उपलब्ध कराता है.

यह जानकर अच्छा लगा कि WebGL और WebGPU, कई मुख्य सिद्धांतों को शेयर करते हैं. दोनों एपीआई की मदद से, GPU पर शेडर नाम के छोटे प्रोग्राम चलाए जा सकते हैं. WebGL, वर्टेक्स और फ़्रैगमेंट शेडर के साथ काम करता है. वहीं, WebGPU, कंप्यूट शेडर के साथ भी काम करता है. WebGL, OpenGL Shading Language (GLSL) का इस्तेमाल करता है, जबकि WebGPU, WebGPU Shading Language (WGSL) का इस्तेमाल करता है. दोनों भाषाएं अलग-अलग हैं, लेकिन इनके बुनियादी सिद्धांत काफ़ी हद तक एक जैसे हैं.

इस बात को ध्यान में रखते हुए, इस लेख में WebGL और WebGPU के बीच कुछ अंतर बताए गए हैं, ताकि आपको शुरुआत करने में मदद मिल सके.

ग्लोबल स्टेट

WebGL में बहुत सारी ग्लोबल स्टेट होती हैं. कुछ सेटिंग, रेंडरिंग की सभी कार्रवाइयों पर लागू होती हैं. जैसे, कौनसी बनावट और बफ़र बाइंड किए गए हैं. अलग-अलग एपीआई फ़ंक्शन कॉल करके, इस ग्लोबल स्टेट को सेट किया जाता है. यह तब तक लागू रहती है, जब तक इसे बदला नहीं जाता. WebGL में ग्लोबल स्टेट, गड़बड़ियों का मुख्य सोर्स है. ऐसा इसलिए, क्योंकि ग्लोबल सेटिंग को बदलना भूलना आसान है. इसके अलावा, ग्लोबल स्टेट की वजह से कोड शेयर करना मुश्किल हो जाता है. ऐसा इसलिए, क्योंकि डेवलपर को यह ध्यान रखना होता है कि वे गलती से ग्लोबल स्टेट में इस तरह से बदलाव न करें जिससे कोड के अन्य हिस्सों पर असर पड़े.

WebGPU एक स्टेटलेस एपीआई है. यह ग्लोबल स्टेट को बनाए नहीं रखता. इसके बजाय, यह पाइपलाइन के कॉन्सेप्ट का इस्तेमाल करता है, ताकि रेंडरिंग की उस सभी स्थिति को शामिल किया जा सके जो WebGL में ग्लोबल थी. पाइपलाइन में यह जानकारी होती है कि किस तरह की ब्लेंडिंग, टोपोलॉजी, और एट्रिब्यूट का इस्तेमाल करना है. पाइपलाइन में बदलाव नहीं किया जा सकता. अगर आपको कुछ सेटिंग बदलनी हैं, तो आपको दूसरी पाइपलाइन बनानी होगी. WebGPU, कमांड एनकोडर का इस्तेमाल करके, कमांड को एक साथ बैच करता है और उन्हें उसी क्रम में लागू करता है जिस क्रम में उन्हें रिकॉर्ड किया गया था. यह शैडो मैपिंग के लिए फ़ायदेमंद है. उदाहरण के लिए, ऑब्जेक्ट पर एक ही पास में, ऐप्लिकेशन कई कमांड स्ट्रीम रिकॉर्ड कर सकता है. हर लाइट के शैडो मैप के लिए एक कमांड स्ट्रीम रिकॉर्ड की जा सकती है.

संक्षेप में कहें, तो WebGL के ग्लोबल स्टेट मॉडल की वजह से, मज़बूत और कंपोज़ेबल लाइब्रेरी और ऐप्लिकेशन बनाना मुश्किल और कमज़ोर हो गया था. वहीं, WebGPU ने उस स्टेट की मात्रा को काफ़ी कम कर दिया है जिसे डेवलपर को GPU को कमांड भेजते समय ट्रैक करना होता है.

अब सिंक न करें

जीपीयू पर, आम तौर पर कमांड भेजने और उनके सिंक्रोनस होने का इंतज़ार करना सही नहीं होता. इससे पाइपलाइन फ़्लश हो सकती है और बबल बन सकते हैं. यह खास तौर पर WebGPU और WebGL में होता है. ये मल्टी-प्रोसेस आर्किटेक्चर का इस्तेमाल करते हैं. इनमें GPU ड्राइवर, JavaScript से अलग प्रोसेस में चलता है.

उदाहरण के लिए, WebGL में gl.getError() को कॉल करने के लिए, JavaScript प्रोसेस से GPU प्रोसेस और वापस तक सिंक्रोनस आईपीसी की ज़रूरत होती है. इन दोनों प्रोसेस के बीच कम्यूनिकेशन होने की वजह से, सीपीयू पर लोड बढ़ सकता है.

इन बबल्स से बचने के लिए, WebGPU को पूरी तरह से एसिंक्रोनस बनाया गया है. गड़बड़ी का मॉडल और अन्य सभी कार्रवाइयां एसिंक्रोनस तरीके से होती हैं. उदाहरण के लिए, जब कोई टेक्सचर बनाया जाता है, तो ऑपरेशन तुरंत पूरा हो जाता है. भले ही, टेक्सचर में कोई गड़बड़ी हो. गड़बड़ी का पता सिर्फ़ एसिंक्रोनस तरीके से लगाया जा सकता है. इस डिज़ाइन की वजह से, क्रॉस-प्रोसेस कम्यूनिकेशन में कोई रुकावट नहीं आती. साथ ही, ऐप्लिकेशन को भरोसेमंद परफ़ॉर्मेंस मिलती है.

कंप्यूट शेडर

कंप्यूट शेडर ऐसे प्रोग्राम होते हैं जो सामान्य कंप्यूटेशन करने के लिए, जीपीयू पर चलते हैं. ये सिर्फ़ WebGPU में उपलब्ध हैं, WebGL में नहीं.

वर्टेक्स और फ़्रैगमेंट शेडर के उलट, ये सिर्फ़ ग्राफ़िक्स प्रोसेसिंग के लिए नहीं होते. इनका इस्तेमाल कई तरह के कामों के लिए किया जा सकता है. जैसे, मशीन लर्निंग, फ़िज़िक्स सिमुलेशन, और साइंटिफ़िक कंप्यूटिंग. कंप्यूट शेडर को सैकड़ों या हज़ारों थ्रेड एक साथ एक्ज़ीक्यूट करते हैं. इसलिए, ये बड़े डेटासेट को प्रोसेस करने के लिए बहुत कारगर होते हैं. जीपीयू कंप्यूट के बारे में जानें. साथ ही, WebGPU के बारे में इस लेख में ज़्यादा जानकारी पाएं.

वीडियो फ़्रेम को प्रोसेस किया जा रहा है

JavaScript और WebAssembly का इस्तेमाल करके वीडियो फ़्रेम प्रोसेस करने के कुछ नुकसान हैं: जीपीयू मेमोरी से सीपीयू मेमोरी में डेटा कॉपी करने का खर्च और वर्कर और सीपीयू थ्रेड के साथ हासिल की जा सकने वाली सीमित पैरललिज़्म. WebGPU में ये सीमाएं नहीं हैं. इसलिए, यह WebCodecs API के साथ इंटिग्रेट होने की वजह से, वीडियो फ़्रेम को प्रोसेस करने के लिए सबसे सही है.

यहां दिए गए कोड स्निपेट में, WebGPU में VideoFrame को बाहरी टेक्सचर के तौर पर इंपोर्ट करने और उसे प्रोसेस करने का तरीका बताया गया है. इस डेमो को आज़माएं.

// Init WebGPU device and pipeline...
// Configure canvas context...
// Feed camera stream to video...

(function render() {
  const videoFrame = new VideoFrame(video);
  applyFilter(videoFrame);
  requestAnimationFrame(render);
})();

function applyFilter(videoFrame) {
  const texture = device.importExternalTexture({ source: videoFrame });
  const bindgroup = device.createBindGroup({
    layout: pipeline.getBindGroupLayout(0),
    entries: [{ binding: 0, resource: texture }],
  });
  // Finally, submit commands to GPU
}

डिफ़ॉल्ट रूप से ऐप्लिकेशन पोर्ट करने की सुविधा

WebGPU में, आपको limits का अनुरोध करना होगा. डिफ़ॉल्ट रूप से, requestDevice() एक GPUDevice ऑब्जेक्ट दिखाता है. ऐसा हो सकता है कि यह ऑब्जेक्ट, फ़िज़िकल डिवाइस के हार्डवेयर की क्षमताओं से मेल न खाए. हालांकि, यह सभी जीपीयू के लिए एक सामान्य और सबसे कम डिनॉमिनेटर होता है. WebGPU, डेवलपर को डिवाइस की सीमाओं के बारे में अनुरोध करने के लिए कहता है. इससे यह पक्का होता है कि ऐप्लिकेशन ज़्यादा से ज़्यादा डिवाइसों पर काम करेंगे.

कैनवस को मैनेज करना

WebGL कॉन्टेक्स्ट बनाने और कॉन्टेक्स्ट एट्रिब्यूट देने के बाद, WebGL अपने-आप कैनवस को मैनेज करता है. जैसे, ऐल्फ़ा, एंटीएलियास, कलरस्पेस, डेप्थ, प्रिज़र्वड्रॉइंगबफ़र या स्टेंसिल.

दूसरी ओर, WebGPU में आपको कैनवस को खुद मैनेज करना होता है. उदाहरण के लिए, WebGPU में ऐंटीएलियासिंग करने के लिए, आपको एक मल्टीसैंपल टेक्सचर बनाना होगा और उसे रेंडर करना होगा. इसके बाद, मल्टीसैंपल टेक्सचर को सामान्य टेक्सचर में बदला जाता है और उस टेक्सचर को कैनवस पर बनाया जाता है. मैन्युअल तरीके से मैनेज करने की सुविधा की मदद से, एक GPUDevice ऑब्जेक्ट से जितने चाहें उतने कैनवस पर आउटपुट दिया जा सकता है. इसके उलट, WebGL हर कैनवस के लिए सिर्फ़ एक कॉन्टेक्स्ट बना सकता है.

WebGPU के एक से ज़्यादा कैनवस का डेमो देखें.

एक और बात यह है कि फ़िलहाल, ब्राउज़र में हर पेज के लिए WebGL कैनवस की संख्या सीमित होती है. यह लेख लिखते समय, Chrome और Safari एक साथ सिर्फ़ 16 WebGL कैनवस का इस्तेमाल कर सकते हैं. वहीं, Firefox 200 WebGL कैनवस बना सकता है. दूसरी ओर, हर पेज पर WebGPU कैनवस की संख्या की कोई सीमा नहीं है.

Safari, Chrome, और Firefox ब्राउज़र में ज़्यादा से ज़्यादा WebGL कैनवस दिखाने वाला स्क्रीनशॉट
Safari, Chrome, और Firefox (बाएं से दाएं) में WebGL कैनवस की ज़्यादा से ज़्यादा संख्या - डेमो.

गड़बड़ी के मददगार मैसेज

WebGPU, एपीआई से मिले हर मैसेज के लिए कॉल स्टैक उपलब्ध कराता है. इसका मतलब है कि आपको तुरंत पता चल जाएगा कि आपके कोड में गड़बड़ी कहां हुई है. यह गड़बड़ियों को डीबग करने और उन्हें ठीक करने के लिए मददगार है.

WebGPU के गड़बड़ी वाले मैसेज में कॉल स्टैक के साथ-साथ, गड़बड़ी के बारे में आसानी से समझ आने वाली जानकारी भी होती है. साथ ही, गड़बड़ी को ठीक करने के लिए कार्रवाई करने का तरीका भी बताया जाता है. गड़बड़ी के मैसेज में आम तौर पर, गड़बड़ी के बारे में जानकारी और उसे ठीक करने के तरीके के बारे में सुझाव शामिल होते हैं.

WebGPU की मदद से, हर WebGPU ऑब्जेक्ट के लिए कस्टम label भी दिया जा सकता है. इसके बाद, ब्राउज़र इस लेबल का इस्तेमाल GPUError मैसेज, कंसोल चेतावनियों, और ब्राउज़र डेवलपर टूल में करता है.

नामों से इंडेक्स तक

WebGL में, कई चीज़ें नामों से जुड़ी होती हैं. उदाहरण के लिए, GLSL में myUniform नाम का एक यूनिफ़ॉर्म वैरिएबल तय किया जा सकता है. साथ ही, gl.getUniformLocation(program, 'myUniform') का इस्तेमाल करके इसकी जगह की जानकारी पाई जा सकती है. यह सुविधा तब काम आती है, जब यूनिफ़ॉर्म वैरिएबल का नाम गलत टाइप करने पर आपको गड़बड़ी का मैसेज मिलता है.

दूसरी ओर, WebGPU में हर चीज़ को बाइट ऑफ़सेट या इंडेक्स (जिसे अक्सर जगह कहा जाता है) से पूरी तरह कनेक्ट किया जाता है. WGSL और JavaScript में कोड की जगहों को सिंक में रखना आपकी ज़िम्मेदारी है.

मिपमैप जनरेट करना

WebGL में, टेक्सचर का लेवल 0 मिप बनाया जा सकता है. इसके बाद, gl.generateMipmap() को कॉल किया जा सकता है. इसके बाद, WebGL आपके लिए अन्य सभी मिप लेवल जनरेट करेगा.

WebGPU में, आपको मिपमैप खुद जनरेट करने होंगे. इसके लिए, कोई बिल्ट-इन फ़ंक्शन उपलब्ध नहीं है. फ़ैसले के बारे में ज़्यादा जानने के लिए, स्पेसिफ़िकेशन से जुड़ी चर्चा देखें. मिपमैप जनरेट करने के लिए, webgpu-utils जैसी काम की लाइब्रेरी का इस्तेमाल किया जा सकता है. इसके अलावा, खुद मिपमैप जनरेट करने का तरीका भी सीखा जा सकता है.

स्टोरेज बफ़र और स्टोरेज टेक्सचर

यूनिफ़ॉर्म बफ़र, WebGL और WebGPU, दोनों के साथ काम करते हैं. इनकी मदद से, शेडर को सीमित साइज़ के कॉन्सटेंट पैरामीटर पास किए जा सकते हैं. स्टोरेज बफ़र, यूनिफ़ॉर्म बफ़र की तरह ही दिखते हैं. हालांकि, ये सिर्फ़ WebGPU के साथ काम करते हैं. साथ ही, ये यूनिफ़ॉर्म बफ़र से ज़्यादा बेहतर और फ़्लेक्सिबल होते हैं.

  • स्टोरेज बफ़र, यूनिफ़ॉर्म बफ़र की तुलना में, शेडर को पास किए गए डेटा को ज़्यादा समय तक सेव कर सकते हैं. स्पेसिफ़िकेशन के मुताबिक, यूनिफ़ॉर्म बफ़र बाइंडिंग का साइज़ 64 केबी तक हो सकता है (maxUniformBufferBindingSize देखें). हालांकि, WebGPU में स्टोरेज बफ़र बाइंडिंग का ज़्यादा से ज़्यादा साइज़ कम से कम 128 एमबी होता है (maxStorageBufferBindingSize देखें).

  • स्टोरेज बफ़र में डेटा लिखा जा सकता है. साथ ही, ये कुछ एटॉमिक ऑपरेशन के साथ काम करते हैं. वहीं, यूनिफ़ॉर्म बफ़र सिर्फ़ पढ़ने के लिए होते हैं. इससे एल्गोरिदम की नई क्लास लागू की जा सकती हैं.

  • स्टोरेज बफ़र बाइंडिंग, ज़्यादा फ़्लेक्सिबल एल्गोरिदम के लिए रनटाइम-साइज़ वाले ऐरे के साथ काम करती हैं. वहीं, यूनिफ़ॉर्म बफ़र ऐरे के साइज़, शेडर में देने होते हैं.

स्टोरेज टेक्सचर सिर्फ़ WebGPU में काम करते हैं. ये टेक्सचर के लिए वही काम करते हैं जो यूनिफ़ॉर्म बफ़र के लिए स्टोरेज बफ़र करते हैं. ये सामान्य टेक्सचर के मुकाबले ज़्यादा फ़्लेक्सिबल होते हैं. साथ ही, ये रैंडम ऐक्सेस राइट को सपोर्ट करते हैं. आने वाले समय में, ये रैंडम ऐक्सेस रीड को भी सपोर्ट करेंगे.

बफ़र और बनावट में बदलाव

WebGL में, बफ़र या टेक्सचर बनाया जा सकता है. इसके बाद, gl.bufferData() और gl.texImage2D() का इस्तेमाल करके, कभी भी इसका साइज़ बदला जा सकता है. उदाहरण के लिए, ऐसा किया जा सकता है.

WebGPU में, बफ़र और टेक्सचर में बदलाव नहीं किया जा सकता. इसका मतलब है कि एक बार बनाने के बाद, न तो इनके साइज़, इस्तेमाल या फ़ॉर्मैट में बदलाव किया जा सकता है. सिर्फ़ उनके कॉन्टेंट में बदलाव किया जा सकता है.

स्पेस के नामकरण के नियमों में अंतर

WebGL में, Z क्लिप स्पेस की रेंज -1 से 1 तक होती है. WebGPU में, Z क्लिप स्पेस की रेंज 0 से 1 तक होती है. इसका मतलब है कि z वैल्यू 0 वाले ऑब्जेक्ट, कैमरे के सबसे करीब होते हैं. वहीं, z वैल्यू 1 वाले ऑब्जेक्ट सबसे दूर होते हैं.

WebGL और WebGPU में Z क्लिप स्पेस रेंज का इलस्ट्रेशन.
WebGL और WebGPU में Z क्लिप स्पेस की रेंज.

WebGL, OpenGL कन्वेंशन का इस्तेमाल करता है. इसमें Y ऐक्सिस ऊपर की ओर होता है और Z ऐक्सिस, व्यूअर की ओर होता है. WebGPU, Metal के कन्वेंशन का इस्तेमाल करता है. इसमें Y ऐक्सिस नीचे की ओर होता है और Z ऐक्सिस स्क्रीन से बाहर की ओर होता है. ध्यान दें कि फ़्रेमबफ़र कोऑर्डिनेट, व्यूपोर्ट कोऑर्डिनेट, और फ़्रैगमेंट/पिक्सल कोऑर्डिनेट में Y-ऐक्सिस की दिशा नीचे की ओर होती है. क्लिप स्पेस में, Y ऐक्सिस की दिशा अब भी WebGL की तरह ऊपर की ओर होती है.

Acknowledgements

इस लेख की समीक्षा करने के लिए, कोरेंटिन वॉलेज़, ग्रेग टावारेस, स्टीफ़न व्हाइट, केन रसेल, और राहेल ऐंड्रयू का धन्यवाद.

WebGPU और WebGL के बीच के अंतर के बारे में ज़्यादा जानने के लिए, हम WebGPUFundamentals.org पर जाने का सुझाव देते हैं.