Skip to content

Commit ef622c1

Browse files
committed
validate multi draw indirect calls
1 parent 2ab3b6d commit ef622c1

3 files changed

Lines changed: 117 additions & 29 deletions

File tree

wgpu-core/src/command/bundle.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,15 +1051,19 @@ impl RenderBundle {
10511051
instance_limit,
10521052
} => {
10531053
let (buffer, offset) = if self.device.indirect_draw_validation.is_some() {
1054-
indirect_draw_validation_batcher.add(
1054+
let (dst_resource_index, offset) = indirect_draw_validation_batcher.add(
10551055
indirect_draw_validation_resources,
10561056
&self.device,
1057-
buffer.clone(),
1057+
buffer,
10581058
*offset,
10591059
*indexed,
10601060
*vertex_or_index_limit,
10611061
*instance_limit,
1062-
)?
1062+
)?;
1063+
1064+
let dst_buffer =
1065+
indirect_draw_validation_resources.get_dst_buffer(dst_resource_index);
1066+
(dst_buffer, offset)
10631067
} else {
10641068
(buffer.try_raw(snatch_guard)?, *offset)
10651069
};

wgpu-core/src/command/render.rs

Lines changed: 103 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,46 +2546,131 @@ fn multi_draw_indirect(
25462546
),
25472547
);
25482548

2549-
let (indirect_raw, offset) = if count == 1 && state.device.indirect_draw_validation.is_some() {
2549+
fn draw(
2550+
raw_encoder: &mut dyn hal::DynCommandEncoder,
2551+
indexed: bool,
2552+
indirect_buffer: &dyn hal::DynBuffer,
2553+
offset: u64,
2554+
count: u32,
2555+
) {
2556+
match indexed {
2557+
false => unsafe {
2558+
raw_encoder.draw_indirect(indirect_buffer, offset, count);
2559+
},
2560+
true => unsafe {
2561+
raw_encoder.draw_indexed_indirect(indirect_buffer, offset, count);
2562+
},
2563+
}
2564+
}
2565+
2566+
if state.device.indirect_draw_validation.is_some() {
25502567
state
25512568
.info
25522569
.usage_scope
25532570
.buffers
25542571
.merge_single(&indirect_buffer, wgt::BufferUses::STORAGE_READ_ONLY)?;
25552572

2556-
indirect_draw_validation_batcher.add(
2573+
struct DrawData {
2574+
buffer_index: usize,
2575+
offset: u64,
2576+
count: u32,
2577+
}
2578+
2579+
struct DrawContext<'a> {
2580+
raw_encoder: &'a mut dyn hal::DynCommandEncoder,
2581+
device: &'a Device,
2582+
2583+
indirect_draw_validation_resources:
2584+
&'a mut crate::indirect_draw_validation::IndirectDrawValidationResources,
2585+
indirect_draw_validation_batcher:
2586+
&'a mut crate::indirect_draw_validation::IndirectDrawValidationBatcher,
2587+
2588+
indirect_buffer: Arc<crate::resource::Buffer>,
2589+
indexed: bool,
2590+
vertex_or_index_limit: u64,
2591+
instance_limit: u64,
2592+
}
2593+
2594+
impl<'a> DrawContext<'a> {
2595+
fn add(&mut self, offset: u64) -> Result<DrawData, DeviceError> {
2596+
let (dst_resource_index, dst_offset) = self.indirect_draw_validation_batcher.add(
2597+
self.indirect_draw_validation_resources,
2598+
self.device,
2599+
&self.indirect_buffer,
2600+
offset,
2601+
self.indexed,
2602+
self.vertex_or_index_limit,
2603+
self.instance_limit,
2604+
)?;
2605+
Ok(DrawData {
2606+
buffer_index: dst_resource_index,
2607+
offset: dst_offset,
2608+
count: 1,
2609+
})
2610+
}
2611+
fn draw(&mut self, draw_data: DrawData) {
2612+
let dst_buffer = self
2613+
.indirect_draw_validation_resources
2614+
.get_dst_buffer(draw_data.buffer_index);
2615+
draw(
2616+
self.raw_encoder,
2617+
self.indexed,
2618+
dst_buffer,
2619+
draw_data.offset,
2620+
draw_data.count,
2621+
);
2622+
}
2623+
}
2624+
2625+
let mut draw_ctx = DrawContext {
2626+
raw_encoder: state.raw_encoder,
2627+
device: state.device,
25572628
indirect_draw_validation_resources,
2558-
state.device,
2629+
indirect_draw_validation_batcher,
25592630
indirect_buffer,
2560-
offset,
25612631
indexed,
2562-
if indexed {
2632+
vertex_or_index_limit: if indexed {
25632633
state.index.limit
25642634
} else {
25652635
state.vertex.limits.vertex_limit
25662636
},
2567-
state.vertex.limits.instance_limit,
2568-
)?
2637+
instance_limit: state.vertex.limits.instance_limit,
2638+
};
2639+
2640+
let mut current_draw_data = draw_ctx.add(offset)?;
2641+
2642+
for i in 1..count {
2643+
let draw_data = draw_ctx.add(offset + stride * i as u64)?;
2644+
2645+
if draw_data.buffer_index == current_draw_data.buffer_index {
2646+
debug_assert_eq!(
2647+
draw_data.offset,
2648+
current_draw_data.offset + stride * current_draw_data.count as u64
2649+
);
2650+
current_draw_data.count += 1;
2651+
} else {
2652+
draw_ctx.draw(current_draw_data);
2653+
current_draw_data = draw_data;
2654+
}
2655+
}
2656+
2657+
draw_ctx.draw(current_draw_data);
25692658
} else {
25702659
state
25712660
.info
25722661
.usage_scope
25732662
.buffers
25742663
.merge_single(&indirect_buffer, wgt::BufferUses::INDIRECT)?;
25752664

2576-
(indirect_buffer.try_raw(state.snatch_guard)?, offset)
2665+
draw(
2666+
state.raw_encoder,
2667+
indexed,
2668+
indirect_buffer.try_raw(state.snatch_guard)?,
2669+
offset,
2670+
count,
2671+
);
25772672
};
25782673

2579-
match indexed {
2580-
false => unsafe {
2581-
state.raw_encoder.draw_indirect(indirect_raw, offset, count);
2582-
},
2583-
true => unsafe {
2584-
state
2585-
.raw_encoder
2586-
.draw_indexed_indirect(indirect_raw, offset, count);
2587-
},
2588-
}
25892674
Ok(())
25902675
}
25912676

wgpu-core/src/indirect_draw_validation.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ impl IndirectDrawValidationResources {
751751
}
752752
}
753753

754-
fn get_dst_buffer(&self, index: usize) -> &dyn hal::DynBuffer {
754+
pub(crate) fn get_dst_buffer(&self, index: usize) -> &dyn hal::DynBuffer {
755755
self.dst_entries.get(index).unwrap().buffer.as_ref()
756756
}
757757

@@ -933,17 +933,18 @@ impl IndirectDrawValidationBatcher {
933933

934934
/// Add an indirect draw to be validated.
935935
///
936-
/// Returns an indirect buffer and offset to be used for the draw.
936+
/// Returns the index of the indirect buffer in `indirect_draw_validation_resources`
937+
/// and the offset to be used for the draw.
937938
pub(crate) fn add<'a>(
938939
&mut self,
939940
indirect_draw_validation_resources: &'a mut IndirectDrawValidationResources,
940941
device: &Device,
941-
src_buffer: Arc<crate::resource::Buffer>,
942+
src_buffer: &Arc<crate::resource::Buffer>,
942943
offset: u64,
943944
indexed: bool,
944945
vertex_or_index_limit: u64,
945946
instance_limit: u64,
946-
) -> Result<(&'a dyn hal::DynBuffer, u64), DeviceError> {
947+
) -> Result<(usize, u64), DeviceError> {
947948
let stride = crate::command::get_stride_of_indirect_args(indexed);
948949

949950
let (dst_resource_index, dst_offset) = indirect_draw_validation_resources
@@ -973,7 +974,7 @@ impl IndirectDrawValidationBatcher {
973974
}
974975
hashbrown::hash_map::Entry::Vacant(vacant_entry) => {
975976
vacant_entry.insert(DrawIndirectValidationBatch {
976-
src_buffer,
977+
src_buffer: src_buffer.clone(),
977978
src_dynamic_offset,
978979
dst_resource_index,
979980
entries: vec![entry],
@@ -987,8 +988,6 @@ impl IndirectDrawValidationBatcher {
987988
}
988989
}
989990

990-
let dst_buffer = indirect_draw_validation_resources.get_dst_buffer(dst_resource_index);
991-
992-
Ok((dst_buffer, dst_offset))
991+
Ok((dst_resource_index, dst_offset))
993992
}
994993
}

0 commit comments

Comments
 (0)