من WebGL إلى WebGPU

François Beaufort
François Beaufort

بصفتك مطوّر WebGL، قد تشعر بالخوف والتشويق في الوقت نفسه لبدء استخدام WebGPU، وهو البديل لواجهة WebGL الذي يقدّم ميزات واجهة برمجة تطبيقات الرسومات الحديثة إلى الويب.

من المطمئن معرفة أنّ WebGL وWebGPU يتشاركان العديد من المفاهيم الأساسية. تتيح لك كلتا واجهات برمجة التطبيقات تشغيل برامج صغيرة تُعرف باسم "برامج معالجة الألوان" على وحدة معالجة الرسومات. يتيح WebGL استخدام برامج تشويش رؤوس الأشكال وبرامج تشويش الأجزاء، بينما يتيح WebGPU أيضًا استخدام برامج تشويش العمليات الحسابية. يستخدم WebGL لغة OpenGL Shading Language (GLSL)، بينما يستخدم WebGPU لغة WebGPU Shading Language (WGSL). على الرغم من اختلاف اللغتين، إلا أن المفاهيم الأساسية هي نفسها في الغالب.

مع أخذ ذلك في الاعتبار، تُبرز هذه المقالة بعض الاختلافات بين WebGL وWebGPU لمساعدتك في البدء.

حالة عامة

يحتوي WebGL على الكثير من الحالات الشاملة. تسري بعض الإعدادات على جميع عمليات العرض، مثل ربط الزخارف والمورد الاحتياطي. يمكنك إعداد هذه الحالة العامة من خلال استدعاء دوال مختلفة لواجهة برمجة التطبيقات، وتظل سارية إلى أن يتم تغييرها. تُعد الحالة العالمية في WebGL مصدرًا رئيسيًا للأخطاء، حيث إنه من السهل أن ننسى تغيير الإعداد العام. بالإضافة إلى ذلك، تجعل الحالة العامة مشاركة الرمز البرمجي أمرًا صعبًا، لأنّ المطوّرين عليهم الحذر من تغيير الحالة العامة عن طريق الخطأ بطريقة تؤثّر في أجزاء أخرى من الرمز البرمجي.

‫WebGPU هي واجهة برمجة تطبيقات لا تعتمد على الحالة، ولا تحافظ على حالة عامة. بدلاً من ذلك، يستخدم مفهوم مسار العرض لتضمين جميع حالات العرض التي كانت عالمية في WebGL. يحتوي مسار الإحالة الناجحة على معلومات، مثل عمليات الدمج والطوبولوجيا والسمات التي يجب استخدامها. مسار الإحالة الناجحة غير قابل للتغيير. إذا كنت ترغب في تغيير بعض الإعدادات، فستحتاج إلى إنشاء مسار آخر. تستخدم WebGPU أيضًا برامج ترميز الأوامر لتجميع الأوامر معًا وتنفيذها بالترتيب الذي تم تسجيلها به. ويفيد هذا في رسم خريطة الظل، على سبيل المثال، حيث يمكن للتطبيق تسجيل عدة عمليات بث للأوامر، حيث يمكن للتطبيق تسجيل عدة عمليات بث لخريطة الظل، بتمريرة واحدة فوق الكائنات.

باختصار، بما أنّ نموذج الحالة الشاملة في WebGL جعل إنشاء مكتبات وتطبيقات قوية وقابلة للتجميع أمرًا صعبًا وحساسًا، قلّل WebGPU بشكل كبير من مقدار الحالة التي يحتاج المطوّرون إلى تتبُّعها أثناء إرسال الأوامر إلى وحدة معالجة الرسومات.

عدم المزامنة بعد الآن

في وحدات معالجة الرسومات، لا يكون إرسال الأوامر والانتظار عليها بشكل متزامن عادةً فعّالاً، لأنّ ذلك قد يؤدي إلى تنظيف مسار الإرسال وتسبب فقاعات. وينطبق ذلك بشكل خاص على WebGPU وWebGL اللذَين يستخدمان بنية متعددة العمليات مع تشغيل برنامج تشغيل وحدة معالجة الرسومات في عملية منفصلة عن JavaScript.

في WebGL، على سبيل المثال، يتطلّب استدعاء gl.getError() استخدام IPC متزامن من عملية JavaScript إلى عملية وحدة معالجة الرسومات والعكس. ويمكن أن يؤدي ذلك إلى حدوث فقاعة على جانب وحدة المعالجة المركزية أثناء تواصل العمليتين.

لتجنُّب هذه الفقاعات، تم تصميم WebGPU ليكون غير متزامن تمامًا. يحدث نموذج الخطأ وجميع العمليات الأخرى بشكل غير متزامن. على سبيل المثال، عند إنشاء نسيج، يبدو أنّ العملية قد نجحت على الفور، حتى إذا كان النسيج خطأً في الواقع. لا يمكنك اكتشاف الخطأ إلا بشكل غير متزامن. يحافظ هذا التصميم على خلوّ عملية التواصل بين العمليات من أي مشاكل ويمنح التطبيقات أداءً موثوقًا.

أدوات تظليل الحوسبة

برامج تظليل الحوسبة هي برامج يتم تشغيلها على وحدة معالجة الرسومات لإجراء عمليات حسابية للأغراض العامة. ولا تتوفّر إلا في WebGPU، وليس في WebGL.

وعلى عكس برامج تشفير قمة الالتقاط وبرامج تشفير أجزاء الصورة، لا تقتصر هذه البرامج على معالجة الرسومات، ويمكن استخدامها لمجموعة كبيرة من المهام، مثل التعلّم الآلي ومحاكاة الفيزياء والحساب العلمي. يتم تنفيذ برامج shaders الحسابية بشكل موازٍ من خلال مئات أو حتى آلاف سلاسل المهام، ما يجعلها فعالة جدًا في معالجة مجموعات البيانات الكبيرة. اطّلِع على مزيد من المعلومات عن المعالجة باستخدام وحدة معالجة الرسومات ومزيد من التفاصيل في هذه المقالة الشاملة عن WebGPU.

معالجة إطارات الفيديو

تتضمن معالجة لقطات الفيديو باستخدام JavaScript وWebAssembly بعض العيوب، مثل تكلفة نسخ البيانات من ذاكرة وحدة معالجة الرسومات إلى ذاكرة وحدة المعالجة المركزية، والتوازي المحدود الذي يمكن تحقيقه باستخدام وحدات العمل وخيوط وحدة المعالجة المركزية. لا تفرض WebGPU هذه القيود، ما يجعلها مناسبة تمامًا لمعالجة لقطات الفيديو بفضل دمجها الوثيق مع واجهة برمجة التطبيقات WebCodecs.

يوضح مقتطف الرمز التالي كيفية استيراد VideoFrame كزخرفة خارجية في WebGPU ومعالجتها. يمكنك تجربة هذا الإصدار التجريبي.

// 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() تلقائيًا جهاز GPU قد لا يتطابق مع إمكانات الجهاز المادي، بل يعرض أدنى حدّ معقول من جميع وحدات معالجة الرسومات. من خلال مطالبة المطوّرين بطلب حدود الأجهزة، تضمن WebGPU تشغيل التطبيقات على أكبر عدد ممكن من الأجهزة.

معالجة لوحة الرسم

تدير WebGL اللوحة تلقائيًا بعد إنشاء سياق WebGL وتقديم سمات السياق، مثل alpha أو antialias أو colorSpace أو depth أو preserveDrawingBuffer أو stencil.

من ناحية أخرى، تتطلّب WebGPU منك إدارة اللوحة بنفسك. على سبيل المثال، لتحقيق ميزة إزالة التمويه في WebGPU، عليك إنشاء نسيج متعدد العيّنات وعرضه. بعد ذلك، يمكنك تحويل النسيج المتعدد النماذج إلى نسيج عادي ورسم هذا النسيج على اللوحة. تتيح لك هذه الإدارة اليدوية إمكانية الإخراج إلى أي عدد تريده من اللوحات من عنصر GPUDevice واحد. وفي المقابل، يمكن لـ WebGL إنشاء سياق واحد فقط لكل لوحة.

اطّلِع على العرض التجريبي لميزة "WebGPU Multiple Canvases".

من الناحية الجانبية، تفرض المتصفحات حاليًا حدًا أقصى على عدد لوحات WebGL في كل صفحة. في وقت كتابة هذه المقالة، يمكن لمتصفّحَي Chrome وSafari استخدام ما يصل إلى 16 لوحة WebGL في الوقت نفسه، ويمكن لمتصفّح Firefox إنشاء ما يصل إلى 200 لوحة. من ناحية أخرى، ما من حدّ أقصى لعدد لوحات WebGPU لكل صفحة.

لقطة شاشة تعرِض الحد الأقصى لعدد لوحات WebGL في متصفّحات Safari وChrome وFirefox
الحد الأقصى لعدد لوحات WebGL في Safari وChrome وFirefox (من اليمين إلى اليسار) - العرض التجريبي.

رسائل خطأ مفيدة

يوفّر WebGPU تسلسل استدعاء لكل رسالة يتم عرضها من واجهة برمجة التطبيقات. وهذا يعني أنّه يمكنك الاطّلاع بسرعة على مكان حدوث الخطأ في الرمز البرمجي، ما يساعد في تصحيح الأخطاء وإصلاحها.

بالإضافة إلى توفير تسلسل استدعاء الدوال البرمجية، تكون رسائل خطأ WebGPU سهلة الفهم وقابلة للتنفيذ. تتضمّن رسائل الخطأ عادةً وصفًا للخطأ واقتراحات حول كيفية إصلاحه.

تتيح لك WebGPU أيضًا توفير label مخصّص لكل عنصر WebGPU. ويستخدم المتصفّح هذا التصنيف بعد ذلك في رسائل GPUError وتحذيرات وحدة التحكّم وأدوات مطوّري المتصفّح.

من الأسماء إلى الفهارس

في WebGL، يتم ربط العديد من العناصر بالأسماء. على سبيل المثال، يمكنك تعريف متغيّر موحد يُسمى myUniform في GLSL والحصول على موقعه باستخدام gl.getUniformLocation(program, 'myUniform'). يُعدّ ذلك مفيدًا لأنّه سيظهر لك خطأ إذا أخطأت في كتابة اسم متغيّر الزيّ.

من ناحية أخرى، في WebGPU، يكون كل شيء مرتبطًا بالكامل من خلال إزاحة أو فهرس البايت (يُشار إليه غالبًا باسم الموقع). وتقع على عاتقك مسؤولية مواءمة مواضع الرمز في WGSL وJavaScript.

إنشاء صور Mipmap

في WebGL، يمكنك إنشاء مستوى 0 من mip للّوحة ثمّ استدعاء gl.generateMipmap(). وسينشئ لك WebGL بعد ذلك جميع مستويات mip الأخرى.

في WebGPU، عليك إنشاء خرائط MIP بنفسك. لا تتوفّر دالة مضمّنة لإجراء ذلك. يمكنك الاطّلاع على مناقشة المواصفات لمعرفة المزيد من المعلومات عن القرار. يمكنك استخدام مكتبات مفيدة مثل webgpu-utils لإنشاء خرائط MIP أو التعرّف على كيفية إجراء ذلك بنفسك.

المخازن المؤقتة للتخزين وزخارف التخزين

تتوافق المخزن المؤقت الموحَّد مع كل من WebGL وWebGPU، كما تسمح لك بتمرير معلمات ثابتة ذات حجم محدود إلى أدوات التظليل. المخازن المؤقتة للتخزين، التي تشبه إلى حد كبير الموارد الاحتياطية الموحدة، لا تتوافق إلا مع WebGPU، وهي أكثر قوة ومرونة من الموارد الاحتياطية الموحدة.

  • يمكن أن تكون البيانات التي يتم تمريرها إلى أدوات التظليل أكبر بكثير من الموارد الاحتياطية المنتظمة. على الرغم من أنّ المواصفات تنص على أنّ حجم عمليات ربط ذاكرة التخزين المؤقت الموحّدة يمكن أن يصل إلى 64 كيلوبايت (راجِع maxUniformBufferBindingSize)، فإنّ الحد الأقصى لحجم عملية ربط ذاكرة التخزين المؤقت هو 128 ميغابايت على الأقل في WebGPU (راجِع maxStorageBufferBindingSize).

  • الموارد الاحتياطية للتخزين قابلة للكتابة، وتتوافق مع بعض العمليات البسيطة، في حين تكون الموارد الاحتياطية الموحدة للقراءة فقط. ويسمح ذلك بتنفيذ فئات جديدة من الخوارزميات.

  • تتوافق عمليات ربط مخازن العناصر المؤقتة مع صفائف بحجم وقت التشغيل لتقديم خوارزميات أكثر مرونة، في حين يجب توفير أحجام صفائف العناصر المؤقتة الموحّدة في برنامج التظليل.

لا تتوفّر نسيج التخزين إلا في WebGPU، وهو يمثّل بالنسبة إلى النسيج ما يمثّله مخزن التخزين بالنسبة إلى المخزن الموحّد. وهي أكثر مرونة من مواد النسيج العادية، وتسمح بالكتابة العشوائية (والقراءة أيضًا في المستقبل).

التغييرات في المخزن المؤقت والنسيج

في WebGL، يمكنك إنشاء ذاكرة تخزين مؤقت أو نسيج ثم تغيير حجمه في أي وقت باستخدام gl.bufferData() وgl.texImage2D() على التوالي على سبيل المثال.

في WebGPU، تكون المخازن المؤقتة والقوام غير قابلة للتغيير. وهذا يعني أنّه لا يمكنك تغيير حجمها أو استخدامها أو تنسيقها بعد إنشائها. ويمكنك تغيير محتواها فقط.

الاختلافات في تنسيقات المساحات

في WebGL، يتراوح نطاق مساحة المقطع على محور Z بين -1 و1. في WebGPU، يتراوح نطاق مساحة المقطع في محور Z بين 0 و1. وهذا يعني أنّ الأجسام التي تبلغ قيمة z فيها 0 هي الأقرب إلى الكاميرا، في حين أنّ الأجسام التي تبلغ قيمة z فيها 1 هي الأبعد.

صورة توضيحية لنطاقات مساحة المقطع العرضي للمحور Z في WebGL وWebGPU
تتراوح مساحات المقاطع في محور Z في WebGL وWebGPU.

يستخدم WebGL اصطلاح OpenGL، حيث يكون المحور Y لأعلى ويكون المحور Z باتجاه العارض. يستخدم WebGPU اصطلاح Metal، حيث يكون محور Y للأسفل ومحور Z خارج الشاشة. يُرجى العلم أنّ اتجاه محور Y هو للأسفل في إحداثيات إطار التخزين المؤقت للصور وإحداثيات مساحة العرض وإحداثيات الشريحة/البكسل. في مساحة المقطع، لا يزال اتجاه محور Y للأعلى كما هو الحال في WebGL.

الشكر والتقدير

شكرًا لـ "كورنتين واليز" و"غريغ تافاريس" و"ستيفن وايت" و"كين راسل" و"رايتشل أندرو" على مراجعة هذه المقالة.

أنصحك أيضًا بزيارة WebGPUFundamentals.org للاطّلاع على تفاصيل أكثر حول الاختلافات بين WebGPU وWebGL.