מפתחי WebGL עשויים להרגיש גם רתיעה וגם התלהבות מהאפשרות להתחיל להשתמש ב-WebGPU, יורשו של WebGL שמביא את ההתקדמות של ממשקי ה-API המודרניים לעיבוד גרפיקה לאינטרנט.
חשוב לדעת של-WebGL ול-WebGPU יש הרבה מושגים בסיסיים משותפים. שני ממשקי ה-API מאפשרים להריץ תוכנות קטנות שנקראות תוכנות הצללה (shader) ב-GPU. WebGL תומך בשיידרים של קודקודים ושל שברי קוד, בעוד ש-WebGPU תומך גם בשיידרים של מחשוב. טכנולוגיית WebGL משתמשת ב-Open OpenGL Shading Language (GLSL) ואילו WebGPU משתמש ב-WebGPU Shading Language (WGSL). שתי השפות שונות, אבל העקרונות הבסיסיים שלהן זהים ברובם.
לכן, במאמר הזה נסביר על ההבדלים בין WebGL לבין WebGPU כדי לעזור לכם להתחיל.
מצב גלובלי
ל-WebGL יש מצב גלובלי רב. חלק מההגדרות חלות על כל פעולות הרינדור, כמו הטקסטורות והמאגרים שמקושרים. כדי להגדיר את המצב הגלובלי הזה באמצעות קריאה לפונקציות שונות של ה-API, הוא יישאר בתוקף עד שתשנו אותו. המצב הגלובלי ב-WebGL הוא מקור עיקרי לשגיאות, כי קל לשכוח לשנות הגדרה גלובלית. בנוסף, מצב גלובלי מקשה על שיתוף הקוד, כי המפתחים צריכים להיזהר שלא לשנות בטעות את המצב הגלובלי באופן שמשפיע על חלקים אחרים בקוד.
WebGPU הוא ממשק API ללא שמירת מצב, והוא לא שומר על מצב גלובלי. במקום זאת, הוא משתמש במושג צינור עיבוד נתונים כדי להכיל את כל מצבי הרינדור שהיו גלובליים ב-WebGL. צינור עיבוד נתונים מכיל מידע כמו סוגי המיזוג, הטופולוגיה והמאפיינים שבהם צריך להשתמש. צינור עיבוד נתונים הוא בלתי ניתן לשינוי. אם רוצים לשנות חלק מההגדרות, צריך ליצור צינור עיבוד נתונים נוסף. ב-WebGPU גם משתמשים במקודדי פקודות כדי לקבץ פקודות באצווה ולהפעיל אותן לפי הסדר שבו הן הוקלטו. האפשרות הזו שימושית, למשל, במיפוי צללים, שבו באפליקציה אפשר להקליט כמה מקורות של פקודות במעבר יחיד על האובייקטים, אחד לכל מפת צללים של תאורה.
לסיכום, מודל המצב הגלובלי של WebGL הפך את תהליך היצירה של ספריות ואפליקציות חזקות וניתנות לקומפוזביליות לקשות ושבריריות, ולכן WebGPU הפחית משמעותית את כמות המצב שהמפתחים היו צריכים לעקוב אחריו בזמן שליחת פקודות ל-GPU.
סיום הסנכרון
במעבדי GPU לרוב לא יעיל לשלוח פקודות ולהמתין להן באופן סינכרוני, מכיוון שהדבר עלול לרוקן את צינור עיבוד הנתונים ולגרום לבועות. זה נכון במיוחד ב-WebGPU וב-WebGL, שמשתמשים בארכיטקטורה מרובת תהליכים כשמנהל ה-GPU פועל בתהליך נפרד מ-JavaScript.
לדוגמה, ב-WebGL, קריאה ל-gl.getError()
מחייבת IPC סינכרוני מתהליך ה-JavaScript לתהליך ה-GPU וחזרה ממנו. הדבר עלול לגרום לבעה בצד המעבד (CPU) בזמן ששני התהליכים מתקשרים.
כדי למנוע את הבועות האלה, WebGPU תוכנן להיות אסינכרוני לחלוטין. מודל השגיאות וכל שאר הפעולות מתרחשות באופן אסינכרוני. לדוגמה, כשיוצרים טקסטורה, נראה שהפעולה מצליחה באופן מיידי, גם אם הטקסטורה היא למעשה שגיאה. אפשר לגלות את השגיאה רק באופן אסינכרוני. בזכות העיצוב הזה, ההודעות בין תהליכים שונים נקיות מבועות, וביצועים אמינים של האפליקציות.
תוכנות הצללה (shaders) ל-Compute
תוכנות הצללה למחשוב הן תוכנות שרצות ב-GPU כדי לבצע חישובים לשימוש כללי. הם זמינים רק ב-WebGPU ולא ב-WebGL.
בניגוד לשיפועי קודקודים ושיפועי שברי קוד, הם לא מוגבלים לעיבוד גרפיקה, ואפשר להשתמש בהם למגוון רחב של משימות, כמו למידת מכונה, סימולציה של פיזיקה ומחשוב מדעי. עיבוד הנתונים של Shaders מחשוב מתבצע במקביל על ידי מאות או אלפי חוטים, ולכן הם יעילים מאוד לעיבוד של מערכי נתונים גדולים. מידע נוסף על מחשוב GPU זמין במאמר המקיף הזה על WebGPU.
עיבוד של פריים בסרטון
לעיבוד פריימים של וידאו באמצעות JavaScript ו-WebAssembly יש כמה חסרונות: עלות העתקת הנתונים מהזיכרון של ה-GPU לזיכרון של המעבד (CPU), ויכולת ההצגה הזמנית המוגבלת שניתן להשיג עם עובדים ושרשורים של המעבד (CPU) ל-WebGPU אין את המגבלות האלה, ולכן הוא מתאים במיוחד לעיבוד של פריימים של וידאו, בזכות השילוב ההדוק שלו עם ממשק ה-API של 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()
מחזירה GPUDevice שעשוי שלא להתאים ליכולות החומרה של המכשיר הפיזי, אלא לשותף הנמוך ביותר של כל ה-GPU. כשהמפתחים דורשים לבקש מגבלות על המכשיר, WebGPU מבטיח שהאפליקציות יפעלו בכמה שיותר מכשירים.
טיפול בקנבס
WebGL מנהל את הלוח באופן אוטומטי אחרי שיוצרים הקשר WebGL ומספקים מאפייני הקשר כמו alpha, antialias, colorSpace, depth, preserveDrawingBuffer או stencil.
מצד שני, כדי להשתמש ב-WebGPU אתם צריכים לנהל את אזור העריכה בעצמכם. לדוגמה, כדי לבצע סינון רעשי צבע ב-WebGPU, צריך ליצור טקסטורה עם כמה דגימות ולבצע רינדור אליה. לאחר מכן, פותרים את הטקסטורה עם מספר הדוגמאות לטקסטורה רגילה ומציירים את הטקסטורה הזו על הלוח. הניהול הידני הזה מאפשר לכם להפיק פלט לכמה קנבסים שתרצו מאובייקט GPUDevice יחיד. לעומת זאת, ב-WebGL אפשר ליצור רק הקשר אחד לכל לוח.
כדאי לעיין בהדגמה של WebGPU עם כמה משטחי ציור.
דרך אגב, בדפדפנים יש כרגע מגבלה על מספר משטחי הקנבס של WebGL בכל דף. נכון למועד כתיבת המאמר, ב-Chrome וב-Safari אפשר להשתמש בו-זמנית רק ב-16 משטחי WebGL. ב-Firefox אפשר ליצור עד 200 משטחים כאלה. לעומת זאת, אין הגבלה על מספר משטחי הקנבס של WebGPU בכל דף.
הודעות שגיאה מועילות
WebGPU מספק סטאק קריאות לכל הודעה שמוחזרת מה-API. כך תוכלו לראות במהירות איפה השגיאה התרחשה בקוד, וזה עוזר לניפוי באגים ולתיקון שגיאות.
מעבר למערך השיחות, קל להבין הודעות שגיאה של WebGPU וגם לפעול לפיהן. בדרך כלל, הודעות השגיאה כוללות תיאור של השגיאה והצעות לתיקון שלה.
באמצעות WebGPU אפשר גם לספק label
בהתאמה אישית לכל אובייקט WebGPU. לאחר מכן התווית הזו משמשת את הדפדפן בהודעות GPUError, באזהרות במסוף ובכלים למפתחים בדפדפן.
משמות לאינדקסים
ב-WebGL, הרבה דברים מקושרים באמצעות שמות. לדוגמה, אפשר להצהיר על משתנה אחיד בשם myUniform
ב-GLSL ולקבל את המיקום שלו באמצעות gl.getUniformLocation(program, 'myUniform')
. האפשרות הזו שימושית אם מקבלים שגיאה אם מקלידים את השם של המשתנה האחיד.
לעומת זאת, ב-WebGPU, הכול מחובר באמצעות אופסט בייט או אינדקס (שנקראים לרוב מיקום). באחריותכם לוודא שהמיקומים של הקוד ב-WGSL וב-JavaScript מסונכרנים.
יצירת Mipmap
ב-WebGL, אפשר ליצור מיפוי מיפי ברמה 0 של טקסטורה ואז לבצע קריאה ל-gl.generateMipmap()
. לאחר מכן, WebGL תיצור בשבילכם את כל שאר רמות ה-mip.
ב-WebGPU, אתם צריכים ליצור מפות מיפוי בעצמכם. אין פונקציה מובנית לביצוע הפעולה הזו. מידע נוסף על ההחלטה זמין בדיון בנושא המפרט. אפשר להשתמש בספריות שימושיות כמו webgpu-utils כדי ליצור מפות מיפוי רזולוציה (mipmap), או ללמוד איך לעשות זאת בעצמכם.
מאגרי אחסון וטקסטורות אחסון
מאגרי אחסון אחידים נתמכים גם ב-WebGL וגם ב-WebGPU, ומאפשרים להעביר לשיידרים פרמטרים קבועים בגודל מוגבל. מאגרי אחסון, שנראים כמו מאגרים אחידים, נתמכים רק ב-WebGPU והם חזקים וגמישים יותר ממאגרים אחידים.
מאגרי נתונים לאחסון שיעברו לשכבות השיזוף יכולים להיות גדולים בהרבה ממאגרי נתונים אחידים. לפי המפרט, הגודל המקסימלי של קישורי מאגרי נתונים אחידים הוא 64KB (ראו
maxUniformBufferBindingSize
), אבל הגודל המקסימלי של קישור של מאגר נתונים לאחסון הוא לפחות 128MB ב-WebGPU (ראוmaxStorageBufferBindingSize
).אפשר לכתוב במאגרי שטחי האחסון, והם תומכים בחלק מהפעולות האטומיות. לעומת זאת, מאגרי שטחי אחסון אחידים הם לקריאה בלבד. כך אפשר ליישם סוגים חדשים של אלגוריתמים.
קישורי מאגרי נתונים זמניים תומכים במערכים בגודל של זמן הריצה לצורך אלגוריתמים גמישים יותר, בעוד שגדלים אחידים של מערכי מאגרים זמניים צריכים להיות מסופקים בשדר.
יש תמיכה בטקסטורות אחסון רק ב-WebGPU, והן למעשה מה שמאגרי אחסון הם למאגרי אחסון אחידים. הם גמישים יותר מטקסטורות רגילות, והם תומכים בכתיבה בגישה אקראית (וגם בקריאה בעתיד).
שינויים של מאגר נתונים זמני ומרקם
ב-WebGL, אפשר ליצור מאגר נתונים זמני או טקסטורה ואז לשנות את הגודל שלו בכל שלב באמצעות gl.bufferData()
ו-gl.texImage2D()
בהתאמה.
ב-WebGPU, מאגרים וטקסטורות הם בלתי ניתנים לשינוי. המשמעות היא שלא תוכלו לשנות את הגודל, השימוש או הפורמט שלהם אחרי שייווצרו. אפשר רק לשנות את התוכן שלהם.
הבדלים בין המרחבים המשותפים
ב-WebGL, הטווח של הקליפ על Z הוא בין 1- ל-1. ב-WebGPU, הטווח של מרחב החיתוך Z הוא מ-0 ל-1. כלומר, אובייקטים עם ערך z של 0 קרובים יותר למצלמה, ואובייקטים עם ערך z של 1 רחוקים יותר.
ב-WebGL נעשה שימוש במוסכמה של OpenGL, שבה ציר Y הוא למעלה וציר Z הוא לכיוון הצופה. ב-WebGPU נעשה שימוש בהסכם של Metal, שבו ציר Y נמצא למטה וציר Z נמצא מחוץ למסך. שימו לב שהכיוון של ציר ה-Y למטה בקואורדינטה של מאגר נתונים זמני, קואורדינטות של אזור תצוגה וקואורדינטה שבר/פיקסל. בשטח הקליפ, הכיוון של ציר ה-Y עדיין למעלה כמו ב-WebGL.
תודות
תודה ל-Corentin Wallez, Gregg Tavares, Stephen White, Ken Russell ו-Rachel Andrew על בדיקת המאמר הזה.
אני גם ממליץ על WebGPUFundamentals.org כדי להבין לעומק את ההבדלים בין WebGPU לבין WebGL.