WebGPU: ביטול הנעילה של גישת GPU מודרנית בדפדפן

איך WebGPU מאפשרת לכם לנצל את מלוא העוצמה של ה-GPU כדי לשפר את הביצועים של למידת המכונה ואת רינדור הגרפיקה?

WebGPU API החדש מאפשר לשפר משמעותית את הביצועים של עומסי עבודה של גרפיקה ולמידת מכונה. במאמר הזה נסביר איך WebGPU הוא שיפור על פני הפתרון הנוכחי של WebGL, ונציג הצצה לתכונות עתידיות. אבל קודם, נציג הקשר שבו WebGPU פותח.

הקשר ב-WebGPU

WebGL הגיע ל-Chrome בשנת 2011. WebGL מאפשר לאפליקציות אינטרנט לנצל את היתרונות של מעבדי GPU, וכך מאפשר חוויות מדהימות באינטרנט – החל מ-Google Earth ועד לסרטוני מוזיקה אינטראקטיביים, סיורים וירטואליים בנכסי נדל"ן בתלת-ממד ועוד. WebGL מבוסס על משפחת ממשקי ה-API של OpenGL, שפותחה לראשונה בשנת 1992. זה היה לפני הרבה זמן! אפשר רק לדמיין כמה התפתחה חומרת ה-GPU מאז.

כדי לעמוד בקצב האבולוציה הזו, פיתחנו סוג חדש של ממשקי API כדי ליצור אינטראקציה יעילה יותר עם חומרת GPU מודרנית. ממשקי API כמו Direct3D 12,‏ Metal ו-Vulkan. ממשקי ה-API החדשים האלה תמכו בתרחישי שימוש חדשים ומאתגרים לתכנות ב-GPU, כמו ההתפתחות המהירה של למידת המכונה והפיתוחים באלגוריתמים של עיבוד תמונה. WebGPU הוא יורשו של WebGL, והוא מביא לאינטרנט את השיפורים של הסוג החדש הזה של ממשקי API מודרניים.

WebGPU מאפשר הרבה אפשרויות חדשות לתכנות GPU בדפדפן. הוא משקף טוב יותר את אופן הפעולה של חומרת GPU מודרנית, וגם מאפשר להניח יסודות ליכולות מתקדמות יותר של GPU בעתיד. ממשק ה-API נמצא בפיתוח בקבוצה GPU for the Web של W3C מאז 2017, והוא תוצר של שיתוף פעולה בין חברות רבות כמו Apple,‏ Google,‏ Mozilla,‏ Microsoft ו-Intel. עכשיו, אחרי 6 שנים של עבודה, אנחנו שמחים להודיע שאחד מהתוספים הגדולים ביותר לפלטפורמת האינטרנט זמין סוף סוף!

WebGPU זמין עכשיו ב-Chrome 113 ב-ChromeOS, ב-macOS וב-Windows, ובקרוב יהיה זמין בפלטפורמות נוספות. תודה רבה למפתחים אחרים ב-Chromium ול-Intel במיוחד, שעזרו לנו להשיג את זה.

עכשיו נציג כמה תרחישים לדוגמה שמאפשרים להשתמש ב-WebGPU.

מקבלים גישה לעומסי עבודה חדשים של GPU לעיבוד

תכונות של WebGPU כמו compute shaders מאפשרות להעביר ל-GPU סוגים חדשים של אלגוריתמים. לדוגמה, אלגוריתמים שיכולים להוסיף פרטים דינמיים יותר לזירות, לדמות תופעות פיזיות ועוד. יש אפילו עומסי עבודה שקודם אפשר היה לבצע רק ב-JavaScript, ועכשיו אפשר להעביר אותם ל-GPU.

בסרטון הבא מוצג האלגוריתם marching cubes שמשמש ליצירת משולשויות על פני השטח של המטא-כדורים האלה. ב-20 השניות הראשונות של הסרטון, כשהאלגוריתם פועל ב-JavaScript, הוא מתקשה לעמוד בקצב של הדף שפועל רק במהירות של 8 פריימים לשנייה, וכתוצאה מכך האנימציה קטועה. כדי לשמור על הביצועים ב-JavaScript, נצטרך להפחית משמעותית את רמת הפרטים.

ההבדל בין שתי השיטות הוא עצום כשאנחנו מעבירים את אותו אלגוריתם ל-compute shader, כפי שרואים בסרטון אחרי 20 שניות. הביצועים השתפרו באופן משמעותי, והדף פועל עכשיו במהירות חלקה של 60FPS, ועדיין יש הרבה מקום לביצועים טובים יותר עם אפקטים אחרים. בנוסף, הלולאה הראשית של JavaScript בדף תהיה פנויה לחלוטין למשימות אחרות, וכך תבטיח שהאינטראקציות עם הדף יהיו תגובה.

הדגמה של Metaballs

WebGPU מאפשר גם להשתמש באפקטים חזותיים מורכבים שלא היו מעשיים בעבר. בדוגמה הבאה, שנוצרה בספרייה הפופולרית Babylon.js, סימולציית פני האוקיינוס מתבצעת כולה ב-GPU. הדינמיקה הריאליסטית נוצרת מגליות רבות ועצמאיות שמתווספות זו לזו. אבל הדמיה ישירה של כל גל תעלה יותר מדי.

הדגמה של האוקיינוס

לכן, הדגמה משתמשת באלגוריתם מתקדם שנקרא Fast Fourier Transform. במקום לייצג את כל הגלים כנתוני מיקום מורכבים, המערכת משתמשת בנתונים הספקטרליים, שמאפשרים לבצע חישובים בצורה יעילה הרבה יותר. לאחר מכן, בכל פריים נעשה שימוש בטרנספורמציית Fourier כדי להמיר מנתונים ספקטרליים לנתוני מיקום שמייצגים את גובה הגלים.

הסקת מסקנות מהירה יותר בלמידת מכונה

WebGPU שימושי גם כדי לזרז למידת מכונה, שהפכה לשימוש העיקרי ב-GPU בשנים האחרונות.

במשך זמן רב, מפתחים יצירתיים השתמשו ב-WebGL API לצורכי רינדור למטרות אחרות, כמו חישובים של למידת מכונה. עם זאת, כדי לעשות זאת צריך לצייר את הפיקסלים של המשולשים כדי להתחיל את החישובים, ולקפל ולפרוק בזהירות את נתוני הטנסור בטקסטורה במקום לבצע גישה לזיכרון למטרות כלליות יותר.

איור של חוסר היעילות בהרצה של אופרטור ML יחיד באמצעות WebGL, כולל עומסי זיכרון מיותרים, חישובים מיותרים ומספר קטן של ערכים שנכתבים לכל שרשור.
הרצת אופרטור ML יחיד באמצעות WebGL.

כדי להשתמש ב-WebGL בדרך הזו, המפתחים צריכים להתאים את הקוד שלהם בצורה לא נוחה לציפיות של ממשק API שמיועד רק לציור. בשילוב עם חוסר התכונות הבסיסיות כמו גישה לזיכרון משותף בין חישובים, המצב הזה מוביל לעבודה כפולה ולביצועים לא אופטימליים.

עיבוד שגיאות (compute shaders) הוא התכונה החדשה העיקרית של WebGPU, והוא מסיר את נקודות החולשה האלה. פונקציות Compute Shaders מציעות מודל תכנות גמיש יותר שמנצל את האופי המקבילה של המעבדים הגרפיים (GPU) בלי להיות מוגבל על ידי המבנה המחמיר של פעולות הרינדור.

השיפורים השונים ביעילות של שגיאות מחשוב ב-WebGPU, כולל עומסי זיכרון משותפים, חישובים משותפים וכתיבה גמישה בזיכרון.
יעילות של WebGPU compute shader.

שימוש ב-Compute Shaders מאפשר לכם לשתף נתונים ותוצאות חישובים בקבוצות של עבודות של Shaders, וכך לשפר את היעילות. השימוש ב-WebGL יכול להוביל לשיפורים משמעותיים בהשוואה לניסיונות קודמים להשתמש ב-WebGL לאותה מטרה.

לדוגמה של השיפורים ביעילות שאפשר להשיג, העברה ראשונית של מודל של דיפוזיה של תמונה ב-TensorFlow.js מ-WebGL ל-WebGPU מובילה לשיפור של פי 3 בביצועים במגוון חומרות. בחלק מחומרת הבדיקה, התמונה עברה רינדור תוך פחות מ-10 שניות. וכיוון שזו הייתה גרסה מוקדמת, אנחנו מאמינים שאפשר לבצע עוד שיפורים ב-WebGPU וב-TensorFlow.js. מה חדש ב-Web ML בשנת 2023? סשן ב-Google I/O.

אבל WebGPU לא רק מאפשר להשתמש בתכונות של GPU באינטרנט.

תוכנן בראש ובראשונה ל-JavaScript

התכונות שמאפשרות את התרחישים האלה היו זמינות כבר זמן מה למפתחים של מחשבים נייחים ומכשירים ניידים בפלטפורמות ספציפיות. האתגר שלנו היה לחשוף אותן בצורה שתהיה חלק טבעי מפלטפורמת האינטרנט.

WebGPU פותח על סמך ניסיון של יותר מעשור של מפתחים שעשו עבודה מדהימה עם WebGL. הצלחנו להשתמש בבעיות שהם נתקלו בהן, בצווארי בקבוק שהם נתקלו בהם ובבעיות שהם העלו, והעברנו את כל המשוב הזה ל-API החדש.

שמנו לב שמודל המצב הגלובלי של WebGL מקשה על יצירת ספריות ואפליקציות חזקות וניתנות לשימוש חוזר, וגם הופך אותן לפגיעות. כך, WebGPU מפחית באופן משמעותי את כמות המצבים שהמפתחים צריכים לעקוב אחריהם בזמן שליחת הפקודות ל-GPU.

שמענו שדיבוג של אפליקציות WebGL הוא תהליך קשה, ולכן WebGPU כולל מנגנונים גמישים יותר לטיפול בשגיאות שלא פוגעים בביצועים. בנוסף, עשינו מאמצים רבים כדי לוודא שכל הודעה שתקבלו מה-API תהיה קלה להבנה וניתן יהיה לבצע בה פעולות.

גילינו גם שלעיתים קרובות, העלויות הנלוות ליצירת יותר מדי קריאות ל-JavaScript הן צוואר בקבוק באפליקציות WebGL מורכבות. כתוצאה מכך, ה-API של WebGPU פחות מדבר, כך שאפשר להשיג יותר עם פחות קריאות לפונקציות. אנחנו מתמקדים בביצוע אימות כבד מראש, כדי לשמור על לולאת הציור הקריטית יעילה ככל האפשר. בנוסף, אנחנו מציעים ממשקי API חדשים כמו Render Bundles, שמאפשרים להקליט מראש כמויות גדולות של פקודות ציור ולנגן אותן מחדש בקריאה אחת.

כדי להמחיש את ההבדל המשמעותי שאפשר להשיג באמצעות תכונה כמו חבילות רינדור, הנה דוגמה נוספת מ-Babylon.js. המנגנון שלהם לעיבוד גרפיקה של WebGL 2 יכול לבצע את כל הקריאות ל-JavaScript כדי ליצור את התצוגה של גלריית האמנות הזו כ-500 פעמים בשנייה. זה די טוב!

גלריית האמנות

עם זאת, ה-renderer של WebGPU מאפשר תכונה שנקראת Snapshot Rendering. התכונה הזו מבוססת על חבילות רינדור של WebGPUs, ומאפשרת לשלוח את אותה סצנה במהירות גבוהה פי 10. הפחתת העלויות הנלוות באופן משמעותי מאפשרת ל-WebGPU ליצור עיבוד תמונה של סצנות מורכבות יותר, וגם מאפשרת לאפליקציות לבצע יותר פעולות ב-JavaScript במקביל.

לממשקי API מודרניים של גרפיקה יש מוניטין של מורכבות, והם מחליפים את הפשטות בהזדמנויות אופטימיזציה קיצוניות. לעומת זאת, WebGPU מתמקד בתאימות בפלטפורמות שונות, ומטפל בנושאים קשים באופן מסורתי כמו סנכרון משאבים באופן אוטומטי ברוב המקרים.

לכך יש השפעה חיובית: קל ללמוד את WebGPU ולהשתמש בו. התג מסתמך על תכונות קיימות בפלטפורמת האינטרנט לפעולות כמו טעינה של תמונות וסרטונים, ומשתמש בתבניות JavaScript מוכרות כמו Promises לפעולות אסינכרוניות. כך אפשר לצמצם את כמות הקוד הסטנדרטי שנדרש. אפשר להציג את המשולש הראשון במסך בפחות מ-50 שורות קוד.

<canvas id="canvas" width="512" height="512"></canvas>
<script type="module">
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();

  const context = canvas.getContext("webgpu");
  const format = navigator.gpu.getPreferredCanvasFormat();
  context.configure({ device, format });

  const code = `
    @vertex fn vertexMain(@builtin(vertex_index) i : u32) ->
      @builtin(position) vec4f {
       const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1));
       return vec4f(pos[i], 0, 1);
    }
    @fragment fn fragmentMain() -> @location(0) vec4f {
      return vec4f(1, 0, 0, 1);
    }`;
  const shaderModule = device.createShaderModule({ code });
  const pipeline = device.createRenderPipeline({
    layout: "auto",
    vertex: {
      module: shaderModule,
      entryPoint: "vertexMain",
    },
    fragment: {
      module: shaderModule,
      entryPoint: "fragmentMain",
      targets: [{ format }],
    },
  });
  const commandEncoder = device.createCommandEncoder();
  const colorAttachments = [
    {
      view: context.getCurrentTexture().createView(),
      loadOp: "clear",
      storeOp: "store",
    },
  ];
  const passEncoder = commandEncoder.beginRenderPass({ colorAttachments });
  passEncoder.setPipeline(pipeline);
  passEncoder.draw(3);
  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);
</script>

סיכום

אנחנו שמחים לראות את כל האפשרויות החדשות ש-WebGPU מביא לפלטפורמת האינטרנט, ונשמח לראות את כל תרחישי השימוש החדשים והמעניינים שתמצאו ל-WebGPU!

סביבת WebGL כוללת ספריות ותבניות עבודה רבות, ואותה סביבה מוכנה לאמץ את WebGPU. התמיכה ב-WebGPU מתבצעת או כבר הושלמה בספריות WebGL פופולריות רבות של Javascript, ובמקרים מסוימים ליהנות מהיתרונות של WebGPU יכול להיות פשוט כמו שינוי דגל אחד.

Babylon.js,‏ Construct 3,‏ Google Earth,‏ Google Meet,‏ PlayCanvas,‏ Sketchfab,‏ Three.JS,‏ TensorFlow.js ו-Unity.
מסגרות, אפליקציות וספריות עם יציאות WebGPU שהושלמו או שנמצאות בתהליך.

והגרסה הראשונה ב-Chrome 113 היא רק ההתחלה. הגרסה הראשונית שלנו מיועדת ל-Windows, ל-ChromeOS ול-macOS, אבל אנחנו מתכננים להוסיף את WebGPU לפלטפורמות הנותרות, כמו Android ו-Linux, בעתיד הקרוב.

וגם לא רק צוות Chrome עבד על השקת WebGPU. אנחנו גם מטמיעים את התכונה ב-Firefox וב-WebKit.

בנוסף, כבר מתכננים ב-W3C תכונות חדשות שאפשר לחשוף כשהן יהיו זמינות בחומרה. לדוגמה: בקרוב אנחנו מתכננים להפעיל ב-Chrome תמיכה במספרים של 16 ביט עם נקודה צפה בשכבות הגדרת התאורה (shaders) ואת סוג ההוראות DP4a, כדי לשפר עוד יותר את הביצועים של למידת המכונה.

WebGPU הוא ממשק API נרחב שמאפשר לכם לשפר את הביצועים אם תשקיעו בו. היום הצגנו רק את היתרונות העיקריים של WebGPU, אבל אם אתם רוצים להתחיל להשתמש ב-WebGPU, כדאי לעיין במדריך Codelab למתחילים, האפליקציה הראשונה שלכם ב-WebGPU. במדריך הזה תלמדו ליצור גרסה ל-GPU של המשחק הקלאסי Conway's Game of Life. ב-codelab הזה נסביר את התהליך שלב אחרי שלב, כדי שתוכלו לנסות אותו גם אם זו הפעם הראשונה שאתם מפתחים ל-GPU.

הדוגמאות ל-WebGPU הן גם מקום טוב להבין את ה-API. הדוגמאות נעות בין 'משולש שלום' הפשוט לבין צינורות עיבוד נתונים מלאים יותר לעיבוד וחישוב, שממחישים מגוון שיטות. לבסוף, כדאי לעיין במקורות המידע האחרים שלנו.