learn-wgpu
learn-wgpu copied to clipboard
Wgpu without a window for web
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