Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uniform buffers are all zeros on Intel ipgus on WebGL backend #3371

Closed
Dinnerbone opened this issue Jan 11, 2023 · 0 comments · Fixed by #3391
Closed

Uniform buffers are all zeros on Intel ipgus on WebGL backend #3371

Dinnerbone opened this issue Jan 11, 2023 · 0 comments · Fixed by #3391
Labels
api: gles Issues with GLES or WebGL external: driver-bug A driver is causing the bug, though we may still want to work around it

Comments

@Dinnerbone
Copy link
Contributor

Dinnerbone commented Jan 11, 2023

Description
On some devices, when using the webgl backend, uniform buffers are all zeros in shaders.
I've managed to narrow it down to "some" ranges of intel integrated graphics, but I can't say with confidence which ones. I can definitely reproduce it on my old surface pro 3, which uses Intel® HD Graphics 4400.

I can't say for sure it's only intel igpus, but so far I haven't found a user that has this issue on any other graphics driver.

This is affecting an unfortunate portion of our end users and currently blocking us from fully switching to wgpu.

Repro steps

  1. Find yourself such a device. Browser doesn't seem to matter.
  2. Try this commit, which modifies hello-triangle to draw the color bound to a uniform.
  3. Run cargo run-wasm --example hello-triangle --features webgl and open it in your browser.
  4. If you see a triangle that's anything but rgba(1.0, 0.5, 0.25, 1.0) then it's broken. In my experience it's either black or white when broken. Screenshots below.

Expected vs observed behavior
For the example code above, this is a correct output:
image

If the triangle is any other color, it is broken.

Extra materials
No warnings or validation or extra log at all.

I did find that if you move the buffer out of the loop and up to the top, it works:

diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs
index 16a96129..60e213ca 100644
--- a/wgpu/examples/hello-triangle/main.rs
+++ b/wgpu/examples/hello-triangle/main.rs
@@ -86,6 +86,14 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
         multisample: wgpu::MultisampleState::default(),
         multiview: None,
     });
+    let color: [f32; 4] = [1.0, 0.5, 0.25, 1.0];
+    let buffer =
+        device
+            .create_buffer_init(&wgpu::util::BufferInitDescriptor {
+                label: None,
+                contents: bytemuck::cast_slice(&[color]),
+                usage: wgpu::BufferUsages::UNIFORM,
+            });
 
     let mut config = wgpu::SurfaceConfiguration {
         usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
@@ -127,14 +135,6 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
                 let view = frame
                     .texture
                     .create_view(&wgpu::TextureViewDescriptor::default());
-                let color: [f32; 4] = [1.0, 0.5, 0.25, 1.0];
-                let buffer =
-                    device
-                        .create_buffer_init(&wgpu::util::BufferInitDescriptor {
-                            label: None,
-                            contents: bytemuck::cast_slice(&[color]),
-                            usage: wgpu::BufferUsages::UNIFORM,
-                        });
                 let bind_group = device
                     .create_bind_group(&wgpu::BindGroupDescriptor {
                         layout: &bind_group_layout,

But if you store the buffer between frames, intentionally leaking them, it doesn't work:

diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs
index 16a96129..4a2f9c4a 100644
--- a/wgpu/examples/hello-triangle/main.rs
+++ b/wgpu/examples/hello-triangle/main.rs
@@ -98,6 +98,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
 
     surface.configure(&device, &config);
 
+    let mut buffers = vec![];
     event_loop.run(move |event, _, control_flow| {
         // Have the closure take ownership of the resources.
         // `event_loop.run` never returns, therefore we must do this to ensure
@@ -166,6 +167,7 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
                 queue.submit(Some(encoder.finish()));
                 frame.present();
                 log::info!("Presented");
+                buffers.push(buffer);
             }
             Event::WindowEvent {
                 event: WindowEvent::CloseRequested,

So my theory right now is that the buffer isn't initialized fast enough, rather than being dropped too soon.

Meanwhile, duplicating the entire submission seems to work too:

diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs
index 16a96129..9893308c 100644
--- a/wgpu/examples/hello-triangle/main.rs
+++ b/wgpu/examples/hello-triangle/main.rs
@@ -164,6 +164,26 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
                     rpass.draw(0..3, 0..1);
                 }
                 queue.submit(Some(encoder.finish()));
+                let mut encoder =
+                    device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
+                {
+                    let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
+                        label: None,
+                        color_attachments: &[Some(wgpu::RenderPassColorAttachment {
+                            view: &view,
+                            resolve_target: None,
+                            ops: wgpu::Operations {
+                                load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
+                                store: true,
+                            },
+                        })],
+                        depth_stencil_attachment: None,
+                    });
+                    rpass.set_pipeline(&render_pipeline);
+                    rpass.set_bind_group(0, &bind_group, &[]);
+                    rpass.draw(0..3, 0..1);
+                }
+                queue.submit(Some(encoder.finish()));
                 frame.present();
                 log::info!("Presented");
             }

(If you just duplicate the renderpass on the encoder, it flickers randomly between working and not working)

Platform
wgpu v0.14.2 and 48fbb92 (master as of writing). Haven't tried older versions.
Browser doesn't seem to matter, it's been reprod in Edge, Firefox and Chrome.
Reproduced on Intel® HD Graphics 630 and Intel® HD Graphics 4400 so far.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: gles Issues with GLES or WebGL external: driver-bug A driver is causing the bug, though we may still want to work around it
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants