מה חדש ב-WebGPU (Chrome 121)

François Beaufort
François Beaufort

תמיכה ב-WebGPU ב-Android

צוות Chrome שמח להודיע ש-WebGPU מופעל עכשיו כברירת מחדל ב-Chrome 121 במכשירים עם Android מגרסה 12 ואילך עם מעבדי GPU של Qualcomm ו-ARM.

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

צילום מסך של דוגמה ל-WebGPU שפועלת ב-Chrome ל-Android.
דוגמה ל-WebGPU שפועלת ב-Chrome ל-Android.

שימוש ב-DXC במקום ב-FXC להידור של תוכנת ההצללה ב-Windows

Chrome משתמש עכשיו ביכולות של DXC (DirectX Compiler) כדי לקמפל שגיאות (shaders) במכונות Windows D3D12 עם חומרת גרפיקה מדגם SM6 ואילך. בעבר, WebGPU הסתמך על FXC‏ (FX Compiler) כדי לבצע הידור של שגיאות ב-Windows. ה-FXC היה פונקציונלי, אבל חסר בו סט התכונות ואופטימיזציית הביצועים שקיימים ב-DXC.

בבדיקה הראשונית נמצא עלייה ממוצעת של 20% במהירות ההידור של תוכנת ההצללה למחשוב בזמן השימוש ב-DXC, בהשוואה ל-FXC.

שאילתות של חותמות זמן בשלבי המחשוב והעיבוד

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

כשהתכונה "timestamp-query" זמינה ב-GPUAdapter, אפשר לבצע את הפעולות הבאות:

  • מבקשים GPUDevice עם התכונה "timestamp-query".
  • יוצרים GPUQuerySet מסוג "timestamp".
  • משתמשים ב-GPUComputePassDescriptor.timestampWrites וב-GPURenderPassDescriptor.timestampWrites כדי להגדיר איפה לכתוב את ערכי חותמות הזמן ב-GPUQuerySet.
  • פותרים את ערכי חותמות הזמן ב-GPUBuffer באמצעות resolveQuerySet().
  • קוראים חזרה את ערכי חותמות הזמן על ידי העתקת התוצאות מ-GPUBuffer ל-CPU.
  • פענוח של ערכי חותמות זמן כ-BigInt64Array.

אפשר לעיין בדוגמה הבאה ובבעיה dawn:1800.

const adapter = await navigator.gpu.requestAdapter();
if (!adapter.features.has("timestamp-query")) {
  throw new Error("Timestamp query feature is not available");
}
// Explicitly request timestamp query feature.
const device = await adapter.requestDevice({
  requiredFeatures: ["timestamp-query"],
});
const commandEncoder = device.createCommandEncoder();

// Create a GPUQuerySet which holds 2 timestamp query results: one for the
// beginning and one for the end of compute pass execution.
const querySet = device.createQuerySet({ type: "timestamp", count: 2 });
const timestampWrites = {
  querySet,
  beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins.
  endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends.
};
const passEncoder = commandEncoder.beginComputePass({ timestampWrites });
// TODO: Set pipeline, bind group, and dispatch work to be performed.
passEncoder.end();

// Resolve timestamps in nanoseconds as a 64-bit unsigned integer into a GPUBuffer.
const size = 2 * BigInt64Array.BYTES_PER_ELEMENT;
const resolveBuffer = device.createBuffer({
  size,
  usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,
});
commandEncoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0);

// Read GPUBuffer memory.
const resultBuffer = device.createBuffer({
  size,
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
});
commandEncoder.copyBufferToBuffer(resolveBuffer, 0, resultBuffer, 0, size);

// Submit commands to the GPU.
device.queue.submit([commandEncoder.finish()]);

// Log compute pass duration in nanoseconds.
await resultBuffer.mapAsync(GPUMapMode.READ);
const times = new BigInt64Array(resultBuffer.getMappedRange());
console.log(`Compute pass duration: ${Number(times[1] - times[0])}ns`);
resultBuffer.unmap();

עקב חששות מהתקפת תזמון, שאילתות של חותמות זמן עוברות קוונטיזציה ברזולוציה של 100 מיקרו-שניות, שמספקת פשרה טובה בין דיוק לאבטחה. בדפדפן Chrome, אפשר להשבית את התקציבים של חותמות הזמן על ידי הפעלת הדגל 'WebGPU Developer Features' בקטע chrome://flags/#enable-webgpu-developer-features במהלך הפיתוח של האפליקציה. מידע נוסף זמין במאמר התקציבים של שאילתות עם חותמות זמן.

לפעמים, מעבדי GPU מאפסים את מונה חותמות הזמן, מה שעלול לגרום לערכים לא צפויים כמו דלתא שלילית בין חותמות זמן. לכן, מומלץ לבדוק את השינויים ב-git diff שמוסיפים תמיכה בשאילתות של חותמות זמן לדוגמה הבאה של Compute Boids.

צילום מסך של דוגמה ל-Compute Boids עם שאילתה של חותמת זמן.
דוגמה של Compute Boids עם שאילתה של חותמת זמן.

נקודות כניסה שמוגדרות כברירת מחדל למודולים של שגיאות

כדי לשפר את חוויית הפיתוח, עכשיו אפשר להשמיט את entryPoint של מודול ההצללה בזמן יצירת צינור עיבוד נתונים של מחשוב או רינדור. אם לא נמצאת נקודת כניסה ייחודית לשלב ה-shader בקוד ה-shader, תופעל הודעת השגיאה GPUValidationError. דוגמה לכך מופיעה בהמשך, וגם בבעיה dawn:2254.

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 module = myDevice.createShaderModule({ code });
const format = navigator.gpu.getPreferredCanvasFormat();
const pipeline = await myDevice.createRenderPipelineAsync({
  layout: "auto",
  vertex: { module, entryPoint: "vertexMain" },
  fragment: { module, entryPoint: "fragmentMain", targets: [{ format }] },
  vertex: { module },
  fragment: { module, targets: [{ format }] },
});

תמיכה ב-display-p3 כמרחב צבעים של GPUExternalTexture

עכשיו אפשר להגדיר את מרחב הצבעים של היעד "display-p3" כשמייבאים GPUExternalTexture מסרטוני HDR באמצעות importExternalTexture(). אתם יכולים לבדוק איך WebGPU מטפל במרחבי צבעים. דוגמה לכך מופיעה בבעיה chromium:1330250.

// Create texture from HDR video.
const video = document.querySelector("video");
const texture = myDevice.importExternalTexture({
  source: video,
  colorSpace: "display-p3",
});

מידע על ערימות זיכרון

כדי לעזור לכם לצפות מראש את מגבלות הזיכרון כשאתם מקצים כמויות גדולות במהלך הפיתוח של האפליקציה, requestAdapterInfo() חושף עכשיו מידע על memoryHeaps, כמו הגודל והסוג של ערמות הזיכרון הזמינות במתאם. אפשר לגשת לתכונה הניסיונית הזו רק כשהדגל 'WebGPU Developer Features' מופעל ב-chrome://flags/#enable-webgpu-developer-features. אפשר לעיין בדוגמה הבאה ובבעיה dawn:2249.

const adapter = await navigator.gpu.requestAdapter();
const adapterInfo = await adapter.requestAdapterInfo();

for (const { size, properties } of adapterInfo.memoryHeaps) {
  console.log(size); // memory heap size in bytes
  if (properties & GPUHeapProperty.DEVICE_LOCAL)  { /* ... */ }
  if (properties & GPUHeapProperty.HOST_VISIBLE)  { /* ... */ }
  if (properties & GPUHeapProperty.HOST_COHERENT) { /* ... */ }
  if (properties & GPUHeapProperty.HOST_UNCACHED) { /* ... */ }
  if (properties & GPUHeapProperty.HOST_CACHED)   { /* ... */ }
}
צילום מסך של https://webgpureport.org עם אשכולות זיכרון בפרטי המתאם.
מקבצים גדולים של זיכרון של מידע על מתאם מוצגים בכתובת https://webgpureport.org.

עדכונים לגבי זריחה

השיטות HasWGSLLanguageFeature ו-EnumerateWGSLLanguageFeatures ב-wgpu::Instance נוספו כדי לטפל בתכונות השפה של WGSL. ראו את הבעיה dawn:2260.

התכונה הלא סטנדרטית wgpu::Feature::BufferMapExtendedUsages מאפשרת ליצור מאגר GPU עם wgpu::BufferUsage::MapRead או wgpu::BufferUsage::MapWrite וכל wgpu::BufferUsage אחר. דוגמה לכך מופיעה בבעיה dawn:2204.

wgpu::BufferDescriptor descriptor = {
  .size = 128,
  .usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::Uniform
};
wgpu::Buffer uniformBuffer = device.CreateBuffer(&descriptor);

uniformBuffer.MapAsync(wgpu::MapMode::Write, 0, 128,
   [](WGPUBufferMapAsyncStatus status, void* userdata)
   {
      wgpu::Buffer* buffer = static_cast<wgpu::Buffer*>(userdata);
      memcpy(buffer->GetMappedRange(), data, sizeof(data));
   },
   &uniformBuffer);

התכונות הבאות תועדו: חלוקת טקסטורות ב-ANGLE, D3D11 multithread protected, Implicit Device Synchronization, Norm16 texture formats, Timestamp Query Inside Passes, Pixel Local Storage, Shader Features ו-Multi Planar Formats.

צוות Chrome יצר מאגר רשמי ב-GitHub עבור Dawn.

הסקירה הזו כוללת רק חלק מהנקודות העיקריות. רשימת ההצהרות המלאה

מה חדש ב-WebGPU

רשימה של כל מה שדיברנו עליו בסדרה מה חדש ב-WebGPU.

Chrome 131

Chrome 130

Chrome 129

Chrome 128

Chrome 127

Chrome 126

Chrome 125

Chrome 124

Chrome 123

Chrome 122

Chrome 121

Chrome 120

Chrome 119

Chrome 118

Chrome 117

Chrome 116

Chrome 115

Chrome 114

Chrome 113