Skip to content

Write WebGPU buffer data directly from its storage - #9379

Merged
mvaligursky merged 1 commit into
mainfrom
mv-webgpu-buffer-upload
Sep 14, 2026
Merged

mvaligursky merged 1 commit into
mainfrom
mv-webgpu-buffer-upload

Conversation

@mvaligursky

Copy link
Copy Markdown
Contributor

Removes a per-upload allocation and copy from the WebGPU buffer upload path.

Changes:

  • WebgpuBuffer#unlock allocated a Uint8Array of the GPU buffer size and copied the storage into it on every upload, to pad the data to the multiple of 4 that writeBuffer requires. Uniform buffer storage is always a multiple of 16 bytes and vertex and index buffers mostly are, so the copy was almost always redundant, and it produced garbage on every upload of a persistent buffer. The data is now written directly from its storage, honouring the byte offset of a typed array view, and only odd-sized data goes through a padded copy.
  • A debug assert catches data larger than the allocated buffer, which previously surfaced as a RangeError from the copy.
  • Unit tests for the direct write, a typed array view with an offset, an ArrayBuffer storage and the padded odd-size path.

Performance:

  • One fewer allocation and memcpy per persistent buffer upload on WebGPU. This matters for buffers uploaded every frame, such as the upcoming per-material uniform buffers.

WebgpuBuffer#unlock allocated a Uint8Array of the buffer size and copied the storage into it on
every upload, to pad the data to the multiple of 4 that writeBuffer requires. Uniform buffer storage
is always a multiple of 16 bytes and vertex and index buffers mostly are, so the copy was almost
always redundant and created garbage per upload - once per changed uniform buffer per frame. The data
is now written straight from its storage, honouring the byte offset of a typed array view, and only
odd-sized data goes through a padded copy.
@github-actions

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2432.5 KB (+58 B, +0.00%) 627.0 KB (+18 B, +0.00%) 486.9 KB (+32 B, +0.01%)
playcanvas.min.mjs 2429.9 KB (+58 B, +0.00%) 626.1 KB (+10 B, +0.00%) 486.2 KB (−75 B, −0.02%)

@mvaligursky mvaligursky left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated PR review by Codex (GPT-5).

No actionable findings. The direct path deliberately passes the backing ArrayBuffer, so dataOffset and size remain byte-based regardless of the original typed-array element type; offset views are bounded by their own byteLength, and odd logical sizes still go through a zero-padded multiple-of-four copy. The vertex, index, and persistent-uniform callers keep their CPU storage consistent with the allocated GPU size, and WebGL is untouched.

Validation performed: the new focused tests pass (4/4), the full unit suite passes (2889 passing, 2 pending), git diff --check passes, and all current CI checks are green. Following byte-exact rendering verification criteria, I did not run a real-WebGPU GPU readback or a controlled before/after pixel matrix locally, so actual-device equivalence is supported by the byte-range analysis and tests rather than an independently captured zero-diff result.

@mvaligursky
mvaligursky merged commit bc32951 into main Sep 14, 2026
10 checks passed
@mvaligursky
mvaligursky deleted the mv-webgpu-buffer-upload branch September 14, 2026 15:55

This branch was successfully deployed

2 active deployments
Preview – engine — 481e048e Deployed Sep 14, 2026 by vercel[bot]
Preview – engine-api-docs — 481e048e Deployed Sep 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant