Description
openedon Jul 19, 2024
Bevy version
0.14.0
Relevant system information
AdapterInfo { name: "Radeon R9 200 Series, or similar", vendor: 4098, device: 0, device_type: Other, driver: "WebGL", driver_info: "2.0", backend: Gl }
What you did
The goal is to initialize random data for an Image
, then repeatedly pass the Image
through a fragment shader with the render target as the image itself. (Simulate a cellular automata.) Code snippet:
// In setup schedule
let image_handle = images.add(Image {
texture_descriptor: TextureDescriptor {
label: None,
size,
dimension: TextureDimension::D2,
format: TextureFormat::R8Unorm,
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT,
view_formats: &[],
},
data: (0..(WIDTH * HEIGHT))
.map(|_| if rng.gen_bool(0.5) { 255 } else { 0 })
.collect(),
..default()
});
let first_pass_layer = RenderLayers::layer(1);
cmd.spawn((
MaterialMesh2dBundle {
mesh: rect_handle.clone().into(),
material: materials.add(LifeMaterial { // Use custom frag-pass
color_texture: image_handle.clone().into(),
}),
..default()
},
first_pass_layer.clone(),
));
cmd.spawn((
Camera2dBundle {
camera: Camera {
// render before the "main pass" camera
order: -1,
target: image_handle.clone().into(), // first pass update itself
..default()
},
..default()
},
first_pass_layer,
));
// Second pass resuses the same image and draws it to the screen
What went wrong
What were you expecting?
- Image data is initialized to random noise
- Image's initial state is reflected as random noise on the GPU
- This happens CORRECTLY on native (x86-linux, AMD Vulkan) target
What actually happened?
- Image's initial state on the GPU is blank
Additional information
Again, the bug happens only when building to wasm with the WebGL2 backend.
My theory for why the behavior occurs is that the texture descriptor is passed to the GPU and used before data
is synced between the CPU and the GPU. Then on the first pass through the frag shader (LifeMaterial
), the image's data is overwritten and thus, black.
I'm not sure why the behavior is inconsistent across platforms (perhaps due to wasm being slower? or the backend syncs data differently?). Ideally, data
is sent to the GPU immediately. Or at least before the first render pass.