diff options
Diffstat (limited to 'third_party/rust/wgpu-core/src/command')
-rw-r--r-- | third_party/rust/wgpu-core/src/command/bundle.rs | 294 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/command/clear.rs | 45 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/command/compute.rs | 35 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/command/draw.rs | 120 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/command/mod.rs | 5 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/command/query.rs | 9 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/command/render.rs | 54 |
7 files changed, 359 insertions, 203 deletions
diff --git a/third_party/rust/wgpu-core/src/command/bundle.rs b/third_party/rust/wgpu-core/src/command/bundle.rs index 9d80c62f85..ab2d18bc59 100644 --- a/third_party/rust/wgpu-core/src/command/bundle.rs +++ b/third_party/rust/wgpu-core/src/command/bundle.rs @@ -97,7 +97,7 @@ use crate::{ id, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, pipeline::{PipelineFlags, RenderPipeline, VertexStep}, - resource::{Resource, ResourceInfo, ResourceType}, + resource::{Buffer, Resource, ResourceInfo, ResourceType}, resource_log, track::RenderBundleScope, validation::check_buffer_usage, @@ -110,9 +110,11 @@ use thiserror::Error; use hal::CommandEncoder as _; +use super::ArcRenderCommand; + /// https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-draw -fn validate_draw( - vertex: &[Option<VertexState>], +fn validate_draw<A: HalApi>( + vertex: &[Option<VertexState<A>>], step: &[VertexStep], first_vertex: u32, vertex_count: u32, @@ -152,10 +154,10 @@ fn validate_draw( } // See https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-drawindexed -fn validate_indexed_draw( - vertex: &[Option<VertexState>], +fn validate_indexed_draw<A: HalApi>( + vertex: &[Option<VertexState<A>>], step: &[VertexStep], - index_state: &IndexState, + index_state: &IndexState<A>, first_index: u32, index_count: u32, first_instance: u32, @@ -260,6 +262,9 @@ impl RenderBundleEncoder { None => (true, true), }; + // TODO: should be device.limits.max_color_attachments + let max_color_attachments = hal::MAX_COLOR_ATTACHMENTS; + //TODO: validate that attachment formats are renderable, // have expected aspects, support multisampling. Ok(Self { @@ -267,11 +272,11 @@ impl RenderBundleEncoder { parent_id, context: RenderPassContext { attachments: AttachmentData { - colors: if desc.color_formats.len() > hal::MAX_COLOR_ATTACHMENTS { + colors: if desc.color_formats.len() > max_color_attachments { return Err(CreateRenderBundleError::ColorAttachment( ColorAttachmentError::TooMany { given: desc.color_formats.len(), - limit: hal::MAX_COLOR_ATTACHMENTS, + limit: max_color_attachments, }, )); } else { @@ -345,24 +350,44 @@ impl RenderBundleEncoder { ) -> Result<RenderBundle<A>, RenderBundleError> { let bind_group_guard = hub.bind_groups.read(); let pipeline_guard = hub.render_pipelines.read(); - let query_set_guard = hub.query_sets.read(); let buffer_guard = hub.buffers.read(); - let texture_guard = hub.textures.read(); let mut state = State { - trackers: RenderBundleScope::new( - &*buffer_guard, - &*texture_guard, - &*bind_group_guard, - &*pipeline_guard, - &*query_set_guard, - ), + trackers: RenderBundleScope::new(), pipeline: None, bind: (0..hal::MAX_BIND_GROUPS).map(|_| None).collect(), vertex: (0..hal::MAX_VERTEX_BUFFERS).map(|_| None).collect(), index: None, flat_dynamic_offsets: Vec::new(), }; + + let indices = &device.tracker_indices; + state + .trackers + .buffers + .write() + .set_size(indices.buffers.size()); + state + .trackers + .textures + .write() + .set_size(indices.textures.size()); + state + .trackers + .bind_groups + .write() + .set_size(indices.bind_groups.size()); + state + .trackers + .render_pipelines + .write() + .set_size(indices.render_pipelines.size()); + state + .trackers + .query_sets + .write() + .set_size(indices.query_sets.size()); + let mut commands = Vec::new(); let mut buffer_memory_init_actions = Vec::new(); let mut texture_memory_init_actions = Vec::new(); @@ -399,7 +424,6 @@ impl RenderBundleEncoder { } // Identify the next `num_dynamic_offsets` entries from `base.dynamic_offsets`. - let num_dynamic_offsets = num_dynamic_offsets; let offsets_range = next_dynamic_offset..next_dynamic_offset + num_dynamic_offsets; next_dynamic_offset = offsets_range.end; @@ -471,7 +495,7 @@ impl RenderBundleEncoder { let pipeline_state = PipelineState::new(pipeline); - commands.push(command); + commands.push(ArcRenderCommand::SetPipeline(pipeline.clone())); // If this pipeline uses push constants, zero out their values. if let Some(iter) = pipeline_state.zero_push_constants() { @@ -496,7 +520,7 @@ impl RenderBundleEncoder { .map_pass_err(scope)?; self.check_valid_to_use(buffer.device.info.id()) .map_pass_err(scope)?; - check_buffer_usage(buffer.usage, wgt::BufferUsages::INDEX) + check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::INDEX) .map_pass_err(scope)?; let end = match size { @@ -508,7 +532,7 @@ impl RenderBundleEncoder { offset..end, MemoryInitKind::NeedsInitializedMemory, )); - state.set_index_buffer(buffer_id, index_format, offset..end); + state.set_index_buffer(buffer.clone(), index_format, offset..end); } RenderCommand::SetVertexBuffer { slot, @@ -535,7 +559,7 @@ impl RenderBundleEncoder { .map_pass_err(scope)?; self.check_valid_to_use(buffer.device.info.id()) .map_pass_err(scope)?; - check_buffer_usage(buffer.usage, wgt::BufferUsages::VERTEX) + check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::VERTEX) .map_pass_err(scope)?; let end = match size { @@ -547,13 +571,13 @@ impl RenderBundleEncoder { offset..end, MemoryInitKind::NeedsInitializedMemory, )); - state.vertex[slot as usize] = Some(VertexState::new(buffer_id, offset..end)); + state.vertex[slot as usize] = Some(VertexState::new(buffer.clone(), offset..end)); } RenderCommand::SetPushConstant { stages, offset, size_bytes, - values_offset: _, + values_offset, } => { let scope = PassErrorScope::SetPushConstant; let end_offset = offset + size_bytes; @@ -564,7 +588,7 @@ impl RenderBundleEncoder { .validate_push_constant_ranges(stages, offset, end_offset) .map_pass_err(scope)?; - commands.push(command); + commands.push(ArcRenderCommand::SetPushConstant { stages, offset, size_bytes, values_offset }); } RenderCommand::Draw { vertex_count, @@ -592,14 +616,19 @@ impl RenderBundleEncoder { if instance_count > 0 && vertex_count > 0 { commands.extend(state.flush_vertices()); commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); - commands.push(command); + commands.push(ArcRenderCommand::Draw { + vertex_count, + instance_count, + first_vertex, + first_instance, + }); } } RenderCommand::DrawIndexed { index_count, instance_count, first_index, - base_vertex: _, + base_vertex, first_instance, } => { let scope = PassErrorScope::Draw { @@ -628,7 +657,7 @@ impl RenderBundleEncoder { commands.extend(state.flush_index()); commands.extend(state.flush_vertices()); commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); - commands.push(command); + commands.push(ArcRenderCommand::DrawIndexed { index_count, instance_count, first_index, base_vertex, first_instance }); } } RenderCommand::MultiDrawIndirect { @@ -657,7 +686,7 @@ impl RenderBundleEncoder { .map_pass_err(scope)?; self.check_valid_to_use(buffer.device.info.id()) .map_pass_err(scope)?; - check_buffer_usage(buffer.usage, wgt::BufferUsages::INDIRECT) + check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::INDIRECT) .map_pass_err(scope)?; buffer_memory_init_actions.extend(buffer.initialization_status.read().create_action( @@ -668,7 +697,7 @@ impl RenderBundleEncoder { commands.extend(state.flush_vertices()); commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); - commands.push(command); + commands.push(ArcRenderCommand::MultiDrawIndirect { buffer: buffer.clone(), offset, count: None, indexed: false }); } RenderCommand::MultiDrawIndirect { buffer_id, @@ -696,7 +725,7 @@ impl RenderBundleEncoder { .map_pass_err(scope)?; self.check_valid_to_use(buffer.device.info.id()) .map_pass_err(scope)?; - check_buffer_usage(buffer.usage, wgt::BufferUsages::INDIRECT) + check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::INDIRECT) .map_pass_err(scope)?; buffer_memory_init_actions.extend(buffer.initialization_status.read().create_action( @@ -713,7 +742,7 @@ impl RenderBundleEncoder { commands.extend(index.flush()); commands.extend(state.flush_vertices()); commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets)); - commands.push(command); + commands.push(ArcRenderCommand::MultiDrawIndirect { buffer: buffer.clone(), offset, count: None, indexed: true }); } RenderCommand::MultiDrawIndirect { .. } | RenderCommand::MultiDrawIndirectCount { .. } => unimplemented!(), @@ -748,7 +777,10 @@ impl RenderBundleEncoder { buffer_memory_init_actions, texture_memory_init_actions, context: self.context, - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(device.tracker_indices.bundles.clone()), + ), discard_hal_labels: device .instance_flags .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS), @@ -824,7 +856,7 @@ pub type RenderBundleDescriptor<'a> = wgt::RenderBundleDescriptor<Label<'a>>; pub struct RenderBundle<A: HalApi> { // Normalized command stream. It can be executed verbatim, // without re-binding anything on the pipeline change. - base: BasePass<RenderCommand>, + base: BasePass<ArcRenderCommand<A>>, pub(super) is_depth_read_only: bool, pub(super) is_stencil_read_only: bool, pub(crate) device: Arc<Device<A>>, @@ -863,7 +895,6 @@ impl<A: HalApi> RenderBundle<A> { /// All the validation has already been done by this point. /// The only failure condition is if some of the used buffers are destroyed. pub(super) unsafe fn execute(&self, raw: &mut A::CommandEncoder) -> Result<(), ExecutionError> { - let trackers = &self.used; let mut offsets = self.base.dynamic_offsets.as_slice(); let mut pipeline_layout = None::<Arc<PipelineLayout<A>>>; if !self.discard_hal_labels { @@ -874,74 +905,65 @@ impl<A: HalApi> RenderBundle<A> { let snatch_guard = self.device.snatchable_lock.read(); + use ArcRenderCommand as Cmd; for command in self.base.commands.iter() { - match *command { - RenderCommand::SetBindGroup { + match command { + Cmd::SetBindGroup { index, num_dynamic_offsets, - bind_group_id, + bind_group, } => { - let bind_groups = trackers.bind_groups.read(); - let bind_group = bind_groups.get(bind_group_id).unwrap(); let raw_bg = bind_group .raw(&snatch_guard) - .ok_or(ExecutionError::InvalidBindGroup(bind_group_id))?; + .ok_or(ExecutionError::InvalidBindGroup(bind_group.info.id()))?; unsafe { raw.set_bind_group( pipeline_layout.as_ref().unwrap().raw(), - index, + *index, raw_bg, - &offsets[..num_dynamic_offsets], + &offsets[..*num_dynamic_offsets], ) }; - offsets = &offsets[num_dynamic_offsets..]; + offsets = &offsets[*num_dynamic_offsets..]; } - RenderCommand::SetPipeline(pipeline_id) => { - let render_pipelines = trackers.render_pipelines.read(); - let pipeline = render_pipelines.get(pipeline_id).unwrap(); + Cmd::SetPipeline(pipeline) => { unsafe { raw.set_render_pipeline(pipeline.raw()) }; pipeline_layout = Some(pipeline.layout.clone()); } - RenderCommand::SetIndexBuffer { - buffer_id, + Cmd::SetIndexBuffer { + buffer, index_format, offset, size, } => { - let buffers = trackers.buffers.read(); - let buffer: &A::Buffer = buffers - .get(buffer_id) - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))? + let buffer: &A::Buffer = buffer .raw(&snatch_guard) - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; + .ok_or(ExecutionError::DestroyedBuffer(buffer.info.id()))?; let bb = hal::BufferBinding { buffer, - offset, - size, + offset: *offset, + size: *size, }; - unsafe { raw.set_index_buffer(bb, index_format) }; + unsafe { raw.set_index_buffer(bb, *index_format) }; } - RenderCommand::SetVertexBuffer { + Cmd::SetVertexBuffer { slot, - buffer_id, + buffer, offset, size, } => { - let buffers = trackers.buffers.read(); - let buffer = buffers - .get(buffer_id) - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))? + let buffer = buffer .raw(&snatch_guard) - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; + .ok_or(ExecutionError::DestroyedBuffer(buffer.info.id()))?; let bb = hal::BufferBinding { buffer, - offset, - size, + offset: *offset, + size: *size, }; - unsafe { raw.set_vertex_buffer(slot, bb) }; + unsafe { raw.set_vertex_buffer(*slot, bb) }; } - RenderCommand::SetPushConstant { + Cmd::SetPushConstant { stages, offset, size_bytes, @@ -949,7 +971,7 @@ impl<A: HalApi> RenderBundle<A> { } => { let pipeline_layout = pipeline_layout.as_ref().unwrap(); - if let Some(values_offset) = values_offset { + if let Some(values_offset) = *values_offset { let values_end_offset = (values_offset + size_bytes / wgt::PUSH_CONSTANT_ALIGNMENT) as usize; let data_slice = &self.base.push_constant_data @@ -958,20 +980,20 @@ impl<A: HalApi> RenderBundle<A> { unsafe { raw.set_push_constants( pipeline_layout.raw(), - stages, - offset, + *stages, + *offset, data_slice, ) } } else { super::push_constant_clear( - offset, - size_bytes, + *offset, + *size_bytes, |clear_offset, clear_data| { unsafe { raw.set_push_constants( pipeline_layout.raw(), - stages, + *stages, clear_offset, clear_data, ) @@ -980,15 +1002,22 @@ impl<A: HalApi> RenderBundle<A> { ); } } - RenderCommand::Draw { + Cmd::Draw { vertex_count, instance_count, first_vertex, first_instance, } => { - unsafe { raw.draw(first_vertex, vertex_count, first_instance, instance_count) }; + unsafe { + raw.draw( + *first_vertex, + *vertex_count, + *first_instance, + *instance_count, + ) + }; } - RenderCommand::DrawIndexed { + Cmd::DrawIndexed { index_count, instance_count, first_index, @@ -997,63 +1026,54 @@ impl<A: HalApi> RenderBundle<A> { } => { unsafe { raw.draw_indexed( - first_index, - index_count, - base_vertex, - first_instance, - instance_count, + *first_index, + *index_count, + *base_vertex, + *first_instance, + *instance_count, ) }; } - RenderCommand::MultiDrawIndirect { - buffer_id, + Cmd::MultiDrawIndirect { + buffer, offset, count: None, indexed: false, } => { - let buffers = trackers.buffers.read(); - let buffer = buffers - .get(buffer_id) - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))? + let buffer = buffer .raw(&snatch_guard) - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; - unsafe { raw.draw_indirect(buffer, offset, 1) }; + .ok_or(ExecutionError::DestroyedBuffer(buffer.info.id()))?; + unsafe { raw.draw_indirect(buffer, *offset, 1) }; } - RenderCommand::MultiDrawIndirect { - buffer_id, + Cmd::MultiDrawIndirect { + buffer, offset, count: None, indexed: true, } => { - let buffers = trackers.buffers.read(); - let buffer = buffers - .get(buffer_id) - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))? + let buffer = buffer .raw(&snatch_guard) - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; - unsafe { raw.draw_indexed_indirect(buffer, offset, 1) }; + .ok_or(ExecutionError::DestroyedBuffer(buffer.info.id()))?; + unsafe { raw.draw_indexed_indirect(buffer, *offset, 1) }; } - RenderCommand::MultiDrawIndirect { .. } - | RenderCommand::MultiDrawIndirectCount { .. } => { + Cmd::MultiDrawIndirect { .. } | Cmd::MultiDrawIndirectCount { .. } => { return Err(ExecutionError::Unimplemented("multi-draw-indirect")) } - RenderCommand::PushDebugGroup { .. } - | RenderCommand::InsertDebugMarker { .. } - | RenderCommand::PopDebugGroup => { + Cmd::PushDebugGroup { .. } | Cmd::InsertDebugMarker { .. } | Cmd::PopDebugGroup => { return Err(ExecutionError::Unimplemented("debug-markers")) } - RenderCommand::WriteTimestamp { .. } - | RenderCommand::BeginOcclusionQuery { .. } - | RenderCommand::EndOcclusionQuery - | RenderCommand::BeginPipelineStatisticsQuery { .. } - | RenderCommand::EndPipelineStatisticsQuery => { + Cmd::WriteTimestamp { .. } + | Cmd::BeginOcclusionQuery { .. } + | Cmd::EndOcclusionQuery + | Cmd::BeginPipelineStatisticsQuery { .. } + | Cmd::EndPipelineStatisticsQuery => { return Err(ExecutionError::Unimplemented("queries")) } - RenderCommand::ExecuteBundle(_) - | RenderCommand::SetBlendConstant(_) - | RenderCommand::SetStencilReference(_) - | RenderCommand::SetViewport { .. } - | RenderCommand::SetScissor(_) => unreachable!(), + Cmd::ExecuteBundle(_) + | Cmd::SetBlendConstant(_) + | Cmd::SetStencilReference(_) + | Cmd::SetViewport { .. } + | Cmd::SetScissor(_) => unreachable!(), } } @@ -1087,14 +1107,14 @@ impl<A: HalApi> Resource for RenderBundle<A> { /// and calls [`State::flush_index`] before any indexed draw command to produce /// a `SetIndexBuffer` command if one is necessary. #[derive(Debug)] -struct IndexState { - buffer: id::BufferId, +struct IndexState<A: HalApi> { + buffer: Arc<Buffer<A>>, format: wgt::IndexFormat, range: Range<wgt::BufferAddress>, is_dirty: bool, } -impl IndexState { +impl<A: HalApi> IndexState<A> { /// Return the number of entries in the current index buffer. /// /// Panic if no index buffer has been set. @@ -1109,11 +1129,11 @@ impl IndexState { /// Generate a `SetIndexBuffer` command to prepare for an indexed draw /// command, if needed. - fn flush(&mut self) -> Option<RenderCommand> { + fn flush(&mut self) -> Option<ArcRenderCommand<A>> { if self.is_dirty { self.is_dirty = false; - Some(RenderCommand::SetIndexBuffer { - buffer_id: self.buffer, + Some(ArcRenderCommand::SetIndexBuffer { + buffer: self.buffer.clone(), index_format: self.format, offset: self.range.start, size: wgt::BufferSize::new(self.range.end - self.range.start), @@ -1134,14 +1154,14 @@ impl IndexState { /// /// [`flush`]: IndexState::flush #[derive(Debug)] -struct VertexState { - buffer: id::BufferId, +struct VertexState<A: HalApi> { + buffer: Arc<Buffer<A>>, range: Range<wgt::BufferAddress>, is_dirty: bool, } -impl VertexState { - fn new(buffer: id::BufferId, range: Range<wgt::BufferAddress>) -> Self { +impl<A: HalApi> VertexState<A> { + fn new(buffer: Arc<Buffer<A>>, range: Range<wgt::BufferAddress>) -> Self { Self { buffer, range, @@ -1152,12 +1172,12 @@ impl VertexState { /// Generate a `SetVertexBuffer` command for this slot, if necessary. /// /// `slot` is the index of the vertex buffer slot that `self` tracks. - fn flush(&mut self, slot: u32) -> Option<RenderCommand> { + fn flush(&mut self, slot: u32) -> Option<ArcRenderCommand<A>> { if self.is_dirty { self.is_dirty = false; - Some(RenderCommand::SetVertexBuffer { + Some(ArcRenderCommand::SetVertexBuffer { slot, - buffer_id: self.buffer, + buffer: self.buffer.clone(), offset: self.range.start, size: wgt::BufferSize::new(self.range.end - self.range.start), }) @@ -1219,7 +1239,7 @@ impl<A: HalApi> PipelineState<A> { /// Return a sequence of commands to zero the push constant ranges this /// pipeline uses. If no initialization is necessary, return `None`. - fn zero_push_constants(&self) -> Option<impl Iterator<Item = RenderCommand>> { + fn zero_push_constants(&self) -> Option<impl Iterator<Item = ArcRenderCommand<A>>> { if !self.push_constant_ranges.is_empty() { let nonoverlapping_ranges = super::bind::compute_nonoverlapping_ranges(&self.push_constant_ranges); @@ -1227,7 +1247,7 @@ impl<A: HalApi> PipelineState<A> { Some( nonoverlapping_ranges .into_iter() - .map(|range| RenderCommand::SetPushConstant { + .map(|range| ArcRenderCommand::SetPushConstant { stages: range.stages, offset: range.range.start, size_bytes: range.range.end - range.range.start, @@ -1261,11 +1281,11 @@ struct State<A: HalApi> { bind: ArrayVec<Option<BindState<A>>, { hal::MAX_BIND_GROUPS }>, /// The state of each vertex buffer slot. - vertex: ArrayVec<Option<VertexState>, { hal::MAX_VERTEX_BUFFERS }>, + vertex: ArrayVec<Option<VertexState<A>>, { hal::MAX_VERTEX_BUFFERS }>, /// The current index buffer, if one has been set. We flush this state /// before indexed draw commands. - index: Option<IndexState>, + index: Option<IndexState<A>>, /// Dynamic offset values used by the cleaned-up command sequence. /// @@ -1375,13 +1395,13 @@ impl<A: HalApi> State<A> { /// Set the bundle's current index buffer and its associated parameters. fn set_index_buffer( &mut self, - buffer: id::BufferId, + buffer: Arc<Buffer<A>>, format: wgt::IndexFormat, range: Range<wgt::BufferAddress>, ) { match self.index { Some(ref current) - if current.buffer == buffer + if Arc::ptr_eq(¤t.buffer, &buffer) && current.format == format && current.range == range => { @@ -1400,11 +1420,11 @@ impl<A: HalApi> State<A> { /// Generate a `SetIndexBuffer` command to prepare for an indexed draw /// command, if needed. - fn flush_index(&mut self) -> Option<RenderCommand> { + fn flush_index(&mut self) -> Option<ArcRenderCommand<A>> { self.index.as_mut().and_then(|index| index.flush()) } - fn flush_vertices(&mut self) -> impl Iterator<Item = RenderCommand> + '_ { + fn flush_vertices(&mut self) -> impl Iterator<Item = ArcRenderCommand<A>> + '_ { self.vertex .iter_mut() .enumerate() @@ -1416,7 +1436,7 @@ impl<A: HalApi> State<A> { &mut self, used_bind_groups: usize, dynamic_offsets: &[wgt::DynamicOffset], - ) -> impl Iterator<Item = RenderCommand> + '_ { + ) -> impl Iterator<Item = ArcRenderCommand<A>> + '_ { // Append each dirty bind group's dynamic offsets to `flat_dynamic_offsets`. for contents in self.bind[..used_bind_groups].iter().flatten() { if contents.is_dirty { @@ -1435,9 +1455,9 @@ impl<A: HalApi> State<A> { if contents.is_dirty { contents.is_dirty = false; let offsets = &contents.dynamic_offsets; - return Some(RenderCommand::SetBindGroup { + return Some(ArcRenderCommand::SetBindGroup { index: i.try_into().unwrap(), - bind_group_id: contents.bind_group.as_info().id(), + bind_group: contents.bind_group.clone(), num_dynamic_offsets: offsets.end - offsets.start, }); } diff --git a/third_party/rust/wgpu-core/src/command/clear.rs b/third_party/rust/wgpu-core/src/command/clear.rs index 2569fea1a4..e404fabb14 100644 --- a/third_party/rust/wgpu-core/src/command/clear.rs +++ b/third_party/rust/wgpu-core/src/command/clear.rs @@ -39,6 +39,11 @@ pub enum ClearError { UnalignedFillSize(BufferAddress), #[error("Buffer offset {0:?} is not a multiple of `COPY_BUFFER_ALIGNMENT`")] UnalignedBufferOffset(BufferAddress), + #[error("Clear starts at offset {start_offset} with size of {requested_size}, but these added together exceed `u64::MAX`")] + OffsetPlusSizeExceeds64BitBounds { + start_offset: BufferAddress, + requested_size: BufferAddress, + }, #[error("Clear of {start_offset}..{end_offset} would end up overrunning the bounds of the buffer of size {buffer_size}")] BufferOverrun { start_offset: BufferAddress, @@ -117,25 +122,27 @@ impl Global { if offset % wgt::COPY_BUFFER_ALIGNMENT != 0 { return Err(ClearError::UnalignedBufferOffset(offset)); } - if let Some(size) = size { - if size % wgt::COPY_BUFFER_ALIGNMENT != 0 { - return Err(ClearError::UnalignedFillSize(size)); - } - let destination_end_offset = offset + size; - if destination_end_offset > dst_buffer.size { - return Err(ClearError::BufferOverrun { + + let size = size.unwrap_or(dst_buffer.size.saturating_sub(offset)); + if size % wgt::COPY_BUFFER_ALIGNMENT != 0 { + return Err(ClearError::UnalignedFillSize(size)); + } + let end_offset = + offset + .checked_add(size) + .ok_or(ClearError::OffsetPlusSizeExceeds64BitBounds { start_offset: offset, - end_offset: destination_end_offset, - buffer_size: dst_buffer.size, - }); - } + requested_size: size, + })?; + if end_offset > dst_buffer.size { + return Err(ClearError::BufferOverrun { + start_offset: offset, + end_offset, + buffer_size: dst_buffer.size, + }); } - let end = match size { - Some(size) => offset + size, - None => dst_buffer.size, - }; - if offset == end { + if offset == end_offset { log::trace!("Ignoring fill_buffer of size 0"); return Ok(()); } @@ -144,7 +151,7 @@ impl Global { cmd_buf_data.buffer_memory_init_actions.extend( dst_buffer.initialization_status.read().create_action( &dst_buffer, - offset..end, + offset..end_offset, MemoryInitKind::ImplicitlyInitialized, ), ); @@ -154,7 +161,7 @@ impl Global { let cmd_buf_raw = cmd_buf_data.encoder.open()?; unsafe { cmd_buf_raw.transition_buffers(dst_barrier.into_iter()); - cmd_buf_raw.clear_buffer(dst_raw, offset..end); + cmd_buf_raw.clear_buffer(dst_raw, offset..end_offset); } Ok(()) } @@ -366,7 +373,7 @@ fn clear_texture_via_buffer_copies<A: HalApi>( assert!( max_rows_per_copy > 0, "Zero buffer size is too small to fill a single row \ - of a texture with format {:?} and desc {:?}", + of a texture with format {:?} and desc {:?}", texture_desc.format, texture_desc.size ); diff --git a/third_party/rust/wgpu-core/src/command/compute.rs b/third_party/rust/wgpu-core/src/command/compute.rs index 804186a01e..c2fd3ab397 100644 --- a/third_party/rust/wgpu-core/src/command/compute.rs +++ b/third_party/rust/wgpu-core/src/command/compute.rs @@ -1,6 +1,7 @@ use crate::device::DeviceError; use crate::resource::Resource; use crate::snatch::SnatchGuard; +use crate::track::TrackerIndex; use crate::{ binding_model::{ BindError, BindGroup, LateMinBufferBindingSizeMismatch, PushConstantUploadError, @@ -305,7 +306,7 @@ impl<A: HalApi> State<A> { raw_encoder: &mut A::CommandEncoder, base_trackers: &mut Tracker<A>, bind_group_guard: &Storage<BindGroup<A>>, - indirect_buffer: Option<id::BufferId>, + indirect_buffer: Option<TrackerIndex>, snatch_guard: &SnatchGuard, ) -> Result<(), UsageConflict> { for id in self.binder.list_active() { @@ -402,12 +403,11 @@ impl Global { let pipeline_guard = hub.compute_pipelines.read(); let query_set_guard = hub.query_sets.read(); let buffer_guard = hub.buffers.read(); - let texture_guard = hub.textures.read(); let mut state = State { binder: Binder::new(), pipeline: None, - scope: UsageScope::new(&*buffer_guard, &*texture_guard), + scope: UsageScope::new(&device.tracker_indices), debug_scope_depth: 0, }; let mut temp_offsets = Vec::new(); @@ -452,17 +452,14 @@ impl Global { let snatch_guard = device.snatchable_lock.read(); - tracker.set_size( - Some(&*buffer_guard), - Some(&*texture_guard), - None, - None, - Some(&*bind_group_guard), - Some(&*pipeline_guard), - None, - None, - Some(&*query_set_guard), - ); + let indices = &device.tracker_indices; + tracker.buffers.set_size(indices.buffers.size()); + tracker.textures.set_size(indices.textures.size()); + tracker.bind_groups.set_size(indices.bind_groups.size()); + tracker + .compute_pipelines + .set_size(indices.compute_pipelines.size()); + tracker.query_sets.set_size(indices.query_sets.size()); let discard_hal_labels = self .instance @@ -719,8 +716,12 @@ impl Global { .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) .map_pass_err(scope)?; - check_buffer_usage(indirect_buffer.usage, wgt::BufferUsages::INDIRECT) - .map_pass_err(scope)?; + check_buffer_usage( + buffer_id, + indirect_buffer.usage, + wgt::BufferUsages::INDIRECT, + ) + .map_pass_err(scope)?; let end_offset = offset + mem::size_of::<wgt::DispatchIndirectArgs>() as u64; if end_offset > indirect_buffer.size { @@ -753,7 +754,7 @@ impl Global { raw, &mut intermediate_trackers, &*bind_group_guard, - Some(buffer_id), + Some(indirect_buffer.as_info().tracker_index()), &snatch_guard, ) .map_pass_err(scope)?; diff --git a/third_party/rust/wgpu-core/src/command/draw.rs b/third_party/rust/wgpu-core/src/command/draw.rs index e03a78ee93..98aa689b78 100644 --- a/third_party/rust/wgpu-core/src/command/draw.rs +++ b/third_party/rust/wgpu-core/src/command/draw.rs @@ -2,17 +2,22 @@ !*/ use crate::{ - binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError}, + binding_model::{BindGroup, LateMinBufferBindingSizeMismatch, PushConstantUploadError}, error::ErrorFormatter, + hal_api::HalApi, id, + pipeline::RenderPipeline, + resource::{Buffer, QuerySet}, track::UsageConflict, validation::{MissingBufferUsageError, MissingTextureUsageError}, }; use wgt::{BufferAddress, BufferSize, Color, VertexStepMode}; -use std::num::NonZeroU32; +use std::{num::NonZeroU32, sync::Arc}; use thiserror::Error; +use super::RenderBundle; + /// Error validating a draw call. #[derive(Clone, Debug, Error, Eq, PartialEq)] #[non_exhaustive] @@ -245,3 +250,114 @@ pub enum RenderCommand { EndPipelineStatisticsQuery, ExecuteBundle(id::RenderBundleId), } + +/// Equivalent to `RenderCommand` with the Ids resolved into resource Arcs. +#[doc(hidden)] +#[derive(Clone, Debug)] +pub enum ArcRenderCommand<A: HalApi> { + SetBindGroup { + index: u32, + num_dynamic_offsets: usize, + bind_group: Arc<BindGroup<A>>, + }, + SetPipeline(Arc<RenderPipeline<A>>), + SetIndexBuffer { + buffer: Arc<Buffer<A>>, + index_format: wgt::IndexFormat, + offset: BufferAddress, + size: Option<BufferSize>, + }, + SetVertexBuffer { + slot: u32, + buffer: Arc<Buffer<A>>, + offset: BufferAddress, + size: Option<BufferSize>, + }, + SetBlendConstant(Color), + SetStencilReference(u32), + SetViewport { + rect: Rect<f32>, + depth_min: f32, + depth_max: f32, + }, + SetScissor(Rect<u32>), + + /// Set a range of push constants to values stored in [`BasePass::push_constant_data`]. + /// + /// See [`wgpu::RenderPass::set_push_constants`] for a detailed explanation + /// of the restrictions these commands must satisfy. + SetPushConstant { + /// Which stages we are setting push constant values for. + stages: wgt::ShaderStages, + + /// The byte offset within the push constant storage to write to. This + /// must be a multiple of four. + offset: u32, + + /// The number of bytes to write. This must be a multiple of four. + size_bytes: u32, + + /// Index in [`BasePass::push_constant_data`] of the start of the data + /// to be written. + /// + /// Note: this is not a byte offset like `offset`. Rather, it is the + /// index of the first `u32` element in `push_constant_data` to read. + /// + /// `None` means zeros should be written to the destination range, and + /// there is no corresponding data in `push_constant_data`. This is used + /// by render bundles, which explicitly clear out any state that + /// post-bundle code might see. + values_offset: Option<u32>, + }, + Draw { + vertex_count: u32, + instance_count: u32, + first_vertex: u32, + first_instance: u32, + }, + DrawIndexed { + index_count: u32, + instance_count: u32, + first_index: u32, + base_vertex: i32, + first_instance: u32, + }, + MultiDrawIndirect { + buffer: Arc<Buffer<A>>, + offset: BufferAddress, + /// Count of `None` represents a non-multi call. + count: Option<NonZeroU32>, + indexed: bool, + }, + MultiDrawIndirectCount { + buffer: Arc<Buffer<A>>, + offset: BufferAddress, + count_buffer: Arc<Buffer<A>>, + count_buffer_offset: BufferAddress, + max_count: u32, + indexed: bool, + }, + PushDebugGroup { + color: u32, + len: usize, + }, + PopDebugGroup, + InsertDebugMarker { + color: u32, + len: usize, + }, + WriteTimestamp { + query_set: Arc<QuerySet<A>>, + query_index: u32, + }, + BeginOcclusionQuery { + query_index: u32, + }, + EndOcclusionQuery, + BeginPipelineStatisticsQuery { + query_set: Arc<QuerySet<A>>, + query_index: u32, + }, + EndPipelineStatisticsQuery, + ExecuteBundle(Arc<RenderBundle<A>>), +} diff --git a/third_party/rust/wgpu-core/src/command/mod.rs b/third_party/rust/wgpu-core/src/command/mod.rs index 2d5fca200a..febed4fc97 100644 --- a/third_party/rust/wgpu-core/src/command/mod.rs +++ b/third_party/rust/wgpu-core/src/command/mod.rs @@ -75,7 +75,7 @@ impl<A: HalApi> CommandEncoder<A> { Ok(()) } - fn discard(&mut self) { + pub(crate) fn discard(&mut self) { if self.is_open { self.is_open = false; unsafe { self.raw.discard_encoding() }; @@ -112,7 +112,7 @@ pub(crate) struct DestroyedBufferError(pub id::BufferId); pub(crate) struct DestroyedTextureError(pub id::TextureId); pub struct CommandBufferMutable<A: HalApi> { - encoder: CommandEncoder<A>, + pub(crate) encoder: CommandEncoder<A>, status: CommandEncoderStatus, pub(crate) trackers: Tracker<A>, buffer_memory_init_actions: Vec<BufferInitTrackerAction<A>>, @@ -174,6 +174,7 @@ impl<A: HalApi> CommandBuffer<A> { .as_ref() .unwrap_or(&String::from("<CommandBuffer>")) .as_str(), + None, ), data: Mutex::new(Some(CommandBufferMutable { encoder: CommandEncoder { diff --git a/third_party/rust/wgpu-core/src/command/query.rs b/third_party/rust/wgpu-core/src/command/query.rs index 39d7a9cc93..89cba6fbf3 100644 --- a/third_party/rust/wgpu-core/src/command/query.rs +++ b/third_party/rust/wgpu-core/src/command/query.rs @@ -4,7 +4,7 @@ use hal::CommandEncoder as _; use crate::device::trace::Command as TraceCommand; use crate::{ command::{CommandBuffer, CommandEncoderError}, - device::DeviceError, + device::{DeviceError, MissingFeatures}, global::Global, hal_api::HalApi, id::{self, Id}, @@ -108,6 +108,8 @@ pub enum QueryError { Device(#[from] DeviceError), #[error(transparent)] Encoder(#[from] CommandEncoderError), + #[error(transparent)] + MissingFeature(#[from] MissingFeatures), #[error("Error encountered while trying to use queries")] Use(#[from] QueryUseError), #[error("Error encountered while trying to resolve a query")] @@ -355,6 +357,11 @@ impl Global { let hub = A::hub(self); let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + + cmd_buf + .device + .require_features(wgt::Features::TIMESTAMP_QUERY_INSIDE_ENCODERS)?; + let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); diff --git a/third_party/rust/wgpu-core/src/command/render.rs b/third_party/rust/wgpu-core/src/command/render.rs index d3de3e26e1..9141ddb021 100644 --- a/third_party/rust/wgpu-core/src/command/render.rs +++ b/third_party/rust/wgpu-core/src/command/render.rs @@ -22,7 +22,7 @@ use crate::{ hal_label, id, init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction}, pipeline::{self, PipelineFlags}, - resource::{Buffer, QuerySet, Texture, TextureView, TextureViewNotRenderableReason}, + resource::{QuerySet, Texture, TextureView, TextureViewNotRenderableReason}, storage::Storage, track::{TextureSelector, Tracker, UsageConflict, UsageScope}, validation::{ @@ -531,6 +531,8 @@ pub enum ColorAttachmentError { InvalidFormat(wgt::TextureFormat), #[error("The number of color attachments {given} exceeds the limit {limit}")] TooMany { given: usize, limit: usize }, + #[error("The total number of bytes per sample in color attachments {total} exceeds the limit {limit}")] + TooManyBytesPerSample { total: u32, limit: u32 }, } /// Error encountered when performing a render pass. @@ -799,8 +801,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { texture_memory_actions: &mut CommandBufferTextureMemoryActions<A>, pending_query_resets: &mut QueryResetMap<A>, view_guard: &'a Storage<TextureView<A>>, - buffer_guard: &'a Storage<Buffer<A>>, - texture_guard: &'a Storage<Texture<A>>, query_set_guard: &'a Storage<QuerySet<A>>, snatch_guard: &SnatchGuard<'a>, ) -> Result<Self, RenderPassErrorInner> { @@ -1214,7 +1214,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { Ok(Self { context, - usage_scope: UsageScope::new(buffer_guard, texture_guard), + usage_scope: UsageScope::new(&device.tracker_indices), render_attachments, is_depth_read_only, is_stencil_read_only, @@ -1386,7 +1386,6 @@ impl Global { let render_pipeline_guard = hub.render_pipelines.read(); let query_set_guard = hub.query_sets.read(); let buffer_guard = hub.buffers.read(); - let texture_guard = hub.textures.read(); let view_guard = hub.texture_views.read(); log::trace!( @@ -1406,24 +1405,21 @@ impl Global { texture_memory_actions, pending_query_resets, &*view_guard, - &*buffer_guard, - &*texture_guard, &*query_set_guard, &snatch_guard, ) .map_pass_err(pass_scope)?; - tracker.set_size( - Some(&*buffer_guard), - Some(&*texture_guard), - Some(&*view_guard), - None, - Some(&*bind_group_guard), - None, - Some(&*render_pipeline_guard), - Some(&*bundle_guard), - Some(&*query_set_guard), - ); + let indices = &device.tracker_indices; + tracker.buffers.set_size(indices.buffers.size()); + tracker.textures.set_size(indices.textures.size()); + tracker.views.set_size(indices.texture_views.size()); + tracker.bind_groups.set_size(indices.bind_groups.size()); + tracker + .render_pipelines + .set_size(indices.render_pipelines.size()); + tracker.bundles.set_size(indices.bundles.size()); + tracker.query_sets.set_size(indices.query_sets.size()); let raw = &mut encoder.raw; @@ -1675,7 +1671,7 @@ impl Global { return Err(DeviceError::WrongDevice).map_pass_err(scope); } - check_buffer_usage(buffer.usage, BufferUsages::INDEX) + check_buffer_usage(buffer_id, buffer.usage, BufferUsages::INDEX) .map_pass_err(scope)?; let buf_raw = buffer .raw @@ -1737,7 +1733,7 @@ impl Global { .map_pass_err(scope); } - check_buffer_usage(buffer.usage, BufferUsages::VERTEX) + check_buffer_usage(buffer_id, buffer.usage, BufferUsages::VERTEX) .map_pass_err(scope)?; let buf_raw = buffer .raw @@ -2034,8 +2030,12 @@ impl Global { .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) .map_pass_err(scope)?; - check_buffer_usage(indirect_buffer.usage, BufferUsages::INDIRECT) - .map_pass_err(scope)?; + check_buffer_usage( + buffer_id, + indirect_buffer.usage, + BufferUsages::INDIRECT, + ) + .map_pass_err(scope)?; let indirect_raw = indirect_buffer .raw .get(&snatch_guard) @@ -2106,8 +2106,12 @@ impl Global { .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) .map_pass_err(scope)?; - check_buffer_usage(indirect_buffer.usage, BufferUsages::INDIRECT) - .map_pass_err(scope)?; + check_buffer_usage( + buffer_id, + indirect_buffer.usage, + BufferUsages::INDIRECT, + ) + .map_pass_err(scope)?; let indirect_raw = indirect_buffer .raw .get(&snatch_guard) @@ -2123,7 +2127,7 @@ impl Global { hal::BufferUses::INDIRECT, ) .map_pass_err(scope)?; - check_buffer_usage(count_buffer.usage, BufferUsages::INDIRECT) + check_buffer_usage(buffer_id, count_buffer.usage, BufferUsages::INDIRECT) .map_pass_err(scope)?; let count_raw = count_buffer .raw |