Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGPU use case #17

Open
Jack-Works opened this issue Feb 19, 2025 · 2 comments
Open

WebGPU use case #17

Jack-Works opened this issue Feb 19, 2025 · 2 comments

Comments

@Jack-Works
Copy link
Member

hi @kainino0x I believe this proposal fits the need of WebGPU than the immutable array buffer proposal (tc39/proposal-immutable-arraybuffer#25), but I'd like to know more backgrounds about the WebGPU use case.

I'll re-design this proposal recently, so I hope I'll satisfy the WebGPU use case.

@kainino0x
Copy link

In WebGPU, there's a concept called "mapping" which allows a chunk of memory (owned by a GPUBuffer) to be exclusively transferred to the CPU (for access from JS/Wasm in the VM), and then exclusively transferred back so the GPU can use it. This ownership transfer model allows implementing with or without memory copies - it makes the difference unobservable. From the JS standpoint what this looks like now is mapping give you an ArrayBuffer (which could even point directly at GPU memory), and unmapping detaches that ArrayBuffer so that JS can't read or write it anymore.

Additionally one of the things we are hoping to be able to do with GPUBuffer mapping (but cannot do yet) is mmap-style mapping of pages of GPUBuffer memory into the Wasm heap so it can be accessed directly from Wasm. (Right now we return a new ArrayBuffer which means only JS can access it.)

Mappings are always one way, either:

  • (CPU read/writable, GPU readable).
  • (GPU read/writable, CPU readable). However because ArrayBuffer is always writable, we can't actually do this zero-copy. We have to provide a writable ArrayBuffer to JS, so right now the only way is to use a scratch buffer to prevent JS from overwriting data it's not supposed to (which would result in undefined behavior due to e.g. missing cache invalidation).
  • (We may also allow more complex map configurations in the future, but it shouldn't affect anything here.)

The latter is the case that we could improve with read-only ArrayBuffers. The proposed read-only mapping could be used when you need to "download" data from the GPU to the CPU, i.e. get the result of some on-GPU computation.

So in summary we want an ArrayBuffer:

  • with underlying data constant for the lifetime of the ArrayBuffer, not modifiable by JS/Wasm. (It won't be modified by the browser either, it's fully constant.)
  • that can be mmapped into Wasm, or whatever that mechanism ends up being
  • can be detached on demand such that the underlying memory can immediately become writable to the GPU (without the changes being visible to the CPU).
  • (and un-mmapped from Wasm on demand)

(I've written all this off the top of my head but I think that should be it.)

Thanks for investigating!

@Jack-Works
Copy link
Member Author

Hi! Thank you for the explanation! I believe with the new design, it is possible to provide a read-only view (a TypedArray or a DataView, not an ArrayBuffer object) to the JS program meanwhile the underlying ArrayBuffer remains mutable and inaccessible (so JS programs won't be able to modify it, the browser/engine will not touch it either). You can also detach it on-demand.

But it is impossible to:

  • Provide a mmap style memory mapping to the wasm (beyond the scope of this proposal).
  • Let a view be read-only first, then switch the view to read-write in-place (implementors will not be happy with this). You have to provide a new view.

I tried to write some pseudo code to explain, hope it works.

// memory state: CPU r/w GPU r/o
var m1 = getMem();
// m1 is a normal ArrayBuffer
modify(m1);

commit();
// now m1 is detached
// memory state: CPU r/o GPU r/w
var m2 = getMem();
assert(m2 instanceof Uint8Array && m2.buffer === undefined);
var m2_i8 = new Int8Array(m2); // adjust how we view it
var m2_dv = new DataView(m2); // not possible today, but proposed
some_host_api_that_receives_an_array_buffer(m2); // may throws
stop_and_get_back_memory_control();
// now m2, m2_i8, m2_dv is detached
// memory state: CPU r/w GPU r/o

I'm not going to propose a read-only ArrayBuffer object, but only limiting the mutability of the view (TypedArray or DataView) and hide the underlying ArrayBuffer, because I'm afraid of implementation complexity is too high. I wonder if the model above fits WebGPU, thanks!

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

No branches or pull requests

2 participants