Skip to content
Merged
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,16 @@ Difference for SPIR-V passthrough:
This allows using precompiled shaders without manually checking which backend's code to pass, for example if you have shaders precompiled for both DXIL and SPIR-V.


#### Multi-draw indirect is now unconditionally supported when indirect draws are supported

We have removed `Features::MULTI_DRAW_INDIRECT` as it was unconditionally available on all platforms.
`RenderPass::multi_draw_indirect` is now available if the device supports downlevel flag `DownlevelFlags::INDIRECT_EXECUTION`.

If you are using spirv-passthrough with multi-draw indirect and `gl_DrawID`, you can know if `MULTI_DRAW_INDIRECT` is being emulated
by if the `Feature::MULTI_DRAW_INDIRECT_COUNT` feature is available on the device, this feature cannot be emulated efficicently.

By @cwfitzgerald in [#8162](https://github.com/gfx-rs/wgpu/pull/8162).

### New Features

#### General
Expand Down
6 changes: 0 additions & 6 deletions deno_webgpu/webidl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -399,8 +399,6 @@ pub enum GPUFeatureName {
UniformBufferBindingArrays,
#[webidl(rename = "partially-bound-binding-array")]
PartiallyBoundBindingArray,
#[webidl(rename = "multi-draw-indirect")]
MultiDrawIndirect,
#[webidl(rename = "multi-draw-indirect-count")]
MultiDrawIndirectCount,
#[webidl(rename = "push-constants")]
Expand Down Expand Up @@ -470,7 +468,6 @@ pub fn feature_names_to_features(names: Vec<GPUFeatureName>) -> wgpu_types::Feat
GPUFeatureName::StorageTextureArrayNonUniformIndexing => Features::STORAGE_TEXTURE_ARRAY_NON_UNIFORM_INDEXING,
GPUFeatureName::UniformBufferBindingArrays => Features::UNIFORM_BUFFER_BINDING_ARRAYS,
GPUFeatureName::PartiallyBoundBindingArray => Features::PARTIALLY_BOUND_BINDING_ARRAY,
GPUFeatureName::MultiDrawIndirect => Features::MULTI_DRAW_INDIRECT,
GPUFeatureName::MultiDrawIndirectCount => Features::MULTI_DRAW_INDIRECT_COUNT,
GPUFeatureName::PushConstants => Features::PUSH_CONSTANTS,
GPUFeatureName::AddressModeClampToZero => Features::ADDRESS_MODE_CLAMP_TO_ZERO,
Expand Down Expand Up @@ -593,9 +590,6 @@ pub fn features_to_feature_names(features: wgpu_types::Features) -> HashSet<GPUF
if features.contains(wgpu_types::Features::PARTIALLY_BOUND_BINDING_ARRAY) {
return_features.insert(PartiallyBoundBindingArray);
}
if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT) {
return_features.insert(MultiDrawIndirect);
}
if features.contains(wgpu_types::Features::MULTI_DRAW_INDIRECT_COUNT) {
return_features.insert(MultiDrawIndirectCount);
}
Expand Down
5 changes: 3 additions & 2 deletions tests/tests/wgpu-gpu/mesh_shader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,9 @@ fn default_gpu_test_config(draw_type: DrawType) -> GpuTestConfiguration {
wgpu::Features::EXPERIMENTAL_MESH_SHADER
| wgpu::Features::EXPERIMENTAL_PASSTHROUGH_SHADERS
| match draw_type {
DrawType::Standard | DrawType::Indirect => wgpu::Features::empty(),
DrawType::MultiIndirect => wgpu::Features::MULTI_DRAW_INDIRECT,
DrawType::Standard | DrawType::Indirect | DrawType::MultiIndirect => {
wgpu::Features::empty()
}
DrawType::MultiIndirectCount => wgpu::Features::MULTI_DRAW_INDIRECT_COUNT,
},
)
Expand Down
7 changes: 0 additions & 7 deletions wgpu-core/src/command/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2696,13 +2696,6 @@ fn multi_draw_indirect(

state.is_ready(family)?;

if count != 1 {
state
.general
.device
.require_features(wgt::Features::MULTI_DRAW_INDIRECT)?;
}

state
.general
.device
Expand Down
1 change: 0 additions & 1 deletion wgpu-hal/src/dx12/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,6 @@ impl super::Adapter {
| wgt::Features::DEPTH32FLOAT_STENCIL8
| wgt::Features::INDIRECT_FIRST_INSTANCE
| wgt::Features::MAPPABLE_PRIMARY_BUFFERS
| wgt::Features::MULTI_DRAW_INDIRECT
| wgt::Features::MULTI_DRAW_INDIRECT_COUNT
| wgt::Features::ADDRESS_MODE_CLAMP_TO_BORDER
| wgt::Features::ADDRESS_MODE_CLAMP_TO_ZERO
Expand Down
2 changes: 0 additions & 2 deletions wgpu-hal/src/gles/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -479,8 +479,6 @@ impl super::Adapter {
wgt::Features::SHADER_EARLY_DEPTH_TEST,
supported((3, 1), (4, 2)) || extensions.contains("GL_ARB_shader_image_load_store"),
);
// We emulate MDI with a loop of draw calls.
features.set(wgt::Features::MULTI_DRAW_INDIRECT, indirect_execution);
if extensions.contains("GL_ARB_timer_query") {
features.set(wgt::Features::TIMESTAMP_QUERY, true);
features.set(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS, true);
Expand Down
5 changes: 1 addition & 4 deletions wgpu-hal/src/metal/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -931,10 +931,7 @@ impl super::PrivateCapabilities {
| F::EXTERNAL_TEXTURE;

features.set(F::FLOAT32_FILTERABLE, self.supports_float_filtering);
features.set(
F::INDIRECT_FIRST_INSTANCE | F::MULTI_DRAW_INDIRECT,
self.indirect_draw_dispatch,
);
features.set(F::INDIRECT_FIRST_INSTANCE, self.indirect_draw_dispatch);
features.set(
F::TIMESTAMP_QUERY | F::TIMESTAMP_QUERY_INSIDE_ENCODERS,
self.timestamp_query_support
Expand Down
6 changes: 2 additions & 4 deletions wgpu-hal/src/vulkan/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,7 @@ impl PhysicalDeviceFeatures {
requested_features.contains(wgt::Features::INDIRECT_FIRST_INSTANCE),
)
//.dual_src_blend(requested_features.contains(wgt::Features::DUAL_SRC_BLENDING))
.multi_draw_indirect(
requested_features.contains(wgt::Features::MULTI_DRAW_INDIRECT),
)
.multi_draw_indirect(phd_features.core.multi_draw_indirect != 0)
.fill_mode_non_solid(requested_features.intersects(
wgt::Features::POLYGON_MODE_LINE | wgt::Features::POLYGON_MODE_POINT,
))
Expand Down Expand Up @@ -602,7 +600,6 @@ impl PhysicalDeviceFeatures {
self.core.draw_indirect_first_instance != 0,
);
//if self.core.dual_src_blend != 0
features.set(F::MULTI_DRAW_INDIRECT, self.core.multi_draw_indirect != 0);
features.set(F::POLYGON_MODE_LINE, self.core.fill_mode_non_solid != 0);
features.set(F::POLYGON_MODE_POINT, self.core.fill_mode_non_solid != 0);
//if self.core.depth_bounds != 0 {
Expand Down Expand Up @@ -1775,6 +1772,7 @@ impl super::Instance {
vk::ImageTiling::OPTIMAL,
depth_stencil_required_flags(),
),
multi_draw_indirect: phd_features.core.multi_draw_indirect != 0,
non_coherent_map_mask: phd_capabilities.properties.limits.non_coherent_atom_size - 1,
can_present: true,
//TODO: make configurable
Expand Down
32 changes: 23 additions & 9 deletions wgpu-hal/src/vulkan/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1146,15 +1146,29 @@ impl crate::CommandEncoder for super::CommandEncoder {
offset: wgt::BufferAddress,
draw_count: u32,
) {
unsafe {
self.device.raw.cmd_draw_indexed_indirect(
self.active,
buffer.raw,
offset,
draw_count,
size_of::<wgt::DrawIndexedIndirectArgs>() as u32,
)
};
if draw_count >= 1 && self.device.private_caps.multi_draw_indirect {
unsafe {
self.device.raw.cmd_draw_indexed_indirect(
self.active,
buffer.raw,
offset,
draw_count,
size_of::<wgt::DrawIndexedIndirectArgs>() as u32,
)
};
} else {
for _ in 0..draw_count {
unsafe {
self.device.raw.cmd_draw_indexed_indirect(
self.active,
buffer.raw,
offset,
1,
size_of::<wgt::DrawIndexedIndirectArgs>() as u32,
)
};
}
}
}
unsafe fn draw_mesh_tasks_indirect(
&mut self,
Expand Down
1 change: 1 addition & 0 deletions wgpu-hal/src/vulkan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,7 @@ struct PrivateCapabilities {
/// Ability to present contents to any screen. Only needed to work around broken platform configurations.
can_present: bool,
non_coherent_map_mask: wgt::BufferAddress,
multi_draw_indirect: bool,

/// True if this adapter advertises the [`robustBufferAccess`][vrba] feature.
///
Expand Down
25 changes: 5 additions & 20 deletions wgpu-types/src/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -784,35 +784,20 @@ bitflags_array! {
///
/// This is a native only feature.
const PARTIALLY_BOUND_BINDING_ARRAY = 1 << 13;
/// Allows the user to call [`RenderPass::multi_draw_indirect`] and [`RenderPass::multi_draw_indexed_indirect`].
///
/// Allows multiple indirect calls to be dispatched from a single buffer.
///
/// Natively Supported Platforms:
/// - DX12
/// - Vulkan
///
/// Emulated Platforms:
/// - Metal
/// - OpenGL
/// - WebGPU
///
/// Emulation is preformed by looping over the individual indirect draw calls in the backend. This is still significantly
/// faster than enulating it yourself, as wgpu only does draw call validation once.
///
/// [`RenderPass::multi_draw_indirect`]: ../wgpu/struct.RenderPass.html#method.multi_draw_indirect
/// [`RenderPass::multi_draw_indexed_indirect`]: ../wgpu/struct.RenderPass.html#method.multi_draw_indexed_indirect
const MULTI_DRAW_INDIRECT = 1 << 14;
/// Allows the user to call [`RenderPass::multi_draw_indirect_count`] and [`RenderPass::multi_draw_indexed_indirect_count`].
///
/// This allows the use of a buffer containing the actual number of draw calls.
/// This allows the use of a buffer containing the actual number of draw calls. This feature being present also implies
/// that all calls to [`RenderPass::multi_draw_indirect`] and [`RenderPass::multi_draw_indexed_indirect`] are not being emulated
/// with a series of `draw_indirect` calls.
///
/// Supported platforms:
/// - DX12
/// - Vulkan 1.2+ (or VK_KHR_draw_indirect_count)
///
/// This is a native only feature.
///
/// [`RenderPass::multi_draw_indirect`]: ../wgpu/struct.RenderPass.html#method.multi_draw_indirect
/// [`RenderPass::multi_draw_indexed_indirect`]: ../wgpu/struct.RenderPass.html#method.multi_draw_indexed_indirect
/// [`RenderPass::multi_draw_indirect_count`]: ../wgpu/struct.RenderPass.html#method.multi_draw_indirect_count
/// [`RenderPass::multi_draw_indexed_indirect_count`]: ../wgpu/struct.RenderPass.html#method.multi_draw_indexed_indirect_count
const MULTI_DRAW_INDIRECT_COUNT = 1 << 15;
Expand Down
11 changes: 8 additions & 3 deletions wgpu/src/api/render_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,8 @@ impl RenderPass<'_> {
///
/// This is like calling [`RenderPass::draw`] but the contents of the call are specified in the `indirect_buffer`.
/// The structure expected in `indirect_buffer` must conform to [`DrawIndirectArgs`](crate::util::DrawIndirectArgs).
///
/// Calling this requires the device support [`DownlevelFlags::INDIRECT_EXECUTION`].
pub fn draw_indirect(&mut self, indirect_buffer: &Buffer, indirect_offset: BufferAddress) {
self.inner
.draw_indirect(&indirect_buffer.inner, indirect_offset);
Expand All @@ -246,6 +248,8 @@ impl RenderPass<'_> {
///
/// This is like calling [`RenderPass::draw_indexed`] but the contents of the call are specified in the `indirect_buffer`.
/// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirectArgs`](crate::util::DrawIndexedIndirectArgs).
///
/// Calling this requires the device support [`DownlevelFlags::INDIRECT_EXECUTION`].
pub fn draw_indexed_indirect(
&mut self,
indirect_buffer: &Buffer,
Expand Down Expand Up @@ -287,10 +291,7 @@ impl RenderPass<'_> {

self.inner.execute_bundles(&mut render_bundles);
}
}

/// [`Features::MULTI_DRAW_INDIRECT`] must be enabled on the device in order to call these functions.
impl RenderPass<'_> {
/// Dispatches multiple draw calls from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
/// `count` draw calls are issued.
///
Expand All @@ -299,6 +300,8 @@ impl RenderPass<'_> {
/// The structure expected in `indirect_buffer` must conform to [`DrawIndirectArgs`](crate::util::DrawIndirectArgs).
/// These draw structures are expected to be tightly packed.
///
/// Calling this requires the device support [`DownlevelFlags::INDIRECT_EXECUTION`].
///
/// This drawing command uses the current render state, as set by preceding `set_*()` methods.
/// It is not affected by changes to the state that are performed after it is called.
pub fn multi_draw_indirect(
Expand All @@ -320,6 +323,8 @@ impl RenderPass<'_> {
/// The structure expected in `indirect_buffer` must conform to [`DrawIndexedIndirectArgs`](crate::util::DrawIndexedIndirectArgs).
/// These draw structures are expected to be tightly packed.
///
/// Calling this requires the device support [`DownlevelFlags::INDIRECT_EXECUTION`].
///
/// This drawing command uses the current render state, as set by preceding `set_*()` methods.
/// It is not affected by changes to the state that are performed after it is called.
pub fn multi_draw_indexed_indirect(
Expand Down
3 changes: 1 addition & 2 deletions wgpu/src/backend/webgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,8 +772,7 @@ const FEATURES_MAPPING: [(wgt::Features, webgpu_sys::GpuFeatureName); 15] = [
];

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