diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 725eeaa43b..0133993922 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -79,7 +79,7 @@ index format changes. #![allow(clippy::reversed_empty_ranges)] use crate::{ - binding_model::{BindError, BindGroup, BindGroupLayout, PipelineLayout}, + binding_model::{BindError, BindGroup, PipelineLayout}, command::{ BasePass, BindGroupStateChange, ColorAttachmentError, DrawError, MapPassErr, PassErrorScope, RenderCommandError, StateChange, @@ -347,7 +347,7 @@ impl RenderBundleEncoder { desc: &RenderBundleDescriptor, device: &Arc>, hub: &Hub, - ) -> Result, RenderBundleError> { + ) -> Result>, RenderBundleError> { let scope = PassErrorScope::Bundle; device.check_is_valid().map_pass_err(scope)?; @@ -562,7 +562,7 @@ impl RenderBundleEncoder { .instance_flags .contains(wgt::InstanceFlags::DISCARD_HAL_LABELS); - Ok(RenderBundle { + let render_bundle = RenderBundle { base: BasePass { label: desc.label.as_ref().map(|cow| cow.to_string()), commands, @@ -572,7 +572,7 @@ impl RenderBundleEncoder { }, is_depth_read_only: self.is_depth_read_only, is_stencil_read_only: self.is_stencil_read_only, - device, + device: device.clone(), used: trackers, buffer_memory_init_actions, texture_memory_init_actions, @@ -580,7 +580,17 @@ impl RenderBundleEncoder { label: desc.label.to_string(), tracking_data: TrackingData::new(tracker_indices), discard_hal_labels, - }) + }; + + let render_bundle = Arc::new(render_bundle); + + device + .trackers + .lock() + .bundles + .insert_single(render_bundle.clone()); + + Ok(render_bundle) } pub fn set_index_buffer( @@ -608,11 +618,9 @@ fn set_bind_group( bind_group_id: id::Id, ) -> Result<(), RenderBundleErrorInner> { let bind_group = bind_group_guard - .get(bind_group_id) + .get_owned(bind_group_id) .map_err(|_| RenderCommandError::InvalidBindGroupId(bind_group_id))?; - state.trackers.bind_groups.write().add_single(bind_group); - bind_group.same_device(&state.device)?; let max_bind_groups = state.device.limits.max_bind_groups; @@ -638,13 +646,9 @@ fn set_bind_group( .texture_memory_init_actions .extend_from_slice(&bind_group.used_texture_ranges); - state.set_bind_group( - index, - bind_group_guard.get(bind_group_id).as_ref().unwrap(), - &bind_group.layout, - offsets_range, - ); + state.set_bind_group(index, &bind_group, offsets_range); unsafe { state.trackers.merge_bind_group(&bind_group.used)? }; + state.trackers.bind_groups.write().insert_single(bind_group); // Note: stateless trackers are not merged: the lifetime reference // is held to the bind group itself. Ok(()) @@ -659,11 +663,9 @@ fn set_pipeline( pipeline_id: id::Id, ) -> Result<(), RenderBundleErrorInner> { let pipeline = pipeline_guard - .get(pipeline_id) + .get_owned(pipeline_id) .map_err(|_| RenderCommandError::InvalidPipelineId(pipeline_id))?; - state.trackers.render_pipelines.write().add_single(pipeline); - pipeline.same_device(&state.device)?; context @@ -677,7 +679,7 @@ fn set_pipeline( return Err(RenderCommandError::IncompatibleStencilAccess(pipeline.error_ident()).into()); } - let pipeline_state = PipelineState::new(pipeline); + let pipeline_state = PipelineState::new(&pipeline); state .commands @@ -690,6 +692,12 @@ fn set_pipeline( state.invalidate_bind_groups(&pipeline_state, &pipeline.layout); state.pipeline = Some(pipeline_state); + + state + .trackers + .render_pipelines + .write() + .insert_single(pipeline); Ok(()) } @@ -702,14 +710,14 @@ fn set_index_buffer( size: Option, ) -> Result<(), RenderBundleErrorInner> { let buffer = buffer_guard - .get(buffer_id) + .get_owned(buffer_id) .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id))?; state .trackers .buffers .write() - .merge_single(buffer, hal::BufferUses::INDEX)?; + .merge_single(&buffer, hal::BufferUses::INDEX)?; buffer.same_device(&state.device)?; buffer.check_usage(wgt::BufferUsages::INDEX)?; @@ -721,11 +729,11 @@ fn set_index_buffer( state .buffer_memory_init_actions .extend(buffer.initialization_status.read().create_action( - buffer, + &buffer, offset..end, MemoryInitKind::NeedsInitializedMemory, )); - state.set_index_buffer(buffer.clone(), index_format, offset..end); + state.set_index_buffer(buffer, index_format, offset..end); Ok(()) } @@ -747,14 +755,14 @@ fn set_vertex_buffer( } let buffer = buffer_guard - .get(buffer_id) + .get_owned(buffer_id) .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id))?; state .trackers .buffers .write() - .merge_single(buffer, hal::BufferUses::VERTEX)?; + .merge_single(&buffer, hal::BufferUses::VERTEX)?; buffer.same_device(&state.device)?; buffer.check_usage(wgt::BufferUsages::VERTEX)?; @@ -766,11 +774,11 @@ fn set_vertex_buffer( state .buffer_memory_init_actions .extend(buffer.initialization_status.read().create_action( - buffer, + &buffer, offset..end, MemoryInitKind::NeedsInitializedMemory, )); - state.vertex[slot as usize] = Some(VertexState::new(buffer.clone(), offset..end)); + state.vertex[slot as usize] = Some(VertexState::new(buffer, offset..end)); Ok(()) } @@ -889,14 +897,14 @@ fn multi_draw_indirect( let used_bind_groups = pipeline.used_bind_groups; let buffer = buffer_guard - .get(buffer_id) + .get_owned(buffer_id) .map_err(|_| RenderCommandError::InvalidBufferId(buffer_id))?; state .trackers .buffers .write() - .merge_single(buffer, hal::BufferUses::INDIRECT)?; + .merge_single(&buffer, hal::BufferUses::INDIRECT)?; buffer.same_device(&state.device)?; buffer.check_usage(wgt::BufferUsages::INDIRECT)?; @@ -904,7 +912,7 @@ fn multi_draw_indirect( state .buffer_memory_init_actions .extend(buffer.initialization_status.read().create_action( - buffer, + &buffer, offset..(offset + mem::size_of::() as u64), MemoryInitKind::NeedsInitializedMemory, )); @@ -920,7 +928,7 @@ fn multi_draw_indirect( state.flush_vertices(); state.flush_binds(used_bind_groups, dynamic_offsets); state.commands.push(ArcRenderCommand::MultiDrawIndirect { - buffer: buffer.clone(), + buffer, offset, count: None, indexed, @@ -1275,9 +1283,6 @@ struct BindState { /// The id of the bind group set at this index. bind_group: Arc>, - /// The layout of `group`. - layout: Arc>, - /// The range of dynamic offsets for this bind group, in the original /// command stream's `BassPass::dynamic_offsets` array. dynamic_offsets: Range, @@ -1403,7 +1408,6 @@ impl State { &mut self, slot: u32, bind_group: &Arc>, - layout: &Arc>, dynamic_offsets: Range, ) { // If this call wouldn't actually change this index's state, we can @@ -1420,7 +1424,6 @@ impl State { // Record the index's new state. self.bind[slot as usize] = Some(BindState { bind_group: bind_group.clone(), - layout: layout.clone(), dynamic_offsets, is_dirty: true, }); @@ -1462,7 +1465,7 @@ impl State { } else { let first_changed = self.bind.iter().zip(&layout.bind_group_layouts).position( |(entry, layout)| match *entry { - Some(ref contents) => !contents.layout.is_equal(layout), + Some(ref contents) => !contents.bind_group.layout.is_equal(layout), None => false, }, ); diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index fecf588944..547356180c 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -4,7 +4,7 @@ use std::{ops::Range, sync::Arc}; use crate::device::trace::Command as TraceCommand; use crate::{ api_log, - command::CommandBuffer, + command::CommandEncoderError, device::DeviceError, get_lowest_common_denom, global::Global, @@ -76,7 +76,7 @@ whereas subesource range specified start {subresource_base_array_layer} and coun #[error(transparent)] Device(#[from] DeviceError), #[error(transparent)] - CommandEncoderError(#[from] super::CommandEncoderError), + CommandEncoderError(#[from] CommandEncoderError), } impl Global { @@ -92,7 +92,15 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + let cmd_buf = match hub + .command_buffers + .get(command_encoder_id.into_command_buffer_id()) + { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid.into()), + }; + cmd_buf.check_recording()?; + let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); @@ -176,7 +184,15 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + let cmd_buf = match hub + .command_buffers + .get(command_encoder_id.into_command_buffer_id()) + { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid.into()), + }; + cmd_buf.check_recording()?; + let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index b1dae2b49c..ff2bdf37e7 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -301,35 +301,40 @@ impl Global { timestamp_writes: None, // Handle only once we resolved the encoder. }; - match CommandBuffer::lock_encoder(hub, encoder_id) { - Ok(cmd_buf) => { - arc_desc.timestamp_writes = if let Some(tw) = desc.timestamp_writes { - let Ok(query_set) = hub.query_sets.get(tw.query_set) else { - return ( - ComputePass::new(None, arc_desc), - Some(CommandEncoderError::InvalidTimestampWritesQuerySetId( - tw.query_set, - )), - ); - }; + let make_err = |e, arc_desc| (ComputePass::new(None, arc_desc), Some(e)); - if let Err(e) = query_set.same_device_as(cmd_buf.as_ref()) { - return (ComputePass::new(None, arc_desc), Some(e.into())); - } + let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { + Ok(cmd_buf) => cmd_buf, + Err(_) => return make_err(CommandEncoderError::Invalid, arc_desc), + }; - Some(ArcPassTimestampWrites { - query_set, - beginning_of_pass_write_index: tw.beginning_of_pass_write_index, - end_of_pass_write_index: tw.end_of_pass_write_index, - }) - } else { - None - }; - - (ComputePass::new(Some(cmd_buf), arc_desc), None) + match cmd_buf.lock_encoder() { + Ok(_) => {} + Err(e) => return make_err(e, arc_desc), + }; + + arc_desc.timestamp_writes = if let Some(tw) = desc.timestamp_writes { + let Ok(query_set) = hub.query_sets.get(tw.query_set) else { + return make_err( + CommandEncoderError::InvalidTimestampWritesQuerySetId(tw.query_set), + arc_desc, + ); + }; + + if let Err(e) = query_set.same_device_as(cmd_buf.as_ref()) { + return make_err(e.into(), arc_desc); } - Err(err) => (ComputePass::new(None, arc_desc), Some(err)), - } + + Some(ArcPassTimestampWrites { + query_set, + beginning_of_pass_write_index: tw.beginning_of_pass_write_index, + end_of_pass_write_index: tw.end_of_pass_write_index, + }) + } else { + None + }; + + (ComputePass::new(Some(cmd_buf), arc_desc), None) } /// Creates a type erased compute pass. @@ -378,7 +383,11 @@ impl Global { let hub = A::hub(self); let scope = PassErrorScope::Pass; - let cmd_buf = CommandBuffer::get_encoder(hub, encoder_id).map_pass_err(scope)?; + let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid).map_pass_err(scope), + }; + cmd_buf.check_recording().map_pass_err(scope)?; #[cfg(feature = "trace")] { diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 9987d479dc..f5bfcec24e 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -30,7 +30,6 @@ pub use timestamp_writes::PassTimestampWrites; use self::memory_init::CommandBufferTextureMemoryActions; use crate::device::{Device, DeviceError}; -use crate::hub::Hub; use crate::lock::{rank, Mutex}; use crate::snatch::SnatchGuard; @@ -425,65 +424,41 @@ impl CommandBuffer { } impl CommandBuffer { - fn get_encoder_impl( - hub: &Hub, - id: id::CommandEncoderId, - lock_on_acquire: bool, - ) -> Result, CommandEncoderError> { - let storage = hub.command_buffers.read(); - match storage.get(id.into_command_buffer_id()) { - Ok(cmd_buf) => { - let mut cmd_buf_data = cmd_buf.data.lock(); - let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); - match cmd_buf_data.status { - CommandEncoderStatus::Recording => { - if lock_on_acquire { - cmd_buf_data.status = CommandEncoderStatus::Locked; - } - Ok(cmd_buf.clone()) - } - CommandEncoderStatus::Locked => { - // Any operation on a locked encoder is required to put it into the invalid/error state. - // See https://www.w3.org/TR/webgpu/#encoder-state-locked - cmd_buf_data.encoder.discard(); - cmd_buf_data.status = CommandEncoderStatus::Error; - Err(CommandEncoderError::Locked) - } - CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording), - CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid), + fn lock_encoder_impl(&self, lock: bool) -> Result<(), CommandEncoderError> { + let mut cmd_buf_data_guard = self.data.lock(); + let cmd_buf_data = cmd_buf_data_guard.as_mut().unwrap(); + match cmd_buf_data.status { + CommandEncoderStatus::Recording => { + if lock { + cmd_buf_data.status = CommandEncoderStatus::Locked; } + Ok(()) + } + CommandEncoderStatus::Locked => { + // Any operation on a locked encoder is required to put it into the invalid/error state. + // See https://www.w3.org/TR/webgpu/#encoder-state-locked + cmd_buf_data.encoder.discard(); + cmd_buf_data.status = CommandEncoderStatus::Error; + Err(CommandEncoderError::Locked) } - Err(_) => Err(CommandEncoderError::Invalid), + CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording), + CommandEncoderStatus::Error => Err(CommandEncoderError::Invalid), } } - /// Return the [`CommandBuffer`] for `id`, for recording new commands. - /// - /// In `wgpu_core`, the [`CommandBuffer`] type serves both as encoder and - /// buffer, which is why this function takes an [`id::CommandEncoderId`] but - /// returns a [`CommandBuffer`]. The returned command buffer must be in the - /// "recording" state. Otherwise, an error is returned. - fn get_encoder( - hub: &Hub, - id: id::CommandEncoderId, - ) -> Result, CommandEncoderError> { - let lock_on_acquire = false; - Self::get_encoder_impl(hub, id, lock_on_acquire) + /// Checks that the encoder is in the [`CommandEncoderStatus::Recording`] state. + fn check_recording(&self) -> Result<(), CommandEncoderError> { + self.lock_encoder_impl(false) } - /// Return the [`CommandBuffer`] for `id` and if successful puts it into the [`CommandEncoderStatus::Locked`] state. + /// Locks the encoder by putting it in the [`CommandEncoderStatus::Locked`] state. /// - /// See [`CommandBuffer::get_encoder`]. /// Call [`CommandBuffer::unlock_encoder`] to put the [`CommandBuffer`] back into the [`CommandEncoderStatus::Recording`] state. - fn lock_encoder( - hub: &Hub, - id: id::CommandEncoderId, - ) -> Result, CommandEncoderError> { - let lock_on_acquire = true; - Self::get_encoder_impl(hub, id, lock_on_acquire) + fn lock_encoder(&self) -> Result<(), CommandEncoderError> { + self.lock_encoder_impl(true) } - /// Unlocks the [`CommandBuffer`] for `id` and puts it back into the [`CommandEncoderStatus::Recording`] state. + /// Unlocks the [`CommandBuffer`] and puts it back into the [`CommandEncoderStatus::Recording`] state. /// /// This function is the counterpart to [`CommandBuffer::lock_encoder`]. /// It is only valid to call this function if the encoder is in the [`CommandEncoderStatus::Locked`] state. @@ -661,7 +636,12 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, encoder_id)?; + let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid), + }; + cmd_buf.check_recording()?; + let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); #[cfg(feature = "trace")] @@ -692,7 +672,12 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, encoder_id)?; + let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid), + }; + cmd_buf.check_recording()?; + let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); @@ -723,7 +708,12 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, encoder_id)?; + let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid), + }; + cmd_buf.check_recording()?; + let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index 3b69475653..f6601bddd5 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -231,7 +231,7 @@ pub(super) fn validate_and_begin_occlusion_query( let needs_reset = reset_state.is_none(); query_set.validate_query(SimplifiedQueryType::Occlusion, query_index, reset_state)?; - tracker.add_single(&query_set); + tracker.insert_single(query_set.clone()); if let Some((_old, old_idx)) = active_query.take() { return Err(QueryUseError::AlreadyStarted { @@ -282,7 +282,7 @@ pub(super) fn validate_and_begin_pipeline_statistics_query( reset_state, )?; - tracker.add_single(&query_set); + tracker.insert_single(query_set.clone()); if let Some((_old, old_idx)) = active_query.take() { return Err(QueryUseError::AlreadyStarted { @@ -324,7 +324,14 @@ impl Global { ) -> Result<(), QueryError> { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + let cmd_buf = match hub + .command_buffers + .get(command_encoder_id.into_command_buffer_id()) + { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid.into()), + }; + cmd_buf.check_recording()?; cmd_buf .device @@ -346,12 +353,12 @@ impl Global { let raw_encoder = encoder.open()?; - let query_set_guard = hub.query_sets.read(); - let query_set = query_set_guard + let query_set = hub + .query_sets .get(query_set_id) .map_err(|_| QueryError::InvalidQuerySetId(query_set_id))?; - tracker.query_sets.add_single(query_set); + let query_set = tracker.query_sets.insert_single(query_set); query_set.validate_and_write_timestamp(raw_encoder, query_index, None)?; @@ -369,7 +376,15 @@ impl Global { ) -> Result<(), QueryError> { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + let cmd_buf = match hub + .command_buffers + .get(command_encoder_id.into_command_buffer_id()) + { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid.into()), + }; + cmd_buf.check_recording()?; + let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); @@ -393,12 +408,12 @@ impl Global { return Err(QueryError::Resolve(ResolveError::BufferOffsetAlignment)); } - let query_set_guard = hub.query_sets.read(); - let query_set = query_set_guard + let query_set = hub + .query_sets .get(query_set_id) .map_err(|_| QueryError::InvalidQuerySetId(query_set_id))?; - tracker.query_sets.add_single(query_set); + let query_set = tracker.query_sets.insert_single(query_set); query_set.same_device_as(cmd_buf.as_ref())?; diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 65f5acb40f..66abd33b60 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -1432,9 +1432,16 @@ impl Global { occlusion_query_set: None, }; - let cmd_buf = match CommandBuffer::lock_encoder(hub, encoder_id) { + let make_err = |e, arc_desc| (RenderPass::new(None, arc_desc), Some(e)); + + let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { Ok(cmd_buf) => cmd_buf, - Err(e) => return (RenderPass::new(None, arc_desc), Some(e)), + Err(_) => return make_err(CommandEncoderError::Invalid, arc_desc), + }; + + match cmd_buf.lock_encoder() { + Ok(_) => {} + Err(e) => return make_err(e, arc_desc), }; let err = fill_arc_desc(hub, &cmd_buf.device, desc, &mut arc_desc).err(); @@ -1471,8 +1478,11 @@ impl Global { #[cfg(feature = "trace")] { let hub = A::hub(self); - let cmd_buf: Arc> = - CommandBuffer::get_encoder(hub, encoder_id).map_pass_err(pass_scope)?; + + let cmd_buf = match hub.command_buffers.get(encoder_id.into_command_buffer_id()) { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid).map_pass_err(pass_scope)?, + }; let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); @@ -2762,8 +2772,7 @@ impl Global { let hub = A::hub(self); let buffer = hub .buffers - .read() - .get_owned(buffer_id) + .get(buffer_id) .map_err(|_| RenderPassErrorInner::InvalidBuffer(buffer_id)) .map_pass_err(scope)?; @@ -2778,8 +2787,7 @@ impl Global { let hub = A::hub(self); let query_set = hub .query_sets - .read() - .get_owned(query_set_id) + .get(query_set_id) .map_err(|_| RenderPassErrorInner::InvalidQuerySet(query_set_id)) .map_pass_err(scope)?; @@ -2813,8 +2821,7 @@ impl Global { let hub = A::hub(self); let bind_group = hub .bind_groups - .read() - .get_owned(bind_group_id) + .get(bind_group_id) .map_err(|_| RenderPassErrorInner::InvalidBindGroup(index)) .map_pass_err(scope)?; @@ -2845,8 +2852,7 @@ impl Global { let hub = A::hub(self); let pipeline = hub .render_pipelines - .read() - .get_owned(pipeline_id) + .get(pipeline_id) .map_err(|_| RenderPassErrorInner::InvalidPipeline(pipeline_id)) .map_pass_err(scope)?; diff --git a/wgpu-core/src/command/render_command.rs b/wgpu-core/src/command/render_command.rs index 9050039cb2..287aa888f1 100644 --- a/wgpu-core/src/command/render_command.rs +++ b/wgpu-core/src/command/render_command.rs @@ -138,6 +138,7 @@ impl RenderCommand { let bind_group_guard = hub.bind_groups.read(); let query_set_guard = hub.query_sets.read(); let pipelines_guard = hub.render_pipelines.read(); + let render_bundles_guard = hub.render_bundles.read(); let resolved_commands: Vec> = commands .iter() @@ -363,12 +364,12 @@ impl RenderCommand { RenderCommand::EndOcclusionQuery => ArcRenderCommand::EndOcclusionQuery, RenderCommand::ExecuteBundle(bundle) => ArcRenderCommand::ExecuteBundle( - hub.render_bundles.read().get_owned(bundle).map_err(|_| { - RenderPassError { + render_bundles_guard + .get_owned(bundle) + .map_err(|_| RenderPassError { scope: PassErrorScope::ExecuteBundle, inner: RenderCommandError::InvalidRenderBundle(bundle).into(), - } - })?, + })?, ), }) }) diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 5748c0c994..4379777eb5 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -2,7 +2,7 @@ use crate::device::trace::Command as TraceCommand; use crate::{ api_log, - command::{clear_texture, CommandBuffer, CommandEncoderError}, + command::{clear_texture, CommandEncoderError}, conv, device::{Device, DeviceError, MissingDownlevelFlags}, global::Global, @@ -544,7 +544,15 @@ impl Global { } let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + let cmd_buf = match hub + .command_buffers + .get(command_encoder_id.into_command_buffer_id()) + { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid.into()), + }; + cmd_buf.check_recording()?; + let mut cmd_buf_data = cmd_buf.data.lock(); let cmd_buf_data = cmd_buf_data.as_mut().unwrap(); @@ -702,7 +710,15 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + let cmd_buf = match hub + .command_buffers + .get(command_encoder_id.into_command_buffer_id()) + { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid.into()), + }; + cmd_buf.check_recording()?; + let device = &cmd_buf.device; device.check_is_valid()?; @@ -858,7 +874,15 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + let cmd_buf = match hub + .command_buffers + .get(command_encoder_id.into_command_buffer_id()) + { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid.into()), + }; + cmd_buf.check_recording()?; + let device = &cmd_buf.device; device.check_is_valid()?; @@ -1026,7 +1050,15 @@ impl Global { let hub = A::hub(self); - let cmd_buf = CommandBuffer::get_encoder(hub, command_encoder_id)?; + let cmd_buf = match hub + .command_buffers + .get(command_encoder_id.into_command_buffer_id()) + { + Ok(cmd_buf) => cmd_buf, + Err(_) => return Err(CommandEncoderError::Invalid.into()), + }; + cmd_buf.check_recording()?; + let device = &cmd_buf.device; device.check_is_valid()?; diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 04e43a143d..0e2a22e888 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -7,16 +7,11 @@ use crate::{ ResolvedBindGroupEntry, ResolvedBindingResource, ResolvedBufferBinding, }, command, conv, - device::{ - bgl, life::WaitIdleError, map_buffer, queue, DeviceError, DeviceLostClosure, - DeviceLostReason, HostMap, - }, + device::{bgl, life::WaitIdleError, queue, DeviceError, DeviceLostClosure, DeviceLostReason}, global::Global, hal_api::HalApi, id::{self, AdapterId, DeviceId, QueueId, SurfaceId}, - init_tracker::TextureInitTracker, instance::{self, Adapter, Surface}, - lock::{rank, RwLock}, pipeline::{ self, ResolvedComputePipelineDescriptor, ResolvedFragmentState, ResolvedProgrammableStageDescriptor, ResolvedRenderPipelineDescriptor, ResolvedVertexState, @@ -30,7 +25,6 @@ use crate::{ Label, }; -use arrayvec::ArrayVec; use hal::Device as _; use wgt::{BufferAddress, TextureFormat}; @@ -161,7 +155,6 @@ impl Global { let hub = A::hub(self); let fid = hub.buffers.prepare(id_in); - let mut to_destroy: ArrayVec, 2> = ArrayVec::new(); let error = 'error: { let device = match hub.devices.get(device_id) { Ok(device) => device, @@ -180,92 +173,15 @@ impl Global { trace.add(trace::Action::CreateBuffer(fid.id(), desc)); } - if desc.usage.is_empty() { - // Per spec, `usage` must not be zero. - break 'error CreateBufferError::InvalidUsage(desc.usage); - } - - let buffer = match device.create_buffer(desc, false) { + let buffer = match device.create_buffer(desc) { Ok(buffer) => buffer, Err(e) => { break 'error e; } }; - let buffer_use = if !desc.mapped_at_creation { - hal::BufferUses::empty() - } else if desc.usage.contains(wgt::BufferUsages::MAP_WRITE) { - // buffer is mappable, so we are just doing that at start - let map_size = buffer.size; - let ptr = if map_size == 0 { - ptr::NonNull::dangling() - } else { - let snatch_guard = device.snatchable_lock.read(); - match map_buffer( - device.raw(), - &buffer, - 0, - map_size, - HostMap::Write, - &snatch_guard, - ) { - Ok(ptr) => ptr, - Err(e) => { - to_destroy.push(buffer); - break 'error e.into(); - } - } - }; - *buffer.map_state.lock() = resource::BufferMapState::Active { - ptr, - range: 0..map_size, - host: HostMap::Write, - }; - hal::BufferUses::MAP_WRITE - } else { - // buffer needs staging area for initialization only - let stage_desc = wgt::BufferDescriptor { - label: Some(Cow::Borrowed( - "(wgpu internal) initializing unmappable buffer", - )), - size: desc.size, - usage: wgt::BufferUsages::MAP_WRITE | wgt::BufferUsages::COPY_SRC, - mapped_at_creation: false, - }; - let stage = match device.create_buffer(&stage_desc, true) { - Ok(stage) => Arc::new(stage), - Err(e) => { - to_destroy.push(buffer); - break 'error e; - } - }; + let id = fid.assign(buffer); - let snatch_guard = device.snatchable_lock.read(); - let stage_raw = stage.raw(&snatch_guard).unwrap(); - let mapping = match unsafe { device.raw().map_buffer(stage_raw, 0..stage.size) } { - Ok(mapping) => mapping, - Err(e) => { - to_destroy.push(buffer); - break 'error CreateBufferError::Device(e.into()); - } - }; - - assert_eq!(buffer.size % wgt::COPY_BUFFER_ALIGNMENT, 0); - // Zero initialize memory and then mark both staging and buffer as initialized - // (it's guaranteed that this is the case by the time the buffer is usable) - unsafe { ptr::write_bytes(mapping.ptr.as_ptr(), 0, buffer.size as usize) }; - buffer.initialization_status.write().drain(0..buffer.size); - stage.initialization_status.write().drain(0..buffer.size); - - *buffer.map_state.lock() = resource::BufferMapState::Init { - ptr: mapping.ptr, - needs_flush: !mapping.is_coherent, - stage_buffer: stage, - }; - hal::BufferUses::COPY_DST - }; - - let (id, resource) = fid.assign(Arc::new(buffer)); api_log!( "Device::create_buffer({:?}{}) -> {id:?}", desc.label.as_deref().unwrap_or(""), @@ -276,24 +192,9 @@ impl Global { } ); - device - .trackers - .lock() - .buffers - .insert_single(resource, buffer_use); - return (id, None); }; - // Error path - - for buffer in to_destroy { - let device = Arc::clone(&buffer.device); - device - .lock_life() - .schedule_resource_destruction(queue::TempResource::Buffer(Arc::new(buffer)), !0); - } - let id = fid.assign_error(); (id, Some(error)) } @@ -358,12 +259,9 @@ impl Global { ) -> Result<(), WaitIdleError> { let hub = A::hub(self); - let last_submission = { - let buffer_guard = hub.buffers.write(); - match buffer_guard.get(buffer_id) { - Ok(buffer) => buffer.submission_index(), - Err(_) => return Ok(()), - } + let last_submission = match hub.buffers.read().get(buffer_id) { + Ok(buffer) => buffer.submission_index(), + Err(_) => return Ok(()), }; hub.devices @@ -581,20 +479,14 @@ impl Global { trace.add(trace::Action::CreateTexture(fid.id(), desc.clone())); } - let texture = match device.create_texture(&device.adapter, desc) { + let texture = match device.create_texture(desc) { Ok(texture) => texture, Err(error) => break 'error error, }; - let (id, resource) = fid.assign(Arc::new(texture)); + let id = fid.assign(texture); api_log!("Device::create_texture({desc:?}) -> {id:?}"); - device - .trackers - .lock() - .textures - .insert_single(resource, hal::TextureUses::UNINITIALIZED); - return (id, None); }; @@ -635,39 +527,14 @@ impl Global { trace.add(trace::Action::CreateTexture(fid.id(), desc.clone())); } - let format_features = match device - .describe_format_features(&device.adapter, desc.format) - .map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error)) - { - Ok(features) => features, + let texture = match device.create_texture_from_hal(hal_texture, desc) { + Ok(texture) => texture, Err(error) => break 'error error, }; - let mut texture = device.create_texture_from_hal( - hal_texture, - conv::map_texture_usage(desc.usage, desc.format.into()), - desc, - format_features, - resource::TextureClearMode::None, - ); - if desc.usage.contains(wgt::TextureUsages::COPY_DST) { - texture.hal_usage |= hal::TextureUses::COPY_DST; - } - - texture.initialization_status = RwLock::new( - rank::TEXTURE_INITIALIZATION_STATUS, - TextureInitTracker::new(desc.mip_level_count, 0), - ); - - let (id, resource) = fid.assign(Arc::new(texture)); + let id = fid.assign(texture); api_log!("Device::create_texture({desc:?}) -> {id:?}"); - device - .trackers - .lock() - .textures - .insert_single(resource, hal::TextureUses::UNINITIALIZED); - return (id, None); }; @@ -709,15 +576,9 @@ impl Global { let buffer = device.create_buffer_from_hal(hal_buffer, desc); - let (id, buffer) = fid.assign(Arc::new(buffer)); + let id = fid.assign(buffer); api_log!("Device::create_buffer -> {id:?}"); - device - .trackers - .lock() - .buffers - .insert_single(buffer, hal::BufferUses::empty()); - return (id, None); }; @@ -824,31 +685,15 @@ impl Global { }); } - { - let snatch_guard = device.snatchable_lock.read(); - if let Err(e) = texture.check_destroyed(&snatch_guard) { - break 'error e.into(); - } - } - let view = match device.create_texture_view(&texture, desc) { Ok(view) => view, Err(e) => break 'error e, }; - let (id, resource) = fid.assign(Arc::new(view)); - - { - let mut views = texture.views.lock(); - - // Remove stale weak references - views.retain(|view| view.strong_count() > 0); - - views.push(Arc::downgrade(&resource)); - } + let id = fid.assign(view); api_log!("Texture::create_view({texture_id:?}) -> {id:?}"); - device.trackers.lock().views.insert_single(resource); + return (id, None); }; @@ -920,9 +765,8 @@ impl Global { Err(e) => break 'error e, }; - let (id, resource) = fid.assign(Arc::new(sampler)); + let id = fid.assign(sampler); api_log!("Device::create_sampler -> {id:?}"); - device.trackers.lock().samplers.insert_single(resource); return (id, None); }; @@ -987,20 +831,6 @@ impl Global { Err(e) => break 'error e, }; - // Currently we make a distinction between fid.assign and fid.assign_existing. This distinction is incorrect, - // but see https://github.com/gfx-rs/wgpu/issues/4912. - // - // `assign` also registers the ID with the resource info, so it can be automatically reclaimed. This needs to - // happen with a mutable reference, which means it can only happen on creation. - // - // Because we need to call `assign` inside the closure (to get mut access), we need to "move" the future id into the closure. - // Rust cannot figure out at compile time that we only ever consume the ID once, so we need to move the check - // to runtime using an Option. - let mut fid = Some(fid); - - // The closure might get called, and it might give us an ID. Side channel it out of the closure. - let mut id = None; - let bgl_result = device.bgl_pool.get_or_init(entry_map, |entry_map| { let bgl = device.create_bind_group_layout(&desc.label, entry_map, bgl::Origin::Pool)?; @@ -1008,10 +838,9 @@ impl Global { .set(binding_model::ExclusivePipeline::None) .unwrap(); - let (id_inner, arc) = fid.take().unwrap().assign(Arc::new(bgl)); - id = Some(id_inner); + let bgl = Arc::new(bgl); - Ok(arc) + Ok(bgl) }); let layout = match bgl_result { @@ -1019,16 +848,10 @@ impl Global { Err(e) => break 'error e, }; - // If the ID was not assigned, and we survived the above check, - // it means that the bind group layout already existed and we need to call `assign_existing`. - // - // Calling this function _will_ leak the ID. See https://github.com/gfx-rs/wgpu/issues/4912. - if id.is_none() { - id = Some(fid.take().unwrap().assign_existing(&layout)) - } + let id = fid.assign(layout.clone()); api_log!("Device::create_bind_group_layout -> {id:?}"); - return (id.unwrap(), None); + return (id, None); }; let fid = hub.bind_group_layouts.prepare(id_in); @@ -1112,7 +935,7 @@ impl Global { Err(e) => break 'error e, }; - let (id, _) = fid.assign(Arc::new(layout)); + let id = fid.assign(Arc::new(layout)); api_log!("Device::create_pipeline_layout -> {id:?}"); return (id, None); }; @@ -1257,29 +1080,10 @@ impl Global { Err(e) => break 'error e, }; - let (id, resource) = fid.assign(Arc::new(bind_group)); - - let weak_ref = Arc::downgrade(&resource); - for range in &resource.used_texture_ranges { - let mut bind_groups = range.texture.bind_groups.lock(); - - // Remove stale weak references - bind_groups.retain(|bg| bg.strong_count() > 0); - - bind_groups.push(weak_ref.clone()); - } - for range in &resource.used_buffer_ranges { - let mut bind_groups = range.buffer.bind_groups.lock(); - - // Remove stale weak references - bind_groups.retain(|bg| bg.strong_count() > 0); - - bind_groups.push(weak_ref.clone()); - } + let id = fid.assign(bind_group); api_log!("Device::create_bind_group -> {id:?}"); - device.trackers.lock().bind_groups.insert_single(resource); return (id, None); }; @@ -1380,7 +1184,7 @@ impl Global { Err(e) => break 'error e, }; - let (id, _) = fid.assign(Arc::new(shader)); + let id = fid.assign(Arc::new(shader)); api_log!("Device::create_shader_module -> {id:?}"); return (id, None); }; @@ -1434,7 +1238,7 @@ impl Global { Ok(shader) => shader, Err(e) => break 'error e, }; - let (id, _) = fid.assign(Arc::new(shader)); + let id = fid.assign(Arc::new(shader)); api_log!("Device::create_shader_module_spirv -> {id:?}"); return (id, None); }; @@ -1484,7 +1288,7 @@ impl Global { Err(e) => break 'error e, }; - let (id, _) = fid.assign(Arc::new(command_buffer)); + let id = fid.assign(Arc::new(command_buffer)); api_log!("Device::create_command_encoder -> {id:?}"); return (id.into_command_encoder_id(), None); }; @@ -1574,9 +1378,9 @@ impl Global { Err(e) => break 'error e, }; - let (id, resource) = fid.assign(Arc::new(render_bundle)); + let id = fid.assign(render_bundle); api_log!("RenderBundleEncoder::finish -> {id:?}"); - device.trackers.lock().bundles.insert_single(resource); + return (id, None); }; @@ -1635,9 +1439,8 @@ impl Global { Err(err) => break 'error err, }; - let (id, resource) = fid.assign(Arc::new(query_set)); + let id = fid.assign(query_set); api_log!("Device::create_query_set -> {id:?}"); - device.trackers.lock().query_sets.insert_single(resource); return (id, None); }; @@ -1797,7 +1600,7 @@ impl Global { cache, }; - let pipeline = match device.create_render_pipeline(&device.adapter, desc) { + let pipeline = match device.create_render_pipeline(desc) { Ok(pair) => pair, Err(e) => break 'error e, }; @@ -1832,15 +1635,9 @@ impl Global { } } - let (id, resource) = fid.assign(pipeline); + let id = fid.assign(pipeline); api_log!("Device::create_render_pipeline -> {id:?}"); - device - .trackers - .lock() - .render_pipelines - .insert_single(resource); - return (id, None); }; @@ -1883,7 +1680,7 @@ impl Global { Err(_) => break 'error binding_model::GetBindGroupLayoutError::InvalidPipeline, }; let id = match pipeline.layout.bind_group_layouts.get(index as usize) { - Some(bg) => hub.bind_group_layouts.prepare(id_in).assign_existing(bg), + Some(bg) => hub.bind_group_layouts.prepare(id_in).assign(bg.clone()), None => { break 'error binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index) } @@ -2040,14 +1837,9 @@ impl Global { } } - let (id, resource) = fid.assign(pipeline); + let id = fid.assign(pipeline); api_log!("Device::create_compute_pipeline -> {id:?}"); - device - .trackers - .lock() - .compute_pipelines - .insert_single(resource); return (id, None); }; @@ -2089,7 +1881,7 @@ impl Global { }; let id = match pipeline.layout.bind_group_layouts.get(index as usize) { - Some(bg) => hub.bind_group_layouts.prepare(id_in).assign_existing(bg), + Some(bg) => hub.bind_group_layouts.prepare(id_in).assign(bg.clone()), None => { break 'error binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index) } @@ -2163,7 +1955,7 @@ impl Global { let cache = unsafe { device.create_pipeline_cache(desc) }; match cache { Ok(cache) => { - let (id, _) = fid.assign(Arc::new(cache)); + let id = fid.assign(Arc::new(cache)); api_log!("Device::create_pipeline_cache -> {id:?}"); return (id, None); } @@ -2197,7 +1989,7 @@ impl Global { device_id: DeviceId, config: &wgt::SurfaceConfiguration>, ) -> Option { - use hal::{Adapter as _, Surface as _}; + use hal::Surface as _; use present::ConfigureSurfaceError as E; profiling::scope!("surface_configure"); @@ -2318,9 +2110,8 @@ impl Global { { let hub = A::hub(self); let surface_guard = self.surfaces.read(); - let device_guard = hub.devices.read(); - let device = match device_guard.get(device_id) { + let device = match hub.devices.get(device_id) { Ok(device) => device, Err(_) => break 'error DeviceError::InvalidDeviceId.into(), }; @@ -2339,13 +2130,9 @@ impl Global { Err(_) => break 'error E::InvalidSurface, }; - let caps = unsafe { - let suf = A::surface_as_hal(surface); - let adapter = &device.adapter; - match adapter.raw.adapter.surface_capabilities(suf.unwrap()) { - Some(caps) => caps, - None => break 'error E::UnsupportedQueueFamily, - } + let caps = match surface.get_capabilities(&device.adapter) { + Ok(caps) => caps, + Err(_) => break 'error E::UnsupportedQueueFamily, }; let mut hal_view_formats = vec![]; @@ -2446,7 +2233,7 @@ impl Global { let mut presentation = surface.presentation.lock(); *presentation = Some(present::Presentation { - device: super::any_device::AnyDevice::new(device.clone()), + device: super::any_device::AnyDevice::new(device), config: config.clone(), acquired_texture: None, }); diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index 5951ea7507..9949b5242f 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -498,7 +498,7 @@ impl Global { prepare_staging_buffer(device, buffer_size.get(), device.instance_flags)?; let fid = hub.staging_buffers.prepare(id_in); - let (id, _) = fid.assign(Arc::new(staging_buffer)); + let id = fid.assign(Arc::new(staging_buffer)); resource_log!("Queue::create_staging_buffer {id:?}"); Ok((id, staging_buffer_ptr)) diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index fc9c6a3f07..eb43202bca 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -6,15 +6,16 @@ use crate::{ device::{ bgl, create_validator, life::{LifetimeTracker, WaitIdleError}, + map_buffer, queue::PendingWrites, - AttachmentData, DeviceLostInvocation, MissingDownlevelFlags, MissingFeatures, + AttachmentData, DeviceLostInvocation, HostMap, MissingDownlevelFlags, MissingFeatures, RenderPassContext, CLEANUP_WAIT_MS, }, hal_api::HalApi, hal_label, init_tracker::{ BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange, - TextureInitTracker, TextureInitTrackerAction, + TextureInitTrackerAction, }, instance::Adapter, lock::{rank, Mutex, MutexGuard, RwLock}, @@ -372,8 +373,8 @@ impl Device { self.queue.get().as_ref()?.upgrade() } - pub fn set_queue(&self, queue: Arc>) { - assert!(self.queue.set(Arc::downgrade(&queue)).is_ok()); + pub fn set_queue(&self, queue: &Arc>) { + assert!(self.queue.set(Arc::downgrade(queue)).is_ok()); } /// Check this device for completed commands. @@ -558,8 +559,78 @@ impl Device { pub(crate) fn create_buffer( self: &Arc, desc: &resource::BufferDescriptor, + ) -> Result>, resource::CreateBufferError> { + let buffer = self.create_buffer_impl(desc, false)?; + + let buffer_use = if !desc.mapped_at_creation { + hal::BufferUses::empty() + } else if desc.usage.contains(wgt::BufferUsages::MAP_WRITE) { + // buffer is mappable, so we are just doing that at start + let map_size = buffer.size; + let ptr = if map_size == 0 { + std::ptr::NonNull::dangling() + } else { + let snatch_guard: SnatchGuard = self.snatchable_lock.read(); + map_buffer( + self.raw(), + &buffer, + 0, + map_size, + HostMap::Write, + &snatch_guard, + )? + }; + *buffer.map_state.lock() = resource::BufferMapState::Active { + ptr, + range: 0..map_size, + host: HostMap::Write, + }; + hal::BufferUses::MAP_WRITE + } else { + // buffer needs staging area for initialization only + let stage_desc = wgt::BufferDescriptor { + label: Some(Cow::Borrowed( + "(wgpu internal) initializing unmappable buffer", + )), + size: desc.size, + usage: wgt::BufferUsages::MAP_WRITE | wgt::BufferUsages::COPY_SRC, + mapped_at_creation: false, + }; + let stage = self.create_buffer_impl(&stage_desc, true)?; + + let snatch_guard = self.snatchable_lock.read(); + let stage_raw = stage.raw(&snatch_guard).unwrap(); + let mapping = unsafe { self.raw().map_buffer(stage_raw, 0..stage.size) } + .map_err(DeviceError::from)?; + + assert_eq!(buffer.size % wgt::COPY_BUFFER_ALIGNMENT, 0); + // Zero initialize memory and then mark both staging and buffer as initialized + // (it's guaranteed that this is the case by the time the buffer is usable) + unsafe { std::ptr::write_bytes(mapping.ptr.as_ptr(), 0, buffer.size as usize) }; + buffer.initialization_status.write().drain(0..buffer.size); + stage.initialization_status.write().drain(0..buffer.size); + + *buffer.map_state.lock() = resource::BufferMapState::Init { + ptr: mapping.ptr, + needs_flush: !mapping.is_coherent, + stage_buffer: stage, + }; + hal::BufferUses::COPY_DST + }; + + self.trackers + .lock() + .buffers + .insert_single(&buffer, buffer_use); + + Ok(buffer) + } + + fn create_buffer_impl( + self: &Arc, + desc: &resource::BufferDescriptor, transient: bool, - ) -> Result, resource::CreateBufferError> { + ) -> Result>, resource::CreateBufferError> { self.check_is_valid()?; if desc.size > self.limits.max_buffer_size { @@ -580,8 +651,6 @@ impl Device { self.require_downlevel_flags(wgt::DownlevelFlags::UNRESTRICTED_INDEX_BUFFER)?; } - let mut usage = conv::map_buffer_usage(desc.usage); - if desc.usage.is_empty() || desc.usage.contains_invalid_bits() { return Err(resource::CreateBufferError::InvalidUsage(desc.usage)); } @@ -600,6 +669,8 @@ impl Device { } } + let mut usage = conv::map_buffer_usage(desc.usage); + if desc.mapped_at_creation { if desc.size % wgt::COPY_BUFFER_ALIGNMENT != 0 { return Err(resource::CreateBufferError::UnalignedSize); @@ -641,7 +712,7 @@ impl Device { }; let buffer = unsafe { self.raw().create_buffer(&hal_desc) }.map_err(DeviceError::from)?; - Ok(Buffer { + let buffer = Buffer { raw: Snatchable::new(buffer), device: self.clone(), usage: desc.usage, @@ -655,45 +726,46 @@ impl Device { label: desc.label.to_string(), tracking_data: TrackingData::new(self.tracker_indices.buffers.clone()), bind_groups: Mutex::new(rank::BUFFER_BIND_GROUPS, Vec::new()), - }) + }; + let buffer = Arc::new(buffer); + Ok(buffer) } pub(crate) fn create_texture_from_hal( self: &Arc, hal_texture: A::Texture, - hal_usage: hal::TextureUses, desc: &resource::TextureDescriptor, - format_features: wgt::TextureFormatFeatures, - clear_mode: resource::TextureClearMode, - ) -> Texture { - Texture { - inner: Snatchable::new(resource::TextureInner::Native { raw: hal_texture }), - device: self.clone(), - desc: desc.map_label(|_| ()), - hal_usage, + ) -> Result>, resource::CreateTextureError> { + let format_features = self + .describe_format_features(desc.format) + .map_err(|error| resource::CreateTextureError::MissingFeatures(desc.format, error))?; + + let texture = Texture::new( + self, + resource::TextureInner::Native { raw: hal_texture }, + conv::map_texture_usage(desc.usage, desc.format.into()), + desc, format_features, - initialization_status: RwLock::new( - rank::TEXTURE_INITIALIZATION_STATUS, - TextureInitTracker::new(desc.mip_level_count, desc.array_layer_count()), - ), - full_range: TextureSelector { - mips: 0..desc.mip_level_count, - layers: 0..desc.array_layer_count(), - }, - label: desc.label.to_string(), - tracking_data: TrackingData::new(self.tracker_indices.textures.clone()), - clear_mode: RwLock::new(rank::TEXTURE_CLEAR_MODE, clear_mode), - views: Mutex::new(rank::TEXTURE_VIEWS, Vec::new()), - bind_groups: Mutex::new(rank::TEXTURE_BIND_GROUPS, Vec::new()), - } + resource::TextureClearMode::None, + false, + ); + + let texture = Arc::new(texture); + + self.trackers + .lock() + .textures + .insert_single(&texture, hal::TextureUses::UNINITIALIZED); + + Ok(texture) } pub fn create_buffer_from_hal( self: &Arc, hal_buffer: A::Buffer, desc: &resource::BufferDescriptor, - ) -> Buffer { - Buffer { + ) -> Arc> { + let buffer = Buffer { raw: Snatchable::new(hal_buffer), device: self.clone(), usage: desc.usage, @@ -707,14 +779,22 @@ impl Device { label: desc.label.to_string(), tracking_data: TrackingData::new(self.tracker_indices.buffers.clone()), bind_groups: Mutex::new(rank::BUFFER_BIND_GROUPS, Vec::new()), - } + }; + + let buffer = Arc::new(buffer); + + self.trackers + .lock() + .buffers + .insert_single(&buffer, hal::BufferUses::empty()); + + buffer } pub(crate) fn create_texture( self: &Arc, - adapter: &Adapter, desc: &resource::TextureDescriptor, - ) -> Result, resource::CreateTextureError> { + ) -> Result>, resource::CreateTextureError> { use resource::{CreateTextureError, TextureDimensionError}; self.check_is_valid()?; @@ -804,7 +884,7 @@ impl Device { } let format_features = self - .describe_format_features(adapter, desc.format) + .describe_format_features(desc.format) .map_err(|error| CreateTextureError::MissingFeatures(desc.format, error))?; if desc.sample_count > 1 { @@ -851,7 +931,7 @@ impl Device { .guaranteed_format_features(self.features) .flags .supported_sample_counts(), - adapter + self.adapter .get_texture_format_features(desc.format) .flags .supported_sample_counts(), @@ -982,9 +1062,23 @@ impl Device { resource::TextureClearMode::BufferCopy }; - let mut texture = - self.create_texture_from_hal(raw_texture, hal_usage, desc, format_features, clear_mode); - texture.hal_usage = hal_usage; + let texture = Texture::new( + self, + resource::TextureInner::Native { raw: raw_texture }, + hal_usage, + desc, + format_features, + clear_mode, + true, + ); + + let texture = Arc::new(texture); + + self.trackers + .lock() + .textures + .insert_single(&texture, hal::TextureUses::UNINITIALIZED); + Ok(texture) } @@ -992,7 +1086,7 @@ impl Device { self: &Arc, texture: &Arc>, desc: &resource::TextureViewDescriptor, - ) -> Result, resource::CreateTextureViewError> { + ) -> Result>, resource::CreateTextureViewError> { let snatch_guard = texture.device.snatchable_lock.read(); let texture_raw = texture.try_raw(&snatch_guard)?; @@ -1267,7 +1361,7 @@ impl Device { layers: desc.range.base_array_layer..array_layer_end, }; - Ok(TextureView { + let view = TextureView { raw: Snatchable::new(raw), parent: texture.clone(), device: self.clone(), @@ -1283,13 +1377,28 @@ impl Device { selector, label: desc.label.to_string(), tracking_data: TrackingData::new(self.tracker_indices.texture_views.clone()), - }) + }; + + let view = Arc::new(view); + + { + let mut views = texture.views.lock(); + + // Remove stale weak references + views.retain(|view| view.strong_count() > 0); + + views.push(Arc::downgrade(&view)); + } + + self.trackers.lock().views.insert_single(view.clone()); + + Ok(view) } pub(crate) fn create_sampler( self: &Arc, desc: &resource::SamplerDescriptor, - ) -> Result, resource::CreateSamplerError> { + ) -> Result>, resource::CreateSamplerError> { self.check_is_valid()?; if desc @@ -1385,7 +1494,8 @@ impl Device { .create_sampler(&hal_desc) .map_err(DeviceError::from)? }; - Ok(Sampler { + + let sampler = Sampler { raw: Some(raw), device: self.clone(), label: desc.label.to_string(), @@ -1393,7 +1503,13 @@ impl Device { comparison: desc.compare.is_some(), filtering: desc.min_filter == wgt::FilterMode::Linear || desc.mag_filter == wgt::FilterMode::Linear, - }) + }; + + let sampler = Arc::new(sampler); + + self.trackers.lock().samplers.insert_single(sampler.clone()); + + Ok(sampler) } pub(crate) fn create_shader_module<'a>( @@ -2080,7 +2196,7 @@ impl Device { pub(crate) fn create_bind_group( self: &Arc, desc: binding_model::ResolvedBindGroupDescriptor, - ) -> Result, binding_model::CreateBindGroupError> { + ) -> Result>, binding_model::CreateBindGroupError> { use crate::binding_model::{CreateBindGroupError as Error, ResolvedBindingResource as Br}; let layout = desc.layout; @@ -2255,7 +2371,7 @@ impl Device { .flat_map(|binding| late_buffer_binding_sizes.get(&binding).cloned()) .collect(); - Ok(BindGroup { + let bind_group = BindGroup { raw: Snatchable::new(raw), device: self.clone(), layout, @@ -2266,7 +2382,34 @@ impl Device { used_texture_ranges, dynamic_binding_info, late_buffer_binding_sizes, - }) + }; + + let bind_group = Arc::new(bind_group); + + let weak_ref = Arc::downgrade(&bind_group); + for range in &bind_group.used_texture_ranges { + let mut bind_groups = range.texture.bind_groups.lock(); + + // Remove stale weak references + bind_groups.retain(|bg| bg.strong_count() > 0); + + bind_groups.push(weak_ref.clone()); + } + for range in &bind_group.used_buffer_ranges { + let mut bind_groups = range.buffer.bind_groups.lock(); + + // Remove stale weak references + bind_groups.retain(|bg| bg.strong_count() > 0); + + bind_groups.push(weak_ref.clone()); + } + + self.trackers + .lock() + .bind_groups + .insert_single(bind_group.clone()); + + Ok(bind_group) } pub(crate) fn check_array_binding( @@ -2686,6 +2829,11 @@ impl Device { let pipeline = Arc::new(pipeline); + self.trackers + .lock() + .compute_pipelines + .insert_single(pipeline.clone()); + if is_auto_layout { for bgl in pipeline.layout.bind_group_layouts.iter() { bgl.exclusive_pipeline @@ -2701,7 +2849,6 @@ impl Device { pub(crate) fn create_render_pipeline( self: &Arc, - adapter: &Adapter, desc: pipeline::ResolvedRenderPipelineDescriptor, ) -> Result>, pipeline::CreateRenderPipelineError> { use wgt::TextureFormatFeatureFlags as Tfff; @@ -2870,7 +3017,7 @@ impl Device { )); } - let format_features = self.describe_format_features(adapter, cs.format)?; + let format_features = self.describe_format_features(cs.format)?; if !format_features .allowed_usages .contains(wgt::TextureUsages::RENDER_ATTACHMENT) @@ -2909,7 +3056,7 @@ impl Device { .guaranteed_format_features(self.features) .flags .supported_sample_counts(), - adapter + self.adapter .get_texture_format_features(cs.format) .flags .supported_sample_counts(), @@ -2957,7 +3104,7 @@ impl Device { if let Some(ds) = depth_stencil_state { target_specified = true; let error = 'error: { - let format_features = self.describe_format_features(adapter, ds.format)?; + let format_features = self.describe_format_features(ds.format)?; if !format_features .allowed_usages .contains(wgt::TextureUsages::RENDER_ATTACHMENT) @@ -2988,7 +3135,7 @@ impl Device { .guaranteed_format_features(self.features) .flags .supported_sample_counts(), - adapter + self.adapter .get_texture_format_features(ds.format) .flags .supported_sample_counts(), @@ -3313,6 +3460,11 @@ impl Device { let pipeline = Arc::new(pipeline); + self.trackers + .lock() + .render_pipelines + .insert_single(pipeline.clone()); + if is_auto_layout { for bgl in pipeline.layout.bind_group_layouts.iter() { bgl.exclusive_pipeline @@ -3376,12 +3528,11 @@ impl Device { pub(crate) fn get_texture_format_features( &self, - adapter: &Adapter, format: TextureFormat, ) -> wgt::TextureFormatFeatures { // Variant of adapter.get_texture_format_features that takes device features into account use wgt::TextureFormatFeatureFlags as tfsc; - let mut format_features = adapter.get_texture_format_features(format); + let mut format_features = self.adapter.get_texture_format_features(format); if (format == TextureFormat::R32Float || format == TextureFormat::Rg32Float || format == TextureFormat::Rgba32Float) @@ -3394,7 +3545,6 @@ impl Device { pub(crate) fn describe_format_features( &self, - adapter: &Adapter, format: TextureFormat, ) -> Result { self.require_features(format.required_features())?; @@ -3410,7 +3560,7 @@ impl Device { .contains(wgt::DownlevelFlags::WEBGPU_TEXTURE_FORMAT_SUPPORT); if using_device_features || downlevel { - Ok(self.get_texture_format_features(adapter, format)) + Ok(self.get_texture_format_features(format)) } else { Ok(format.guaranteed_format_features(self.features)) } @@ -3453,7 +3603,7 @@ impl Device { pub(crate) fn create_query_set( self: &Arc, desc: &resource::QuerySetDescriptor, - ) -> Result, resource::CreateQuerySetError> { + ) -> Result>, resource::CreateQuerySetError> { use resource::CreateQuerySetError as Error; self.check_is_valid()?; @@ -3480,13 +3630,23 @@ impl Device { } let hal_desc = desc.map_label(|label| label.to_hal(self.instance_flags)); - Ok(QuerySet { + + let query_set = QuerySet { raw: Some(unsafe { self.raw().create_query_set(&hal_desc).unwrap() }), device: self.clone(), label: desc.label.to_string(), tracking_data: TrackingData::new(self.tracker_indices.query_sets.clone()), desc: desc.map_label(|_| ()), - }) + }; + + let query_set = Arc::new(query_set); + + self.trackers + .lock() + .query_sets + .insert_single(query_set.clone()); + + Ok(query_set) } pub(crate) fn lose(&self, message: &str) { diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index 5bc86b377c..05efbd2e44 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -323,6 +323,9 @@ ids! { pub type QuerySetId QuerySet; } +// The CommandBuffer type serves both as encoder and +// buffer, which is why the 2 functions below exist. + impl CommandEncoderId { pub fn into_command_buffer_id(self) -> CommandBufferId { Id(self.0, PhantomData) diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index ea851b1d57..b2aad0662a 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -155,12 +155,18 @@ impl Surface { pub fn get_capabilities( &self, adapter: &Adapter, + ) -> Result { + self.get_capabilities_with_raw(&adapter.raw) + } + + pub fn get_capabilities_with_raw( + &self, + adapter: &hal::ExposedAdapter, ) -> Result { let suf = A::surface_as_hal(self).ok_or(GetSurfaceSupportError::Unsupported)?; profiling::scope!("surface_capabilities"); let caps = unsafe { adapter - .raw .adapter .surface_capabilities(suf) .ok_or(GetSurfaceSupportError::Unsupported)? @@ -192,16 +198,11 @@ impl Adapter { } pub fn is_surface_supported(&self, surface: &Surface) -> bool { - let suf = A::surface_as_hal(surface); - - // If get_surface returns None, then the API does not advertise support for the surface. + // If get_capabilities returns Err, then the API does not advertise support for the surface. // // This could occur if the user is running their app on Wayland but Vulkan does not support // VK_KHR_wayland_surface. - match suf { - Some(suf) => unsafe { self.raw.adapter.surface_capabilities(suf) }.is_some(), - None => false, - } + surface.get_capabilities(self).is_ok() } pub(crate) fn get_texture_format_features( @@ -272,13 +273,14 @@ impl Adapter { } } + #[allow(clippy::type_complexity)] fn create_device_and_queue_from_hal( self: &Arc, hal_device: OpenDevice, desc: &DeviceDescriptor, instance_flags: wgt::InstanceFlags, trace_path: Option<&std::path::Path>, - ) -> Result<(Arc>, Queue), RequestDeviceError> { + ) -> Result<(Arc>, Arc>), RequestDeviceError> { api_log!("Adapter::create_device"); if let Ok(device) = Device::new( @@ -294,17 +296,20 @@ impl Adapter { device: device.clone(), raw: Some(hal_device.queue), }; + let queue = Arc::new(queue); + device.set_queue(&queue); return Ok((device, queue)); } Err(RequestDeviceError::OutOfMemory) } + #[allow(clippy::type_complexity)] fn create_device_and_queue( self: &Arc, desc: &DeviceDescriptor, instance_flags: wgt::InstanceFlags, trace_path: Option<&std::path::Path>, - ) -> Result<(Arc>, Queue), RequestDeviceError> { + ) -> Result<(Arc>, Arc>), RequestDeviceError> { // Verify all features were exposed by the adapter if !self.raw.features.contains(desc.required_features) { return Err(RequestDeviceError::UnsupportedFeature( @@ -545,7 +550,7 @@ impl Global { if any_created { #[allow(clippy::arc_with_non_send_sync)] - let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface)); + let id = self.surfaces.prepare(id_in).assign(Arc::new(surface)); Ok(id) } else { Err(CreateSurfaceError::FailedToCreateSurfaceForAnyBackend( @@ -583,7 +588,7 @@ impl Global { gl: None, }; - let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface)); + let id = self.surfaces.prepare(id_in).assign(Arc::new(surface)); Ok(id) } @@ -609,7 +614,7 @@ impl Global { gl: None, }; - let (id, _) = self.surfaces.prepare(id_in).assign(Arc::new(surface)); + let id = self.surfaces.prepare(id_in).assign(Arc::new(surface)); Ok(id) } @@ -716,7 +721,7 @@ impl Global { for raw in hal_adapters { let adapter = Adapter::new(raw); log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); - let (id, _) = hub.adapters.prepare(id_backend).assign(Arc::new(adapter)); + let id = hub.adapters.prepare(id_backend).assign(Arc::new(adapter)); list.push(id); } } @@ -763,7 +768,7 @@ impl Global { None => { let adapter = Adapter::new(list.swap_remove(*selected)); log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); - let (id, _) = HalApi::hub(self) + let id = HalApi::hub(self) .adapters .prepare(new_id) .assign(Arc::new(adapter)); @@ -796,16 +801,8 @@ impl Global { adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu); } if let Some(surface) = compatible_surface { - let surface = &A::surface_as_hal(surface); - adapters.retain(|exposed| unsafe { - // If the surface does not exist for this backend, - // then the surface is not supported. - surface.is_some() - && exposed - .adapter - .surface_capabilities(surface.unwrap()) - .is_some() - }); + adapters + .retain(|exposed| surface.get_capabilities_with_raw(exposed).is_ok()); } device_types.extend(adapters.iter().map(|ad| ad.info.device_type)); (id, adapters) @@ -947,7 +944,7 @@ impl Global { let fid = A::hub(self).adapters.prepare(input); - let (id, _adapter): (_, Arc>) = match A::VARIANT { + let id = match A::VARIANT { #[cfg(vulkan)] Backend::Vulkan => fid.assign(Arc::new(Adapter::new(hal_adapter))), #[cfg(metal)] @@ -1039,16 +1036,7 @@ impl Global { api_log!("Adapter::drop {adapter_id:?}"); let hub = A::hub(self); - let mut adapters_locked = hub.adapters.write(); - - let free = match adapters_locked.get(adapter_id) { - Ok(adapter) => Arc::strong_count(adapter) == 1, - Err(_) => true, - }; - if free { - hub.adapters - .unregister_locked(adapter_id, &mut *adapters_locked); - } + hub.adapters.unregister(adapter_id); } } @@ -1078,16 +1066,13 @@ impl Global { Ok((device, queue)) => (device, queue), Err(e) => break 'error e, }; - let (device_id, _) = device_fid.assign(device); - resource_log!("Created Device {:?}", device_id); - let device = hub.devices.get(device_id).unwrap(); + let device_id = device_fid.assign(device); + resource_log!("Created Device {:?}", device_id); - let (queue_id, queue) = queue_fid.assign(Arc::new(queue)); + let queue_id = queue_fid.assign(queue); resource_log!("Created Queue {:?}", queue_id); - device.set_queue(queue); - return (device_id, queue_id, None); }; @@ -1129,16 +1114,13 @@ impl Global { Ok(device) => device, Err(e) => break 'error e, }; - let (device_id, _) = devices_fid.assign(device); - resource_log!("Created Device {:?}", device_id); - let device = hub.devices.get(device_id).unwrap(); + let device_id = devices_fid.assign(device); + resource_log!("Created Device {:?}", device_id); - let (queue_id, queue) = queues_fid.assign(Arc::new(queue)); + let queue_id = queues_fid.assign(queue); resource_log!("Created Queue {:?}", queue_id); - device.set_queue(queue); - return (device_id, queue_id, None); }; diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index a49332a3b5..fa03387cb7 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -20,11 +20,7 @@ use crate::{ global::Global, hal_api::HalApi, hal_label, id, - init_tracker::TextureInitTracker, - lock::{rank, Mutex, RwLock}, - resource::{self, Trackable, TrackingData}, - snatch::Snatchable, - track, + resource::{self, Trackable}, }; use hal::{Queue as _, Surface as _}; @@ -167,7 +163,7 @@ impl Global { drop(fence_guard); let texture_desc = wgt::TextureDescriptor { - label: (), + label: Some(std::borrow::Cow::Borrowed("")), size: wgt::Extent3d { width: config.width, height: config.height, @@ -207,45 +203,31 @@ impl Global { let mut presentation = surface.presentation.lock(); let present = presentation.as_mut().unwrap(); - let texture = resource::Texture { - inner: Snatchable::new(resource::TextureInner::Surface { + let texture = resource::Texture::new( + &device, + resource::TextureInner::Surface { raw: Some(ast.texture), parent_id: surface_id, - }), - device: device.clone(), - desc: texture_desc, + }, hal_usage, + &texture_desc, format_features, - initialization_status: RwLock::new( - rank::TEXTURE_INITIALIZATION_STATUS, - TextureInitTracker::new(1, 1), - ), - full_range: track::TextureSelector { - layers: 0..1, - mips: 0..1, + resource::TextureClearMode::Surface { + clear_view: Some(clear_view), }, - label: String::from(""), - tracking_data: TrackingData::new(device.tracker_indices.textures.clone()), - clear_mode: RwLock::new( - rank::TEXTURE_CLEAR_MODE, - resource::TextureClearMode::Surface { - clear_view: Some(clear_view), - }, - ), - views: Mutex::new(rank::TEXTURE_VIEWS, Vec::new()), - bind_groups: Mutex::new(rank::TEXTURE_BIND_GROUPS, Vec::new()), - }; + true, + ); - let (id, resource) = fid.assign(Arc::new(texture)); - log::debug!("Created CURRENT Surface Texture {:?}", id); + let texture = Arc::new(texture); - { - // register it in the device tracker as uninitialized - let mut trackers = device.trackers.lock(); - trackers - .textures - .insert_single(resource, hal::TextureUses::UNINITIALIZED); - } + device + .trackers + .lock() + .textures + .insert_single(&texture, hal::TextureUses::UNINITIALIZED); + + let id = fid.assign(texture); + log::debug!("Created CURRENT Surface Texture {:?}", id); if present.acquired_texture.is_some() { return Err(SurfaceError::AlreadyAcquired); diff --git a/wgpu-core/src/registry.rs b/wgpu-core/src/registry.rs index 4a776e083e..9183cc83bb 100644 --- a/wgpu-core/src/registry.rs +++ b/wgpu-core/src/registry.rs @@ -76,19 +76,9 @@ impl FutureId<'_, T> { /// Assign a new resource to this ID. /// /// Registers it with the registry. - pub fn assign(self, value: Arc) -> (Id, Arc) { + pub fn assign(self, value: Arc) -> Id { let mut data = self.data.write(); data.insert(self.id, value); - (self.id, data.get(self.id).unwrap().clone()) - } - - /// Assign an existing resource to a new ID. - /// - /// Registers it with the registry. - pub fn assign_existing(self, value: &Arc) -> Id { - let mut data = self.data.write(); - debug_assert!(!data.contains(self.id)); - data.insert(self.id, value.clone()); self.id } @@ -121,14 +111,6 @@ impl Registry { pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage> { self.storage.write() } - pub(crate) fn unregister_locked( - &self, - id: Id, - storage: &mut Storage, - ) -> Option> { - self.identity.free(id); - storage.remove(id) - } pub(crate) fn force_replace_with_error(&self, id: Id) { let mut storage = self.storage.write(); storage.remove(id); @@ -189,7 +171,7 @@ mod tests { for _ in 0..1000 { let value = Arc::new(TestData); let new_id = registry.prepare(None); - let (id, _) = new_id.assign(value); + let id = new_id.assign(value); registry.unregister(id); } }); diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index b674df17ea..4eb073b6b8 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -10,11 +10,11 @@ use crate::{ hal_api::HalApi, id::{AdapterId, BufferId, CommandEncoderId, DeviceId, SurfaceId, TextureId, TextureViewId}, init_tracker::{BufferInitTracker, TextureInitTracker}, - lock::{Mutex, RwLock}, + lock::{rank, Mutex, RwLock}, resource_log, snatch::{ExclusiveSnatchGuard, SnatchGuard, Snatchable}, track::{SharedTrackerIndexAllocator, TextureSelector, TrackerIndex}, - Label, SubmissionIndex, + Label, LabelHelpers, SubmissionIndex, }; use hal::CommandEncoder; @@ -960,6 +960,40 @@ pub struct Texture { } impl Texture { + pub(crate) fn new( + device: &Arc>, + inner: TextureInner, + hal_usage: hal::TextureUses, + desc: &TextureDescriptor, + format_features: wgt::TextureFormatFeatures, + clear_mode: TextureClearMode, + init: bool, + ) -> Self { + Texture { + inner: Snatchable::new(inner), + device: device.clone(), + desc: desc.map_label(|_| ()), + hal_usage, + format_features, + initialization_status: RwLock::new( + rank::TEXTURE_INITIALIZATION_STATUS, + if init { + TextureInitTracker::new(desc.mip_level_count, desc.array_layer_count()) + } else { + TextureInitTracker::new(0, 0) + }, + ), + full_range: TextureSelector { + mips: 0..desc.mip_level_count, + layers: 0..desc.array_layer_count(), + }, + label: desc.label.to_string(), + tracking_data: TrackingData::new(device.tracker_indices.textures.clone()), + clear_mode: RwLock::new(rank::TEXTURE_CLEAR_MODE, clear_mode), + views: Mutex::new(rank::TEXTURE_VIEWS, Vec::new()), + bind_groups: Mutex::new(rank::TEXTURE_BIND_GROUPS, Vec::new()), + } + } /// Checks that the given texture usage contains the required texture usage, /// returns an error otherwise. pub(crate) fn check_usage( @@ -1041,16 +1075,6 @@ impl Texture { .ok_or_else(|| DestroyedResourceError(self.error_ident())) } - pub(crate) fn check_destroyed<'a>( - &'a self, - guard: &'a SnatchGuard, - ) -> Result<(), DestroyedResourceError> { - self.inner - .get(guard) - .map(|_| ()) - .ok_or_else(|| DestroyedResourceError(self.error_ident())) - } - pub(crate) fn inner_mut<'a>( &'a self, guard: &'a mut ExclusiveSnatchGuard, diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index 5b9de27a45..f2875b3542 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -1,4 +1,3 @@ -use std::ops; use std::sync::Arc; use wgt::Backend; @@ -55,15 +54,6 @@ where kind: &'static str, } -impl ops::Index> for Storage -where - T: StorageItem, -{ - type Output = Arc; - fn index(&self, id: Id) -> &Arc { - self.get(id).unwrap() - } -} impl Storage where T: StorageItem, @@ -80,18 +70,6 @@ impl Storage where T: StorageItem, { - #[allow(dead_code)] - pub(crate) fn contains(&self, id: Id) -> bool { - let (index, epoch, _) = id.unzip(); - match self.map.get(index as usize) { - Some(&Element::Vacant) => false, - Some(&Element::Occupied(_, storage_epoch) | &Element::Error(storage_epoch)) => { - storage_epoch == epoch - } - None => false, - } - } - /// Get a reference to an item behind a potentially invalid ID. /// Panics if there is an epoch mismatch, or the entry is empty. pub(crate) fn get(&self, id: Id) -> Result<&Arc, InvalidId> { diff --git a/wgpu-core/src/track/buffer.rs b/wgpu-core/src/track/buffer.rs index 6c0d1714f3..8a899ef85c 100644 --- a/wgpu-core/src/track/buffer.rs +++ b/wgpu-core/src/track/buffer.rs @@ -5,7 +5,7 @@ * one subresource, they have no selector. !*/ -use std::{borrow::Cow, marker::PhantomData, sync::Arc}; +use std::{marker::PhantomData, sync::Arc}; use super::{PendingTransition, ResourceTracker, TrackerIndex}; use crate::{ @@ -171,9 +171,7 @@ impl BufferUsageScope { index as _, index, BufferStateProvider::Direct { state }, - ResourceMetadataProvider::Direct { - resource: Cow::Borrowed(resource), - }, + ResourceMetadataProvider::Direct { resource }, )? }; } @@ -247,9 +245,7 @@ impl BufferUsageScope { index as _, index, BufferStateProvider::Direct { state: new_state }, - ResourceMetadataProvider::Direct { - resource: Cow::Owned(buffer.clone()), - }, + ResourceMetadataProvider::Direct { resource: buffer }, )?; } @@ -387,7 +383,7 @@ impl BufferTracker { /// /// If the ID is higher than the length of internal vectors, /// the vectors will be extended. A call to set_size is not needed. - pub fn insert_single(&mut self, resource: Arc>, state: BufferUses) { + pub fn insert_single(&mut self, resource: &Arc>, state: BufferUses) { let index = resource.tracker_index().as_usize(); self.allow_index(index); @@ -408,9 +404,7 @@ impl BufferTracker { index, BufferStateProvider::Direct { state }, None, - ResourceMetadataProvider::Direct { - resource: Cow::Owned(resource), - }, + ResourceMetadataProvider::Direct { resource }, ) } } @@ -441,9 +435,7 @@ impl BufferTracker { index, BufferStateProvider::Direct { state }, None, - ResourceMetadataProvider::Direct { - resource: Cow::Owned(buffer.clone()), - }, + ResourceMetadataProvider::Direct { resource: buffer }, &mut self.temp, ) }; diff --git a/wgpu-core/src/track/metadata.rs b/wgpu-core/src/track/metadata.rs index d412fc71ac..cc9e297839 100644 --- a/wgpu-core/src/track/metadata.rs +++ b/wgpu-core/src/track/metadata.rs @@ -1,7 +1,7 @@ //! The `ResourceMetadata` type. use bit_vec::BitVec; -use std::{borrow::Cow, mem, sync::Arc}; +use std::{mem, sync::Arc}; use wgt::strict_assert; /// A set of resources, holding a `Arc` and epoch for each member. @@ -176,7 +176,7 @@ impl ResourceMetadata { /// trackers can get new resource metadata from. pub(super) enum ResourceMetadataProvider<'a, T> { /// Comes directly from explicit values. - Direct { resource: Cow<'a, Arc> }, + Direct { resource: &'a Arc }, /// Comes from another metadata tracker. Indirect { metadata: &'a ResourceMetadata }, } diff --git a/wgpu-core/src/track/stateless.rs b/wgpu-core/src/track/stateless.rs index 2f4f297779..903dc21961 100644 --- a/wgpu-core/src/track/stateless.rs +++ b/wgpu-core/src/track/stateless.rs @@ -171,22 +171,6 @@ impl StatelessTracker { unsafe { self.metadata.insert(index, resource) } } - /// Adds the given resource to the tracker. - /// - /// If the ID is higher than the length of internal vectors, - /// the vectors will be extended. A call to set_size is not needed. - pub fn add_single(&mut self, resource: &Arc) { - let index = resource.tracker_index().as_usize(); - - self.allow_index(index); - - self.tracker_assert_in_bounds(index); - - unsafe { - self.metadata.insert(index, resource.clone()); - } - } - /// Adds the given resources from the given tracker. /// /// If the ID is higher than the length of internal vectors, diff --git a/wgpu-core/src/track/texture.rs b/wgpu-core/src/track/texture.rs index 4884195d4b..742af97c50 100644 --- a/wgpu-core/src/track/texture.rs +++ b/wgpu-core/src/track/texture.rs @@ -40,7 +40,7 @@ use naga::FastHashMap; use wgt::{strict_assert, strict_assert_eq}; -use std::{borrow::Cow, iter, marker::PhantomData, ops::Range, sync::Arc, vec::Drain}; +use std::{iter, marker::PhantomData, ops::Range, sync::Arc, vec::Drain}; /// Specifies a particular set of subresources in a texture. #[derive(Clone, Debug, PartialEq, Eq)] @@ -382,9 +382,7 @@ impl TextureUsageScope { &mut self.metadata, index, TextureStateProvider::from_option(selector, new_state), - ResourceMetadataProvider::Direct { - resource: Cow::Borrowed(texture), - }, + ResourceMetadataProvider::Direct { resource: texture }, )? }; @@ -537,7 +535,7 @@ impl TextureTracker { /// /// If the ID is higher than the length of internal vectors, /// the vectors will be extended. A call to set_size is not needed. - pub fn insert_single(&mut self, resource: Arc>, usage: TextureUses) { + pub fn insert_single(&mut self, resource: &Arc>, usage: TextureUses) { let index = resource.tracker_index().as_usize(); self.allow_index(index); @@ -559,9 +557,7 @@ impl TextureTracker { index, TextureStateProvider::KnownSingle { state: usage }, None, - ResourceMetadataProvider::Direct { - resource: Cow::Owned(resource), - }, + ResourceMetadataProvider::Direct { resource }, ) }; } @@ -597,9 +593,7 @@ impl TextureTracker { state: new_state, }, None, - ResourceMetadataProvider::Direct { - resource: Cow::Owned(texture.clone()), - }, + ResourceMetadataProvider::Direct { resource: texture }, &mut self.temp, ) }