learn-wgpu icon indicating copy to clipboard operation
learn-wgpu copied to clipboard

Wgpu without a window for web

Open adamgerhant opened this issue 1 year ago • 0 comments

The current Wgpu without a window code example does not work when compiling to wasm and running in a browser. Specially, copying data from the buffer using futures_intrusive::channel::shared::oneshot_channel() seems to cause the error. To solve this, I used the code in another wgpu example which uses flume::bounded. This fixed the problem and allowed me to copy data from the buffer and return it to Javascript.

l should probably make a pull request, but I think its unnecessary for a very simple change. Here's the old code compared to the new

Old

{
    let buffer_slice = output_buffer.slice(..);

    // NOTE: We have to create the mapping THEN device.poll() before await
    // the future. Otherwise the application will freeze.
    let (tx, rx) = futures_intrusive::channel::shared::oneshot_channel();
    buffer_slice.map_async(wgpu::MapMode::Read, move |result| {
        tx.send(result).unwrap();
    });
    device.poll(wgpu::Maintain::Wait);
    rx.receive().await.unwrap().unwrap();

    let data = buffer_slice.get_mapped_range();

    use image::{ImageBuffer, Rgba};
    let buffer =
        ImageBuffer::<Rgba<u8>, _>::from_raw(texture_size, texture_size, data).unwrap();
    buffer.save("image.png").unwrap();

}
output_buffer.unmap();

New

let mut pixel_data = Vec::<u8>::new();

let buffer_slice = output_buffer.slice(..);
let (sender, receiver) = flume::bounded(1);
buffer_slice.map_async(wgpu::MapMode::Read, move |r| sender.send(r).unwrap());
device.poll(wgpu::Maintain::wait()).panic_on_timeout();
receiver.recv_async().await.unwrap().unwrap();
{
    let view = buffer_slice.get_mapped_range();
    texture_data.extend_from_slice(&view[..]);
}
output_buffer.unmap();

let img = DynamicImage::ImageRgba8(ImageBuffer::from_raw(texture_size, texture_size, pixel_data).unwrap());

//img can be saved to disk, or returned as a byte stream with the following
let mut png_data = Cursor::new(Vec::<u8>::new());
img.write_to(&mut png_data, ImageFormat::Png).unwrap();

let png_bytes = png_data.into_inner();
png_bytes

adamgerhant avatar Feb 02 '24 21:02 adamgerhant