Skip to content

Commit fabcba8

Browse files
authored
Refine Multi-Draw-Indirect (#6870)
1 parent 78e35c4 commit fabcba8

File tree

6 files changed

+55
-55
lines changed

6 files changed

+55
-55
lines changed

wgpu-core/src/command/bundle.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -484,10 +484,10 @@ impl RenderBundleEncoder {
484484
)
485485
.map_pass_err(scope)?;
486486
}
487-
RenderCommand::MultiDrawIndirect {
487+
RenderCommand::DrawIndirect {
488488
buffer_id,
489489
offset,
490-
count: None,
490+
count: 1,
491491
indexed,
492492
} => {
493493
let scope = PassErrorScope::Draw {
@@ -504,7 +504,7 @@ impl RenderBundleEncoder {
504504
)
505505
.map_pass_err(scope)?;
506506
}
507-
RenderCommand::MultiDrawIndirect { .. }
507+
RenderCommand::DrawIndirect { .. }
508508
| RenderCommand::MultiDrawIndirectCount { .. } => unimplemented!(),
509509
RenderCommand::PushDebugGroup { color: _, len: _ } => unimplemented!(),
510510
RenderCommand::InsertDebugMarker { color: _, len: _ } => unimplemented!(),
@@ -887,10 +887,10 @@ fn multi_draw_indirect(
887887

888888
state.flush_vertices();
889889
state.flush_binds(used_bind_groups, dynamic_offsets);
890-
state.commands.push(ArcRenderCommand::MultiDrawIndirect {
890+
state.commands.push(ArcRenderCommand::DrawIndirect {
891891
buffer,
892892
offset,
893-
count: None,
893+
count: 1,
894894
indexed,
895895
});
896896
Ok(())
@@ -1101,25 +1101,25 @@ impl RenderBundle {
11011101
)
11021102
};
11031103
}
1104-
Cmd::MultiDrawIndirect {
1104+
Cmd::DrawIndirect {
11051105
buffer,
11061106
offset,
1107-
count: None,
1107+
count: 1,
11081108
indexed: false,
11091109
} => {
11101110
let buffer = buffer.try_raw(snatch_guard)?;
11111111
unsafe { raw.draw_indirect(buffer, *offset, 1) };
11121112
}
1113-
Cmd::MultiDrawIndirect {
1113+
Cmd::DrawIndirect {
11141114
buffer,
11151115
offset,
1116-
count: None,
1116+
count: 1,
11171117
indexed: true,
11181118
} => {
11191119
let buffer = buffer.try_raw(snatch_guard)?;
11201120
unsafe { raw.draw_indexed_indirect(buffer, *offset, 1) };
11211121
}
1122-
Cmd::MultiDrawIndirect { .. } | Cmd::MultiDrawIndirectCount { .. } => {
1122+
Cmd::DrawIndirect { .. } | Cmd::MultiDrawIndirectCount { .. } => {
11231123
return Err(ExecutionError::Unimplemented("multi-draw-indirect"))
11241124
}
11251125
Cmd::PushDebugGroup { .. } | Cmd::InsertDebugMarker { .. } | Cmd::PopDebugGroup => {
@@ -1727,10 +1727,10 @@ pub mod bundle_ffi {
17271727
buffer_id: id::BufferId,
17281728
offset: BufferAddress,
17291729
) {
1730-
bundle.base.commands.push(RenderCommand::MultiDrawIndirect {
1730+
bundle.base.commands.push(RenderCommand::DrawIndirect {
17311731
buffer_id,
17321732
offset,
1733-
count: None,
1733+
count: 1,
17341734
indexed: false,
17351735
});
17361736
}
@@ -1740,10 +1740,10 @@ pub mod bundle_ffi {
17401740
buffer_id: id::BufferId,
17411741
offset: BufferAddress,
17421742
) {
1743-
bundle.base.commands.push(RenderCommand::MultiDrawIndirect {
1743+
bundle.base.commands.push(RenderCommand::DrawIndirect {
17441744
buffer_id,
17451745
offset,
1746-
count: None,
1746+
count: 1,
17471747
indexed: true,
17481748
});
17491749
}

wgpu-core/src/command/render.rs

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -676,10 +676,9 @@ pub enum RenderPassErrorInner {
676676
MissingDownlevelFlags(#[from] MissingDownlevelFlags),
677677
#[error("Indirect buffer offset {0:?} is not a multiple of 4")]
678678
UnalignedIndirectBufferOffset(BufferAddress),
679-
#[error("Indirect draw uses bytes {offset}..{end_offset} {} which overruns indirect buffer of size {buffer_size}",
680-
count.map_or_else(String::new, |v| format!("(using count {v})")))]
679+
#[error("Indirect draw uses bytes {offset}..{end_offset} using count {count} which overruns indirect buffer of size {buffer_size}")]
681680
IndirectBufferOverrun {
682-
count: Option<NonZeroU32>,
681+
count: u32,
683682
offset: u64,
684683
end_offset: u64,
685684
buffer_size: u64,
@@ -1787,14 +1786,14 @@ impl Global {
17871786
)
17881787
.map_pass_err(scope)?;
17891788
}
1790-
ArcRenderCommand::MultiDrawIndirect {
1789+
ArcRenderCommand::DrawIndirect {
17911790
buffer,
17921791
offset,
17931792
count,
17941793
indexed,
17951794
} => {
17961795
let scope = PassErrorScope::Draw {
1797-
kind: if count.is_some() {
1796+
kind: if count != 1 {
17981797
DrawKind::MultiDrawIndirect
17991798
} else {
18001799
DrawKind::DrawIndirect
@@ -2467,7 +2466,7 @@ fn multi_draw_indirect(
24672466
cmd_buf: &Arc<CommandBuffer>,
24682467
indirect_buffer: Arc<crate::resource::Buffer>,
24692468
offset: u64,
2470-
count: Option<NonZeroU32>,
2469+
count: u32,
24712470
indexed: bool,
24722471
) -> Result<(), RenderPassErrorInner> {
24732472
api_log!(
@@ -2482,7 +2481,7 @@ fn multi_draw_indirect(
24822481
true => size_of::<wgt::DrawIndexedIndirectArgs>(),
24832482
};
24842483

2485-
if count.is_some() {
2484+
if count != 1 {
24862485
state
24872486
.device
24882487
.require_features(wgt::Features::MULTI_DRAW_INDIRECT)?;
@@ -2502,13 +2501,11 @@ fn multi_draw_indirect(
25022501
indirect_buffer.check_usage(BufferUsages::INDIRECT)?;
25032502
let indirect_raw = indirect_buffer.try_raw(state.snatch_guard)?;
25042503

2505-
let actual_count = count.map_or(1, |c| c.get());
2506-
25072504
if offset % 4 != 0 {
25082505
return Err(RenderPassErrorInner::UnalignedIndirectBufferOffset(offset));
25092506
}
25102507

2511-
let end_offset = offset + stride as u64 * actual_count as u64;
2508+
let end_offset = offset + stride as u64 * count as u64;
25122509
if end_offset > indirect_buffer.size {
25132510
return Err(RenderPassErrorInner::IndirectBufferOverrun {
25142511
count,
@@ -2528,14 +2525,12 @@ fn multi_draw_indirect(
25282525

25292526
match indexed {
25302527
false => unsafe {
2531-
state
2532-
.raw_encoder
2533-
.draw_indirect(indirect_raw, offset, actual_count);
2528+
state.raw_encoder.draw_indirect(indirect_raw, offset, count);
25342529
},
25352530
true => unsafe {
25362531
state
25372532
.raw_encoder
2538-
.draw_indexed_indirect(indirect_raw, offset, actual_count);
2533+
.draw_indexed_indirect(indirect_raw, offset, count);
25392534
},
25402535
}
25412536
Ok(())
@@ -2599,7 +2594,7 @@ fn multi_draw_indirect_count(
25992594
let end_offset = offset + stride * max_count as u64;
26002595
if end_offset > indirect_buffer.size {
26012596
return Err(RenderPassErrorInner::IndirectBufferOverrun {
2602-
count: None,
2597+
count: 1,
26032598
offset,
26042599
end_offset,
26052600
buffer_size: indirect_buffer.size,
@@ -3103,10 +3098,10 @@ impl Global {
31033098
};
31043099
let base = pass.base_mut(scope)?;
31053100

3106-
base.commands.push(ArcRenderCommand::MultiDrawIndirect {
3101+
base.commands.push(ArcRenderCommand::DrawIndirect {
31073102
buffer: self.resolve_render_pass_buffer_id(scope, buffer_id)?,
31083103
offset,
3109-
count: None,
3104+
count: 1,
31103105
indexed: false,
31113106
});
31123107

@@ -3125,10 +3120,10 @@ impl Global {
31253120
};
31263121
let base = pass.base_mut(scope)?;
31273122

3128-
base.commands.push(ArcRenderCommand::MultiDrawIndirect {
3123+
base.commands.push(ArcRenderCommand::DrawIndirect {
31293124
buffer: self.resolve_render_pass_buffer_id(scope, buffer_id)?,
31303125
offset,
3131-
count: None,
3126+
count: 1,
31323127
indexed: true,
31333128
});
31343129

@@ -3148,10 +3143,10 @@ impl Global {
31483143
};
31493144
let base = pass.base_mut(scope)?;
31503145

3151-
base.commands.push(ArcRenderCommand::MultiDrawIndirect {
3146+
base.commands.push(ArcRenderCommand::DrawIndirect {
31523147
buffer: self.resolve_render_pass_buffer_id(scope, buffer_id)?,
31533148
offset,
3154-
count: NonZeroU32::new(count),
3149+
count,
31553150
indexed: false,
31563151
});
31573152

@@ -3171,10 +3166,10 @@ impl Global {
31713166
};
31723167
let base = pass.base_mut(scope)?;
31733168

3174-
base.commands.push(ArcRenderCommand::MultiDrawIndirect {
3169+
base.commands.push(ArcRenderCommand::DrawIndirect {
31753170
buffer: self.resolve_render_pass_buffer_id(scope, buffer_id)?,
31763171
offset,
3177-
count: NonZeroU32::new(count),
3172+
count,
31783173
indexed: true,
31793174
});
31803175

wgpu-core/src/command/render_command.rs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::{
66
};
77
use wgt::{BufferAddress, BufferSize, Color};
88

9-
use std::{num::NonZeroU32, sync::Arc};
9+
use std::sync::Arc;
1010

1111
use super::{Rect, RenderBundle};
1212

@@ -82,11 +82,10 @@ pub enum RenderCommand {
8282
base_vertex: i32,
8383
first_instance: u32,
8484
},
85-
MultiDrawIndirect {
85+
DrawIndirect {
8686
buffer_id: id::BufferId,
8787
offset: BufferAddress,
88-
/// Count of `None` represents a non-multi call.
89-
count: Option<NonZeroU32>,
88+
count: u32,
9089
indexed: bool,
9190
},
9291
MultiDrawIndirectCount {
@@ -311,16 +310,16 @@ impl RenderCommand {
311310
first_instance,
312311
},
313312

314-
RenderCommand::MultiDrawIndirect {
313+
RenderCommand::DrawIndirect {
315314
buffer_id,
316315
offset,
317316
count,
318317
indexed,
319-
} => ArcRenderCommand::MultiDrawIndirect {
318+
} => ArcRenderCommand::DrawIndirect {
320319
buffer: buffers_guard.get(buffer_id).get().map_err(|e| {
321320
RenderPassError {
322321
scope: PassErrorScope::Draw {
323-
kind: if count.is_some() {
322+
kind: if count != 1 {
324323
DrawKind::MultiDrawIndirect
325324
} else {
326325
DrawKind::DrawIndirect
@@ -459,11 +458,10 @@ pub enum ArcRenderCommand {
459458
base_vertex: i32,
460459
first_instance: u32,
461460
},
462-
MultiDrawIndirect {
461+
DrawIndirect {
463462
buffer: Arc<Buffer>,
464463
offset: BufferAddress,
465-
/// Count of `None` represents a non-multi call.
466-
count: Option<NonZeroU32>,
464+
count: u32,
467465
indexed: bool,
468466
},
469467
MultiDrawIndirectCount {

wgpu-hal/src/gles/adapter.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ impl super::Adapter {
372372
} else {
373373
vertex_shader_storage_textures.min(fragment_shader_storage_textures)
374374
};
375+
let indirect_execution =
376+
supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_multi_draw_indirect");
375377

376378
let mut downlevel_flags = wgt::DownlevelFlags::empty()
377379
| wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES
@@ -383,10 +385,7 @@ impl super::Adapter {
383385
wgt::DownlevelFlags::FRAGMENT_WRITABLE_STORAGE,
384386
max_storage_block_size != 0,
385387
);
386-
downlevel_flags.set(
387-
wgt::DownlevelFlags::INDIRECT_EXECUTION,
388-
supported((3, 1), (4, 3)) || extensions.contains("GL_ARB_multi_draw_indirect"),
389-
);
388+
downlevel_flags.set(wgt::DownlevelFlags::INDIRECT_EXECUTION, indirect_execution);
390389
downlevel_flags.set(wgt::DownlevelFlags::BASE_VERTEX, supported((3, 2), (3, 2)));
391390
downlevel_flags.set(
392391
wgt::DownlevelFlags::INDEPENDENT_BLEND,
@@ -471,6 +470,8 @@ impl super::Adapter {
471470
wgt::Features::SHADER_EARLY_DEPTH_TEST,
472471
supported((3, 1), (4, 2)) || extensions.contains("GL_ARB_shader_image_load_store"),
473472
);
473+
// We emulate MDI with a loop of draw calls.
474+
features.set(wgt::Features::MULTI_DRAW_INDIRECT, indirect_execution);
474475
if extensions.contains("GL_ARB_timer_query") {
475476
features.set(wgt::Features::TIMESTAMP_QUERY, true);
476477
features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS, true);

wgpu-types/src/lib.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -638,12 +638,17 @@ bitflags::bitflags! {
638638
///
639639
/// Allows multiple indirect calls to be dispatched from a single buffer.
640640
///
641-
/// Supported platforms:
641+
/// Natively Supported Platforms:
642642
/// - DX12
643643
/// - Vulkan
644-
/// - Metal on Apple3+ or Mac1+ (Emulated on top of `draw_indirect` and `draw_indexed_indirect`)
645644
///
646-
/// This is a native only feature.
645+
/// Emulated Platforms:
646+
/// - Metal
647+
/// - OpenGL
648+
/// - WebGPU
649+
///
650+
/// Emulation is preformed by looping over the individual indirect draw calls in the backend. This is still significantly
651+
/// faster than enulating it yourself, as wgpu only does draw call validation once.
647652
///
648653
/// [`RenderPass::multi_draw_indirect`]: ../wgpu/struct.RenderPass.html#method.multi_draw_indirect
649654
/// [`RenderPass::multi_draw_indexed_indirect`]: ../wgpu/struct.RenderPass.html#method.multi_draw_indexed_indirect

wgpu/src/backend/webgpu.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -783,7 +783,8 @@ const FEATURES_MAPPING: [(wgt::Features, webgpu_sys::GpuFeatureName); 12] = [
783783
];
784784

785785
fn map_wgt_features(supported_features: webgpu_sys::GpuSupportedFeatures) -> wgt::Features {
786-
let mut features = wgt::Features::empty();
786+
// We emulate MDI.
787+
let mut features = wgt::Features::MULTI_DRAW_INDIRECT;
787788
for (wgpu_feat, web_feat) in FEATURES_MAPPING {
788789
match wasm_bindgen::JsValue::from(web_feat).as_string() {
789790
Some(value) if supported_features.has(&value) => features |= wgpu_feat,

0 commit comments

Comments
 (0)