( renderer: WebGPURenderer, data: Uint8ClampedArray, width: number, height: number, bytesPerRow: number = width * 4, )
| 304 | } |
| 305 | |
| 306 | export function renderFrameWebGPU( |
| 307 | renderer: WebGPURenderer, |
| 308 | data: Uint8ClampedArray, |
| 309 | width: number, |
| 310 | height: number, |
| 311 | bytesPerRow: number = width * 4, |
| 312 | ): WebGPURenderTiming { |
| 313 | const totalStart = performance.now(); |
| 314 | let resizeMs = 0; |
| 315 | let textureSetupMs = 0; |
| 316 | let uploadMs = 0; |
| 317 | let drawMs = 0; |
| 318 | const { device, context, pipeline, sampler, bindGroupLayout, canvas } = |
| 319 | renderer; |
| 320 | |
| 321 | if (canvas.width !== width || canvas.height !== height) { |
| 322 | const start = performance.now(); |
| 323 | canvas.width = width; |
| 324 | canvas.height = height; |
| 325 | const format = navigator.gpu.getPreferredCanvasFormat(); |
| 326 | context.configure({ |
| 327 | device, |
| 328 | format, |
| 329 | alphaMode: "opaque", |
| 330 | }); |
| 331 | resizeMs = performance.now() - start; |
| 332 | } |
| 333 | |
| 334 | if (renderer.cachedWidth !== width || renderer.cachedHeight !== height) { |
| 335 | const start = performance.now(); |
| 336 | renderer.frameTexture?.destroy(); |
| 337 | renderer.frameTexture = device.createTexture({ |
| 338 | size: { width, height }, |
| 339 | format: "rgba8unorm", |
| 340 | usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST, |
| 341 | }); |
| 342 | renderer.bindGroup = device.createBindGroup({ |
| 343 | layout: bindGroupLayout, |
| 344 | entries: [ |
| 345 | { binding: 0, resource: sampler }, |
| 346 | { binding: 1, resource: renderer.frameTexture.createView() }, |
| 347 | ], |
| 348 | }); |
| 349 | renderer.cachedWidth = width; |
| 350 | renderer.cachedHeight = height; |
| 351 | textureSetupMs = performance.now() - start; |
| 352 | } |
| 353 | |
| 354 | if (!renderer.frameTexture || !renderer.bindGroup) { |
| 355 | return createEmptyTiming(totalStart); |
| 356 | } |
| 357 | |
| 358 | const requiredBytes = bytesPerRow * height; |
| 359 | if (data.byteLength < requiredBytes) { |
| 360 | console.error( |
| 361 | `WebGPU renderFrame: buffer too small. Expected at least ${requiredBytes} bytes, got ${data.byteLength}`, |
| 362 | ); |
| 363 | return createEmptyTiming(totalStart); |
no test coverage detected