bevyengine / bevyengine/bevy

Asset data from code is not sent to the GPU appropriately (on webgl2)

Open
#14,391 2 comments 0 reactions 0 assignees View on GitHub
A-Assets A-Rendering C-Bug S-Needs-Design
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 22h
Merged PRs (30d)
161

Description

## 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:
```rust
// 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.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.