Skip to content

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

Open

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:

//  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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-AssetsLoad files from disk to use for things like images, models, and soundsLoad files from disk to use for things like images, models, and soundsA-RenderingDrawing game state to the screenDrawing game state to the screenC-BugAn unexpected or incorrect behaviorAn unexpected or incorrect behaviorS-Needs-DesignThis issue requires design work to think about how it would best be accomplishedThis issue requires design work to think about how it would best be accomplished

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions