Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ By @beholdnec in [#8505](https://github.com/gfx-rs/wgpu/pull/8505).

#### Metal

- Implement `MULTI_DRAW_INDIRECT_COUNT` via compute shader emulation. By @bromles in [#9659](https://github.com/gfx-rs/wgpu/pull/9659).
- Add `metal::Queue::add_wait_event` / `add_signal_event` (with `remove_*` companions) to stage `MTLSharedEvent` waits/signals on the next `Queue::submit`, for GPU-side interop with foreign APIs. Waits run on an internal CB committed before user CBs. By @AdrianEddy in [#9483](https://github.com/gfx-rs/wgpu/pull/9483).
- Unconditionally enable `Features::CLIP_DISTANCES`. By @ErichDonGubler in [#9270](https://github.com/gfx-rs/wgpu/pull/9270).
- Added full support for mesh shaders, including in WGSL shaders. By @inner-daemons in [#8739](https://github.com/gfx-rs/wgpu/pull/8739).
Expand Down
2 changes: 2 additions & 0 deletions examples/features/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod hello_workgroups;
pub mod mesh_shader;
pub mod mipmap;
pub mod msaa_line;
pub mod multi_draw_indirect_count;
pub mod multiple_render_targets;
pub mod multiview;
pub mod ray_aabb_compute;
Expand Down Expand Up @@ -56,6 +57,7 @@ fn all_tests() -> Vec<wgpu_test::GpuTestInitializer> {
mipmap::TEST,
mipmap::TEST_QUERY,
msaa_line::TEST,
multi_draw_indirect_count::TEST,
multiple_render_targets::TEST,
ray_aabb_compute::TEST,
ray_cube_compute::TEST,
Expand Down
6 changes: 6 additions & 0 deletions examples/features/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ const EXAMPLES: &[ExampleDesc] = &[
webgl: true,
webgpu: true,
},
ExampleDesc {
name: "multi_draw_indirect_count",
function: wgpu_examples::multi_draw_indirect_count::main,
webgl: false,
webgpu: false,
},
ExampleDesc {
name: "multiple_render_targets",
function: wgpu_examples::multiple_render_targets::main,
Expand Down
231 changes: 231 additions & 0 deletions examples/features/src/multi_draw_indirect_count/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
use bytemuck::{Pod, Zeroable};
use wgpu::util::DeviceExt;

const EXAMPLE_NAME: &str = "multi_draw_indirect_count";

const NUM_QUADS: u32 = 16;
const QUAD_SIZE: f32 = 0.2;

#[repr(C)]
#[derive(Clone, Copy, Pod, Zeroable)]
struct Vertex {
position: [f32; 2],
color: [f32; 3],
}

struct Example {
pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
indirect_buffer: wgpu::Buffer,
count_buffer: wgpu::Buffer,
}

impl crate::framework::Example for Example {
fn required_features() -> wgpu::Features {
wgpu::Features::MULTI_DRAW_INDIRECT_COUNT
}

fn required_limits() -> wgpu::Limits {
wgpu::Limits::downlevel_defaults()
}

fn init(
config: &wgpu::SurfaceConfiguration,
_adapter: &wgpu::Adapter,
device: &wgpu::Device,
_queue: &wgpu::Queue,
) -> Self {
let shader = device.create_shader_module(wgpu::include_wgsl!("shader.wgsl"));

let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Pipeline"),
layout: None,
vertex: wgpu::VertexState {
module: &shader,
entry_point: Some("vs_main"),
compilation_options: Default::default(),
buffers: &[Some(wgpu::VertexBufferLayout {
array_stride: size_of::<Vertex>() as u64,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &wgpu::vertex_attr_array![
0 => Float32x2,
1 => Float32x3,
],
})],
},
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleList,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
fragment: Some(wgpu::FragmentState {
module: &shader,
entry_point: Some("fs_main"),
compilation_options: Default::default(),
targets: &[Some(wgpu::ColorTargetState {
format: config.format,
blend: Some(wgpu::BlendState::ALPHA_BLENDING),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
multiview_mask: None,
cache: None,
});

let cols = 4;
let mut vertices = Vec::new();
let mut indirect_args = Vec::new();

for i in 0..NUM_QUADS {
let row = i / cols;
let col = i % cols;
let cx = -0.75 + col as f32 * 0.5;
let cy = 0.75 - row as f32 * 0.5;
let s = QUAD_SIZE;

let hue = i as f32 / NUM_QUADS as f32;
let (r, g, b) = hsv_to_rgb(hue, 0.8, 0.9);

vertices.extend_from_slice(&[
Vertex {
position: [cx - s, cy - s],
color: [r, g, b],
},
Vertex {
position: [cx + s, cy - s],
color: [r, g, b],
},
Vertex {
position: [cx - s, cy + s],
color: [r, g, b],
},
Vertex {
position: [cx + s, cy - s],
color: [r, g, b],
},
Vertex {
position: [cx + s, cy + s],
color: [r, g, b],
},
Vertex {
position: [cx - s, cy + s],
color: [r, g, b],
},
]);

let first_vertex = i * 6;
indirect_args.push(wgpu::util::DrawIndirectArgs {
vertex_count: 6,
instance_count: 1,
first_vertex,
first_instance: 0,
});
}

let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Vertex Buffer"),
contents: bytemuck::cast_slice(&vertices),
usage: wgpu::BufferUsages::VERTEX,
});

let indirect_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Indirect Buffer"),
contents: bytemuck::cast_slice(&indirect_args),
usage: wgpu::BufferUsages::INDIRECT,
});

let count_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
label: Some("Count Buffer"),
contents: bytemuck::cast_slice::<u32, u8>(&[NUM_QUADS]),
usage: wgpu::BufferUsages::INDIRECT,
});

Example {
pipeline,
vertex_buffer,
indirect_buffer,
count_buffer,
}
}

fn resize(
&mut self,
_config: &wgpu::SurfaceConfiguration,
_device: &wgpu::Device,
_queue: &wgpu::Queue,
) {
}

fn update(&mut self, _event: winit::event::WindowEvent) {}

fn render(&mut self, view: &wgpu::TextureView, device: &wgpu::Device, queue: &wgpu::Queue) {
let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Encoder"),
});

{
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: wgpu::StoreOp::Store,
},
depth_slice: None,
})],
depth_stencil_attachment: None,
timestamp_writes: None,
occlusion_query_set: None,
multiview_mask: None,
});

rpass.set_pipeline(&self.pipeline);
rpass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
rpass.multi_draw_indirect_count(
&self.indirect_buffer,
0,
&self.count_buffer,
0,
NUM_QUADS,
);
}

queue.submit([encoder.finish()]);
}
}

fn hsv_to_rgb(h: f32, s: f32, v: f32) -> (f32, f32, f32) {
let i = (h * 6.0) as i32 % 6;
let f = h * 6.0 - (h * 6.0).floor();
let p = v * (1.0 - s);
let q = v * (1.0 - f * s);
let t = v * (1.0 - (1.0 - f) * s);
match i {
0 => (v, t, p),
1 => (q, v, p),
2 => (p, v, t),
3 => (p, q, v),
4 => (t, p, v),
_ => (v, p, q),
}
}

pub fn main() {
crate::framework::run::<Example>(EXAMPLE_NAME);
}

#[cfg(test)]
#[wgpu_test::gpu_test]
pub static TEST: crate::framework::ExampleTestParams = crate::framework::ExampleTestParams {
name: EXAMPLE_NAME,
image_path: "/examples/features/src/multi_draw_indirect_count/screenshot.png",
width: 256,
height: 256,
optional_features: wgpu::Features::default(),
base_test_parameters: wgpu_test::TestParameters::default(),
comparisons: &[wgpu_test::ComparisonType::Mean(0.02)],
_phantom: std::marker::PhantomData::<Example>,
};
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions examples/features/src/multi_draw_indirect_count/shader.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
struct VertexOutput {
@builtin(position) position: vec4f,
@location(0) color: vec3f,
}

@vertex
fn vs_main(@location(0) position: vec2f, @location(1) color: vec3f) -> VertexOutput {
var out: VertexOutput;
out.position = vec4f(position, 0.0, 1.0);
out.color = color;
return out;
}

@fragment
fn fs_main(in: VertexOutput) -> @location(0) vec4f {
return vec4f(in.color, 1.0);
}
Loading
Loading