3

I'm writing some WebGPU code with the rust wgpu library, and compiling it to run on a browser with WASM.

from what i found, seems i could use WebGpu to draw on a HTML canvas when i'm using JS, and could also draw on the canvas if i pass the canvas element to the rust WASM.

i'm intereseted in doing part of the graphic processing in JS, and part of the graphic processing in WASM, but i can't find a way to pass a WebGPU texture between JS and rust.

In contrast, on Android, i can create a texture with OpenGL, do whatever processing i like, and convert it in rust to a WebGPU texture using create_texture_from_hal (which is unavailable for wasm)

Is there any such way to pass WebGpu textures between the JS and the rust WASM?

4
  • Yes, it's possible. e.g. docs.rs/wgpu/latest/wasm32-unknown-unknown/wgpu/… for passing a JS image to wgpu Commented Dec 5, 2024 at 22:57
  • 1
    And overriding the GPUDevice prototype for hooking into wgpu object creation. I'll write up a proper answer later Commented Dec 5, 2024 at 22:57
  • 1
    @Stefnotch any chance you write this answer? Would be very helpful. Thank you! Commented Mar 7 at 11:03
  • 1
    @BenoîtLahoz Ah, I completely forgot about this. I added an answer, let me know if I should go into more detail at any point. Commented Mar 8 at 22:53

1 Answer 1

3

Javascript to WGPU

This direction is easy, since there's a provided method for it

let image_bitmap: web_sys::ImageBitmap = ...;

let size = wgpu::Extent3d { ... };
let desc = wgpu::TextureDescriptor { ... };
let texture = device.create_texture(&desc);

let copy_texture = wgpu::TexelCopyTextureInfo {
    aspect: wgpu::TextureAspect::All,
    texture: &texture,
    mip_level: 0,
    origin: wgpu::Origin3d::ZERO,
};

queue.copy_external_image_to_texture(
    &wgpu::CopyExternalImageSourceInfo {
        source: wgpu::ExternalImageSource::ImageBitmap(image_bitmap),
        origin: wgpu::Origin2d::ZERO,
        flip_y: false,
    },
    copy_texture.to_tagged(wgpu::PredefinedColorSpace::Srgb, true),
    size,
)

See copy_external_image_to_texture

WGPU to Javascript

Nobody seems to have requested this yet. So they haven't added a helper method for this. Please do open an issue on their repository if you actually find yourself needing this. And tell them what for, and why. :)

Until then, here's the rough workaround:

Have this Typescript function, and call it whenever the Rust side is about to create a texture. I haven't looked into how to elegantly call it. wasm-bindgen probably has something for that.

function captureNextTexture(): Promise<GPUTexture> {
  return new Promise((resolve) => {
    const originalCreateTexture = GPUDevice.prototype.createTexture;
    // The Rust bindings will call this, since they go through the browser API
    GPUDevice.prototype.createTexture = function (
      descriptor: GPUTextureDescriptor
    ) {
      // Create underlying texture
      const texture = originalCreateTexture.apply(this, [descriptor]);

      // Tell the promise about it.
      // Be a bit careful if you want to access the Rust side,
      // since the Rust side is in the middle of a WebGPU function call.
      resolve(texture);

      // Restore this function, we're done capturing
      GPUDevice.prototype.createTexture = originalCreateTexture;

      // Finish the createTexture call
      return texture;
    };
  });
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much! I'll dig in this :) In the meantime I posted this (not WASM related) question: stackoverflow.com/questions/79494438/…
I wish I could upvote multiple times! This was one of the cleverest hacks I've ever seen in my career! Hats off to whoever came up with the idea. It's the equivalent of picking someone's pocket, copying their ID card, and putting it back without them even noticing it!
@RafaelBeckel Thank you for all the praise, that really made my day. It sounds like you actually had a use-case for this. Would you mind opening up a GitHub issue on github.com/gfx-rs/wgpu , asking for a function to turn a wgpu::Texture into a GpuTexture, which wasm-bindgen would understand and be able to pass along to the frontend?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.