Add public structs for indirect command buffers

and fix missing IndirectBufferOverrun error for IndirectDispatch
This commit is contained in:
Andreas Reich
2021-01-30 09:38:09 +01:00
parent ac81f3e756
commit 6b51328b2e
3 changed files with 71 additions and 16 deletions

View File

@@ -23,7 +23,7 @@ use thiserror::Error;
use wgt::{BufferAddress, BufferUsage, ShaderStage};
use crate::track::UseExtendError;
use std::{fmt, iter, str};
use std::{fmt, iter, mem, str};
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
@@ -140,6 +140,12 @@ pub enum ComputePassErrorInner {
InvalidQuerySet(id::QuerySetId),
#[error("indirect buffer {0:?} is invalid or destroyed")]
InvalidIndirectBuffer(id::BufferId),
#[error("indirect buffer uses bytes {offset}..{end_offset} which overruns indirect buffer of size {buffer_size}")]
IndirectBufferOverrun {
offset: u64,
end_offset: u64,
buffer_size: u64,
},
#[error(transparent)]
ResourceUsageConflict(#[from] UsageConflict),
#[error(transparent)]
@@ -490,6 +496,17 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.map_pass_err(scope)?;
check_buffer_usage(indirect_buffer.usage, BufferUsage::INDIRECT)
.map_pass_err(scope)?;
let end_offset = offset + mem::size_of::<wgt::DispatchIndirectArgs>() as u64;
if end_offset > indirect_buffer.size {
return Err(ComputePassErrorInner::IndirectBufferOverrun {
offset,
end_offset,
buffer_size: indirect_buffer.size,
})
.map_pass_err(scope);
}
let &(ref buf_raw, _) = indirect_buffer
.raw
.as_ref()

View File

@@ -45,6 +45,7 @@ use std::{
collections::hash_map::Entry,
fmt, iter,
marker::PhantomData,
mem,
num::NonZeroU32,
ops::Range,
str,
@@ -417,11 +418,10 @@ pub enum RenderPassErrorInner {
InvalidValuesOffset,
#[error("required device features not enabled: {0:?}")]
MissingDeviceFeatures(wgt::Features),
#[error("indirect draw with offset {offset}{} uses bytes {begin_offset}..{end_offset} which overruns indirect buffer of size {buffer_size}", count.map_or_else(String::new, |v| format!(" and count {}", v)))]
#[error("indirect draw uses bytes {offset}..{end_offset} {} which overruns indirect buffer of size {buffer_size}", count.map_or_else(String::new, |v| format!("(using count {})", v)))]
IndirectBufferOverrun {
offset: u64,
count: Option<NonZeroU32>,
begin_offset: u64,
offset: u64,
end_offset: u64,
buffer_size: u64,
},
@@ -1549,9 +1549,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
state.is_ready().map_pass_err(scope)?;
let stride = match indexed {
false => 16,
true => 20,
};
false => mem::size_of::<wgt::DrawIndirectArgs>(),
true => mem::size_of::<wgt::DrawIndexedIndirectArgs>(),
} as u64;
if count.is_some() {
check_device_features(
@@ -1577,13 +1577,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
let actual_count = count.map_or(1, |c| c.get());
let begin_offset = offset;
let end_offset = offset + stride * actual_count as u64;
if end_offset > indirect_buffer.size {
return Err(RenderPassErrorInner::IndirectBufferOverrun {
offset,
count,
begin_offset,
offset,
end_offset,
buffer_size: indirect_buffer.size,
})
@@ -1625,9 +1623,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
state.is_ready().map_pass_err(scope)?;
let stride = match indexed {
false => 16,
true => 20,
};
false => mem::size_of::<wgt::DrawIndirectArgs>(),
true => mem::size_of::<wgt::DrawIndexedIndirectArgs>(),
} as u64;
check_device_features(
device.features,
@@ -1663,13 +1661,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
.ok_or(RenderCommandError::DestroyedBuffer(count_buffer_id))
.map_pass_err(scope)?;
let begin_offset = offset;
let end_offset = offset + stride * max_count as u64;
if end_offset > indirect_buffer.size {
return Err(RenderPassErrorInner::IndirectBufferOverrun {
offset,
count: None,
begin_offset,
offset,
end_offset,
buffer_size: indirect_buffer.size,
})

View File

@@ -2811,3 +2811,45 @@ bitflags::bitflags! {
const COMPUTE_SHADER_INVOCATIONS = 0x10;
}
}
/// Argument buffer layout for draw_indirect commands.
#[repr(C)]
#[derive(Clone, Debug)]
pub struct DrawIndirectArgs {
/// The number of vertices to draw.
pub vertex_count: u32,
/// The number of instances to draw.
pub instance_count: u32,
/// Offset into the vertex buffers, in vertices, to begin drawing from.
pub first_vertex: u32,
/// First instance to draw.
pub first_instance: u32,
}
/// Argument buffer layout for draw_indexed_indirect commands.
#[repr(C)]
#[derive(Clone, Debug)]
pub struct DrawIndexedIndirectArgs {
/// The number of indices to draw.
pub index_count: u32,
/// The number of instances to draw.
pub instance_count: u32,
/// Offset into the index buffer, in indices, begin drawing from.
pub first_index: u32,
/// Added to each index value before indexing into the vertex buffers.
pub base_vertex: i32,
/// First instance to draw.
pub first_instance: u32,
}
/// Argument buffer layout for dispatch_indirect commands.
#[repr(C)]
#[derive(Clone, Debug)]
pub struct DispatchIndirectArgs {
/// X dimension of the grid of workgroups to dispatch.
pub group_size_x: u32,
/// Y dimension of the grid of workgroups to dispatch.
pub group_size_y: u32,
/// Z dimension of the grid of workgroups to dispatch.
pub group_size_z: u32,
}