This small sample app reproduces a suspected bug in the Microsoft Basic Render Driver
aka WARP backend of wgpu-rs (or perhaps in WARP itself?).
The sample should run on any platform, but to reproduce the issue, you should be on MS Windows
. You need
- git to clone this repo
- Rust and Cargo to build and run the code
To build and run the sample:
- Open a terminal and point it to some directory where the project can be deployed
- Clone this repository
> git clone https://github.com/kwillemsen/wgpu_warp_issue.git
- Step into the newly cloned repo's root
> cd wgpu_warp_issue
- Build and run the code
> cargo run
When the application starts, you need to select a backend from the command line. On my current machine, the menu looks like this
The sample will then use the selected backend to draw a bunch of quads, each with a different color. If you didn't select Microsoft Basic Render Driver
you should see the correct result:
However, if you are running on MS Windows
and select Microsoft Basic Render Driver
(option 4
on my machine, but YMMV) the result will be incorrect: every rectangle will have the same color
The sample represents each quad as its own entity:
struct Entity {
vertex_buffer: Buffer,
index_buffer: Buffer,
constant_buffer: Buffer,
bind_group: BindGroup,
num_indices: u32,
constant_data: [u8; 16],
}
Each of them has its own vertex buffer, index buffer, constant buffer and bind group. The render loop has two phases:
-
Update each entity's constant buffer through
Queue::write_buffer()
. -
Create a
CommandEncoder
andRenderPass
and draw all entities.// // Phase 1 : update constant buffers. // for e in &entities { queue.write_buffer(&e.constant_buffer, 0, &e.constant_data); // <-- Problem here? } // // Phase 2 : draw all entities. // let mut encoder = device.create_command_encoder(/*...*/); { let mut render_pass = encoder.begin_render_pass(/*...*/); render_pass.set_pipeline(&render_pipeline); for e in &entities { render_pass.set_vertex_buffer(0, e.vertex_buffer.slice(..)); render_pass.set_index_buffer(e.index_buffer.slice(..), wgpu::IndexFormat::Uint32); render_pass.set_bind_group(0, &e.bind_group, &[]); render_pass.draw_indexed(0..e.num_indices, 0, 0..1); } } queue.submit(iter::once(encoder.finish()));
I assume the problem is in the updating of constant buffers. It seems as if all of them are filled with the data of the last entity in the loop.
In an attempt to work around the issue, I tried using explicit staging buffers to upload constant data. This functionality is available when runing the app with the -s
flag
cargo run -- -s
It did not fix the issue.
The sample can generate an API trace through wgpu-rs. To enable this feature, run the sample with the -t
flag
> cargo run -- -t <existing-directory-path>
This will store the trace files in <existing-directory-path>
(which - as the name suggests - must be an existing directory). A pre-created trace is available in this repo.