diff --git a/player/src/bin/play.rs b/player/src/bin/play.rs index ce0b4c3bd4..0429b4bcb6 100644 --- a/player/src/bin/play.rs +++ b/player/src/bin/play.rs @@ -49,7 +49,7 @@ fn main() { IdentityPassThroughFactory, wgt::InstanceDescriptor::default(), ); - let mut command_buffer_id_manager = wgc::identity::IdentityManager::default(); + let mut command_buffer_id_manager = wgc::identity::IdentityManager::new(); #[cfg(feature = "winit")] let surface = global.instance_create_surface( diff --git a/player/src/lib.rs b/player/src/lib.rs index fa6ec72317..340f6e2be6 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -8,39 +8,23 @@ #![cfg(not(target_arch = "wasm32"))] #![warn(unsafe_op_in_unsafe_fn)] -use wgc::device::trace; +use wgc::{device::trace, identity::IdentityManager}; -use std::{borrow::Cow, fmt::Debug, fs, marker::PhantomData, path::Path}; +use std::{borrow::Cow, fs, path::Path, sync::Arc}; -#[derive(Debug)] -pub struct IdentityPassThrough(PhantomData); +pub struct IdentityPassThroughFactory; -impl wgc::identity::IdentityHandler - for IdentityPassThrough -{ +impl wgc::identity::IdentityHandlerFactory for IdentityPassThroughFactory { type Input = I; - fn process(&self, id: I, backend: wgt::Backend) -> I { - let (index, epoch, _backend) = id.unzip(); - I::zip(index, epoch, backend) + fn spawn(&self) -> Option>> { + None } - fn free(&self, _id: I) {} -} - -pub struct IdentityPassThroughFactory; -impl wgc::identity::IdentityHandlerFactory - for IdentityPassThroughFactory -{ - type Filter = IdentityPassThrough; - fn spawn(&self) -> Self::Filter { - IdentityPassThrough(PhantomData) - } -} -impl wgc::identity::GlobalIdentityHandlerFactory for IdentityPassThroughFactory { - fn ids_are_generated_in_wgpu() -> bool { - false + fn input_to_id(id_in: Self::Input) -> I { + id_in } } +impl wgc::identity::GlobalIdentityHandlerFactory for IdentityPassThroughFactory {} pub trait GlobalPlay { fn encode_commands( @@ -53,7 +37,7 @@ pub trait GlobalPlay { device: wgc::id::DeviceId, action: trace::Action, dir: &Path, - comb_manager: &mut wgc::identity::IdentityManager, + comb_manager: &mut wgc::identity::IdentityManager, ); } @@ -168,7 +152,7 @@ impl GlobalPlay for wgc::global::Global { device: wgc::id::DeviceId, action: trace::Action, dir: &Path, - comb_manager: &mut wgc::identity::IdentityManager, + comb_manager: &mut wgc::identity::IdentityManager, ) { use wgc::device::trace::Action; log::debug!("action {:?}", action); @@ -390,7 +374,7 @@ impl GlobalPlay for wgc::global::Global { let (encoder, error) = self.device_create_command_encoder::( device, &wgt::CommandEncoderDescriptor { label: None }, - comb_manager.alloc(device.backend()), + comb_manager.process(device.backend()), ); if let Some(e) = error { panic!("{:?}", e); diff --git a/player/tests/test.rs b/player/tests/test.rs index 2cfa030101..e3a2a6a796 100644 --- a/player/tests/test.rs +++ b/player/tests/test.rs @@ -100,7 +100,7 @@ impl Test<'_> { panic!("{:?}", e); } - let mut command_buffer_id_manager = wgc::identity::IdentityManager::default(); + let mut command_buffer_id_manager = wgc::identity::IdentityManager::new(); println!("\t\t\tRunning..."); for action in self.actions { wgc::gfx_select!(device_id => global.process(device_id, action, dir, &mut command_buffer_id_manager)); diff --git a/tests/src/lib.rs b/tests/src/lib.rs index 51b067fc26..91f531b76a 100644 --- a/tests/src/lib.rs +++ b/tests/src/lib.rs @@ -39,6 +39,7 @@ async fn initialize_device( } pub struct TestingContext { + pub instance: Instance, pub adapter: Adapter, pub adapter_info: wgt::AdapterInfo, pub adapter_downlevel_capabilities: wgt::DownlevelCapabilities, @@ -210,7 +211,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te let _test_guard = isolation::OneTestPerProcessGuard::new(); - let (adapter, _surface_guard) = initialize_adapter(); + let (instance, adapter, _surface_guard) = initialize_adapter(); let adapter_info = adapter.get_info(); let adapter_lowercase_name = adapter_info.name.to_lowercase(); @@ -256,6 +257,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te )); let context = TestingContext { + instance, adapter, adapter_info: adapter_info.clone(), adapter_downlevel_capabilities, @@ -375,7 +377,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te } } -fn initialize_adapter() -> (Adapter, SurfaceGuard) { +fn initialize_adapter() -> (Instance, Adapter, SurfaceGuard) { let backends = wgpu::util::backend_bits_from_env().unwrap_or_else(Backends::all); let dx12_shader_compiler = wgpu::util::dx12_shader_compiler_from_env().unwrap_or_default(); let gles_minor_version = wgpu::util::gles_minor_version_from_env().unwrap_or_default(); @@ -440,7 +442,7 @@ fn initialize_adapter() -> (Adapter, SurfaceGuard) { )) .expect("could not find suitable adapter on the system"); - (adapter, surface_guard) + (instance, adapter, surface_guard) } struct SurfaceGuard { diff --git a/tests/tests/mem_leaks.rs b/tests/tests/mem_leaks.rs new file mode 100644 index 0000000000..2db005c4e0 --- /dev/null +++ b/tests/tests/mem_leaks.rs @@ -0,0 +1,249 @@ +use std::num::NonZeroU64; + +use wasm_bindgen_test::*; +use wgpu::util::DeviceExt; + +use wgpu_test::{initialize_test, TestParameters, TestingContext}; + +#[cfg(any( + not(target_arch = "wasm32"), + target_os = "emscripten", + feature = "webgl" +))] +fn draw_test_with_reports( + ctx: TestingContext, + expected: &[u32], + function: impl FnOnce(&mut wgpu::RenderPass<'_>), +) { + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.adapters.num_allocated, 1); + assert_eq!(report.devices.num_allocated, 1); + assert_eq!(report.queues.num_allocated, 1); + + let shader = ctx + .device + .create_shader_module(wgpu::include_wgsl!("./vertex_indices/draw.vert.wgsl")); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.shader_modules.num_allocated, 1); + + let bgl = ctx + .device + .create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + label: None, + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + ty: wgpu::BindingType::Buffer { + ty: wgpu::BufferBindingType::Storage { read_only: false }, + has_dynamic_offset: false, + min_binding_size: NonZeroU64::new(4), + }, + visibility: wgpu::ShaderStages::VERTEX, + count: None, + }], + }); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.buffers.num_allocated, 0); + assert_eq!(report.bind_groups.num_allocated, 0); + assert_eq!(report.bind_group_layouts.num_allocated, 1); + + let buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: 4 * expected.len() as u64, + usage: wgpu::BufferUsages::COPY_SRC + | wgpu::BufferUsages::STORAGE + | wgpu::BufferUsages::MAP_READ, + mapped_at_creation: false, + }); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.buffers.num_allocated, 1); + + let bg = ctx.device.create_bind_group(&wgpu::BindGroupDescriptor { + label: None, + layout: &bgl, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: buffer.as_entire_binding(), + }], + }); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.buffers.num_allocated, 1); + assert_eq!(report.bind_groups.num_allocated, 1); + assert_eq!(report.bind_group_layouts.num_allocated, 1); + + let ppl = ctx + .device + .create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { + label: None, + bind_group_layouts: &[&bgl], + push_constant_ranges: &[], + }); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.pipeline_layouts.num_allocated, 1); + assert_eq!(report.render_pipelines.num_allocated, 0); + assert_eq!(report.compute_pipelines.num_allocated, 0); + + let pipeline = ctx + .device + .create_render_pipeline(&wgpu::RenderPipelineDescriptor { + label: None, + layout: Some(&ppl), + vertex: wgpu::VertexState { + buffers: &[], + entry_point: "vs_main", + module: &shader, + }, + primitive: wgpu::PrimitiveState::default(), + depth_stencil: None, + multisample: wgpu::MultisampleState::default(), + fragment: Some(wgpu::FragmentState { + entry_point: "fs_main", + module: &shader, + targets: &[Some(wgpu::ColorTargetState { + format: wgpu::TextureFormat::Rgba8Unorm, + blend: None, + write_mask: wgpu::ColorWrites::ALL, + })], + }), + multiview: None, + }); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.buffers.num_allocated, 1); + assert_eq!(report.bind_groups.num_allocated, 1); + assert_eq!(report.bind_group_layouts.num_allocated, 1); + assert_eq!(report.pipeline_layouts.num_allocated, 1); + assert_eq!(report.render_pipelines.num_allocated, 1); + assert_eq!(report.compute_pipelines.num_allocated, 0); + + let texture = ctx.device.create_texture_with_data( + &ctx.queue, + &wgpu::TextureDescriptor { + label: Some("dummy"), + size: wgpu::Extent3d { + width: 1, + height: 1, + depth_or_array_layers: 1, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: wgpu::TextureFormat::Rgba8Unorm, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }, + &[0, 0, 0, 1], + ); + let texture_view = texture.create_view(&wgpu::TextureViewDescriptor::default()); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.buffers.num_allocated, 1); + assert_eq!(report.texture_views.num_allocated, 1); + assert_eq!(report.textures.num_allocated, 1); + + drop(texture); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.buffers.num_allocated, 1); + assert_eq!(report.texture_views.num_allocated, 1); + assert_eq!(report.textures.num_allocated, 1); + assert_eq!(report.textures.num_kept_from_user, 0); + + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.command_buffers.num_allocated, 1); + assert_eq!(report.buffers.num_allocated, 1); + + let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: None, + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + ops: wgpu::Operations::default(), + resolve_target: None, + view: &texture_view, + })], + depth_stencil_attachment: None, + timestamp_writes: None, + occlusion_query_set: None, + }); + + rpass.set_pipeline(&pipeline); + rpass.set_bind_group(0, &bg, &[]); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.buffers.num_allocated, 1); + assert_eq!(report.bind_groups.num_allocated, 1); + assert_eq!(report.bind_group_layouts.num_allocated, 1); + assert_eq!(report.pipeline_layouts.num_allocated, 1); + assert_eq!(report.render_pipelines.num_allocated, 1); + assert_eq!(report.compute_pipelines.num_allocated, 0); + assert_eq!(report.command_buffers.num_allocated, 1); + assert_eq!(report.render_bundles.num_allocated, 0); + assert_eq!(report.texture_views.num_allocated, 1); + assert_eq!(report.textures.num_allocated, 1); + + function(&mut rpass); + + drop(rpass); + drop(pipeline); + drop(texture_view); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.command_buffers.num_allocated, 1); + assert_eq!(report.render_pipelines.num_allocated, 1); + assert_eq!(report.render_pipelines.num_kept_from_user, 0); + assert_eq!(report.texture_views.num_allocated, 1); + assert_eq!(report.texture_views.num_kept_from_user, 0); + assert_eq!(report.textures.num_allocated, 1); + assert_eq!(report.textures.num_kept_from_user, 0); + + ctx.queue.submit(Some(encoder.finish())); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.command_buffers.num_allocated, 0); + + ctx.device.poll(wgpu::Maintain::Wait); + + let global_report = ctx.instance.generate_report(); + let report = global_report.hub_report(); + assert_eq!(report.render_pipelines.num_allocated, 0); + assert_eq!(report.buffers.num_allocated, 1); + assert_eq!(report.bind_groups.num_allocated, 1); + assert_eq!(report.bind_group_layouts.num_allocated, 1); + assert_eq!(report.pipeline_layouts.num_allocated, 1); + assert_eq!(report.texture_views.num_allocated, 0); +} + +#[test] +#[wasm_bindgen_test] +#[cfg(any( + not(target_arch = "wasm32"), + target_os = "emscripten", + feature = "webgl" +))] +fn simple_draw_leaks() { + initialize_test(TestParameters::default().test_features_limits(), |ctx| { + draw_test_with_reports(ctx, &[0, 1, 2, 3, 4, 5], |cmb| { + cmb.draw(0..6, 0..1); + }) + }) +} diff --git a/tests/tests/root.rs b/tests/tests/root.rs index b376ab4981..fdab9ad27b 100644 --- a/tests/tests/root.rs +++ b/tests/tests/root.rs @@ -15,6 +15,7 @@ mod encoder; mod example_wgsl; mod external_texture; mod instance; +mod mem_leaks; mod occlusion_query; mod partially_bounded_arrays; mod poll; diff --git a/wgpu-core/src/binding_model.rs b/wgpu-core/src/binding_model.rs index 85bbe231a9..e4d389703e 100644 --- a/wgpu-core/src/binding_model.rs +++ b/wgpu-core/src/binding_model.rs @@ -847,8 +847,8 @@ pub struct BindGroup { pub(crate) layout: Arc>, pub(crate) info: ResourceInfo, pub(crate) used: BindGroupStates, - pub(crate) used_buffer_ranges: Vec, - pub(crate) used_texture_ranges: Vec, + pub(crate) used_buffer_ranges: Vec>, + pub(crate) used_texture_ranges: Vec>, pub(crate) dynamic_binding_info: Vec, /// Actual binding sizes for buffers that don't have `min_binding_size` /// specified in BGL. Listed in the order of iteration of `BGL.entries`. diff --git a/wgpu-core/src/command/bundle.rs b/wgpu-core/src/command/bundle.rs index 8beb9fec38..0da78e04bd 100644 --- a/wgpu-core/src/command/bundle.rs +++ b/wgpu-core/src/command/bundle.rs @@ -93,12 +93,9 @@ use crate::{ hal_api::HalApi, hub::Hub, id::{self, RenderBundleId}, - identity::GlobalIdentityHandlerFactory, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, pipeline::{self, PipelineFlags, RenderPipeline}, - resource, resource::{Resource, ResourceInfo}, - storage::Storage, track::RenderBundleScope, validation::check_buffer_usage, Label, LabelHelpers, @@ -253,11 +250,11 @@ impl RenderBundleEncoder { /// and accumulate buffer and texture initialization actions. /// /// [`ExecuteBundle`]: RenderCommand::ExecuteBundle - pub(crate) fn finish( + pub(crate) fn finish( self, desc: &RenderBundleDescriptor, device: &Arc>, - hub: &Hub, + hub: &Hub, ) -> Result, RenderBundleError> { let bind_group_guard = hub.bind_groups.read(); let pipeline_guard = hub.render_pipelines.read(); @@ -351,7 +348,7 @@ impl RenderBundleEncoder { unsafe { state .trackers - .merge_bind_group(&*texture_guard, &bind_group.used) + .merge_bind_group(&bind_group.used) .map_pass_err(scope)? }; //Note: stateless trackers are not merged: the lifetime reference @@ -402,7 +399,7 @@ impl RenderBundleEncoder { size, } => { let scope = PassErrorScope::SetIndexBuffer(buffer_id); - let buffer: &resource::Buffer = state + let buffer = state .trackers .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDEX) @@ -417,7 +414,7 @@ impl RenderBundleEncoder { None => buffer.size, }; buffer_memory_init_actions.extend(buffer.initialization_status.read().create_action( - buffer_id, + buffer, offset..end, MemoryInitKind::NeedsInitializedMemory, )); @@ -430,7 +427,7 @@ impl RenderBundleEncoder { size, } => { let scope = PassErrorScope::SetVertexBuffer(buffer_id); - let buffer: &resource::Buffer = state + let buffer = state .trackers .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::VERTEX) @@ -445,7 +442,7 @@ impl RenderBundleEncoder { None => buffer.size, }; buffer_memory_init_actions.extend(buffer.initialization_status.read().create_action( - buffer_id, + buffer, offset..end, MemoryInitKind::NeedsInitializedMemory, )); @@ -565,7 +562,7 @@ impl RenderBundleEncoder { let pipeline = state.pipeline(scope)?; let used_bind_groups = pipeline.used_bind_groups; - let buffer: &resource::Buffer = state + let buffer = state .trackers .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) @@ -576,7 +573,7 @@ impl RenderBundleEncoder { .map_pass_err(scope)?; buffer_memory_init_actions.extend(buffer.initialization_status.read().create_action( - buffer_id, + buffer, offset..(offset + mem::size_of::() as u64), MemoryInitKind::NeedsInitializedMemory, )); @@ -603,7 +600,7 @@ impl RenderBundleEncoder { let pipeline = state.pipeline(scope)?; let used_bind_groups = pipeline.used_bind_groups; - let buffer: &resource::Buffer = state + let buffer = state .trackers .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) @@ -614,7 +611,7 @@ impl RenderBundleEncoder { .map_pass_err(scope)?; buffer_memory_init_actions.extend(buffer.initialization_status.read().create_action( - buffer_id, + buffer, offset..(offset + mem::size_of::() as u64), MemoryInitKind::NeedsInitializedMemory, )); @@ -735,8 +732,8 @@ pub struct RenderBundle { pub(super) is_stencil_read_only: bool, pub(crate) device: Arc>, pub(crate) used: RenderBundleScope, - pub(super) buffer_memory_init_actions: Vec, - pub(super) texture_memory_init_actions: Vec, + pub(super) buffer_memory_init_actions: Vec>, + pub(super) texture_memory_init_actions: Vec>, pub(super) context: RenderPassContext, pub(crate) info: ResourceInfo, } @@ -768,13 +765,8 @@ impl RenderBundle { /// Note that the function isn't expected to fail, generally. /// 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, - bind_group_guard: &Storage, id::BindGroupId>, - pipeline_guard: &Storage, id::RenderPipelineId>, - buffer_guard: &Storage, id::BufferId>, - ) -> Result<(), ExecutionError> { + 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::>>; if let Some(ref label) = self.base.label { @@ -788,7 +780,7 @@ impl RenderBundle { num_dynamic_offsets, bind_group_id, } => { - let bind_group = bind_group_guard.get(bind_group_id).unwrap(); + let bind_group = trackers.bind_groups.get(bind_group_id).unwrap(); unsafe { raw.set_bind_group( pipeline_layout.as_ref().unwrap().raw(), @@ -800,7 +792,7 @@ impl RenderBundle { offsets = &offsets[num_dynamic_offsets as usize..]; } RenderCommand::SetPipeline(pipeline_id) => { - let pipeline = pipeline_guard.get(pipeline_id).unwrap(); + let pipeline = trackers.render_pipelines.get(pipeline_id).unwrap(); unsafe { raw.set_render_pipeline(pipeline.raw()) }; pipeline_layout = Some(pipeline.layout.clone()); @@ -811,12 +803,7 @@ impl RenderBundle { offset, size, } => { - let buffer = buffer_guard - .get(buffer_id) - .unwrap() - .raw - .as_ref() - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; + let buffer = trackers.buffers.get(buffer_id).unwrap().raw(); let bb = hal::BufferBinding { buffer, offset, @@ -830,12 +817,7 @@ impl RenderBundle { offset, size, } => { - let buffer = buffer_guard - .get(buffer_id) - .unwrap() - .raw - .as_ref() - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; + let buffer = trackers.buffers.get(buffer_id).unwrap().raw(); let bb = hal::BufferBinding { buffer, offset, @@ -913,12 +895,7 @@ impl RenderBundle { count: None, indexed: false, } => { - let buffer = buffer_guard - .get(buffer_id) - .unwrap() - .raw - .as_ref() - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; + let buffer = trackers.buffers.get(buffer_id).unwrap().raw(); unsafe { raw.draw_indirect(buffer, offset, 1) }; } RenderCommand::MultiDrawIndirect { @@ -927,12 +904,7 @@ impl RenderBundle { count: None, indexed: true, } => { - let buffer = buffer_guard - .get(buffer_id) - .unwrap() - .raw - .as_ref() - .ok_or(ExecutionError::DestroyedBuffer(buffer_id))?; + let buffer = trackers.buffers.get(buffer_id).unwrap().raw(); unsafe { raw.draw_indexed_indirect(buffer, offset, 1) }; } RenderCommand::MultiDrawIndirect { .. } diff --git a/wgpu-core/src/command/clear.rs b/wgpu-core/src/command/clear.rs index 693882a6a9..26221d19f3 100644 --- a/wgpu-core/src/command/clear.rs +++ b/wgpu-core/src/command/clear.rs @@ -1,4 +1,4 @@ -use std::ops::Range; +use std::{ops::Range, sync::Arc}; #[cfg(feature = "trace")] use crate::device::trace::Command as TraceCommand; @@ -10,8 +10,7 @@ use crate::{ id::{BufferId, CommandEncoderId, DeviceId, TextureId}, identity::GlobalIdentityHandlerFactory, init_tracker::{MemoryInitKind, TextureInitRange}, - resource::{Texture, TextureClearMode}, - storage::Storage, + resource::{Resource, Texture, TextureClearMode}, track::{TextureSelector, TextureTracker}, }; @@ -94,10 +93,13 @@ impl Global { let (dst_buffer, dst_pending) = { let buffer_guard = hub.buffers.read(); + let dst_buffer = buffer_guard + .get(dst) + .map_err(|_| ClearError::InvalidBuffer(dst))?; cmd_buf_data .trackers .buffers - .set_single(&*buffer_guard, dst, hal::BufferUses::COPY_DST) + .set_single(dst_buffer, hal::BufferUses::COPY_DST) .ok_or(ClearError::InvalidBuffer(dst))? }; let dst_raw = dst_buffer @@ -138,7 +140,7 @@ impl Global { // Mark dest as initialized. cmd_buf_data.buffer_memory_init_actions.extend( dst_buffer.initialization_status.read().create_action( - dst, + &dst_buffer, offset..end, MemoryInitKind::ImplicitlyInitialized, ), @@ -221,10 +223,9 @@ impl Global { let device = &cmd_buf.device; let (encoder, tracker) = cmd_buf_data.open_encoder_and_tracker(); - let texture_guard = hub.textures.read(); + clear_texture( - &*texture_guard, - dst, + &dst_texture, TextureInitRange { mip_range: subresource_mip_range, layer_range: subresource_layer_range, @@ -238,22 +239,19 @@ impl Global { } pub(crate) fn clear_texture( - storage: &Storage, TextureId>, - dst_texture_id: TextureId, + dst_texture: &Arc>, range: TextureInitRange, encoder: &mut A::CommandEncoder, texture_tracker: &mut TextureTracker, alignments: &hal::Alignments, zero_buffer: &A::Buffer, ) -> Result<(), ClearError> { - let dst_texture = &storage[dst_texture_id]; - let dst_raw = dst_texture .inner .as_ref() .unwrap() .as_raw() - .ok_or(ClearError::InvalidTexture(dst_texture_id))?; + .ok_or_else(|| ClearError::InvalidTexture(dst_texture.as_info().id()))?; // Issue the right barrier. let clear_usage = match *dst_texture.clear_mode.read() { @@ -265,7 +263,9 @@ pub(crate) fn clear_texture( hal::TextureUses::COLOR_TARGET } TextureClearMode::None => { - return Err(ClearError::NoValidTextureClearMode(dst_texture_id)); + return Err(ClearError::NoValidTextureClearMode( + dst_texture.as_info().id(), + )); } }; @@ -288,7 +288,7 @@ pub(crate) fn clear_texture( // clear_texture api in order to remove this check and call the cheaper // change_replace_tracked whenever possible. let dst_barrier = texture_tracker - .set_single(dst_texture, dst_texture_id, selector, clear_usage) + .set_single(dst_texture, selector, clear_usage) .unwrap() .map(|pending| pending.into_hal(dst_texture)); unsafe { @@ -312,7 +312,9 @@ pub(crate) fn clear_texture( clear_texture_via_render_passes(dst_texture, range, is_color, encoder)? } TextureClearMode::None => { - return Err(ClearError::NoValidTextureClearMode(dst_texture_id)); + return Err(ClearError::NoValidTextureClearMode( + dst_texture.as_info().id(), + )); } } Ok(()) diff --git a/wgpu-core/src/command/compute.rs b/wgpu-core/src/command/compute.rs index 96fb09daf7..2c8d8a5146 100644 --- a/wgpu-core/src/command/compute.rs +++ b/wgpu-core/src/command/compute.rs @@ -18,7 +18,7 @@ use crate::{ identity::GlobalIdentityHandlerFactory, init_tracker::MemoryInitKind, pipeline, - resource::{self, Buffer, Texture}, + resource::{self}, storage::Storage, track::{Tracker, UsageConflict, UsageScope}, validation::{check_buffer_usage, MissingBufferUsageError}, @@ -306,15 +306,10 @@ impl State { raw_encoder: &mut A::CommandEncoder, base_trackers: &mut Tracker, bind_group_guard: &Storage, id::BindGroupId>, - buffer_guard: &Storage, id::BufferId>, - texture_guard: &Storage, id::TextureId>, indirect_buffer: Option, ) -> Result<(), UsageConflict> { for id in self.binder.list_active() { - unsafe { - self.scope - .merge_bind_group(texture_guard, &bind_group_guard[id].used)? - }; + unsafe { self.scope.merge_bind_group(&bind_group_guard[id].used)? }; // Note: stateless trackers are not merged: the lifetime reference // is held to the bind group itself. } @@ -322,7 +317,6 @@ impl State { for id in self.binder.list_active() { unsafe { base_trackers.set_and_remove_from_usage_scope_sparse( - texture_guard, &mut self.scope, &bind_group_guard[id].used, ) @@ -338,7 +332,7 @@ impl State { log::trace!("Encoding dispatch barriers"); - CommandBuffer::drain_barriers(raw_encoder, base_trackers, buffer_guard, texture_guard); + CommandBuffer::drain_barriers(raw_encoder, base_trackers); Ok(()) } } @@ -511,20 +505,18 @@ impl Global { .map_pass_err(scope)?; buffer_memory_init_actions.extend( - bind_group.used_buffer_ranges.iter().filter_map( - |action| match buffer_guard.get(action.id) { - Ok(buffer) => { - buffer.initialization_status.read().check_action(action) - } - Err(_) => None, - }, - ), + bind_group.used_buffer_ranges.iter().filter_map(|action| { + action + .buffer + .initialization_status + .read() + .check_action(action) + }), ); for action in bind_group.used_texture_ranges.iter() { - pending_discard_init_fixups.extend( - texture_memory_actions.register_init_action(action, &texture_guard), - ); + pending_discard_init_fixups + .extend(texture_memory_actions.register_init_action(action)); } let pipeline_layout = &state.binder.pipeline_layout; @@ -662,14 +654,7 @@ impl Global { state.is_ready().map_pass_err(scope)?; state - .flush_states( - raw, - &mut intermediate_trackers, - &*bind_group_guard, - &*buffer_guard, - &*texture_guard, - None, - ) + .flush_states(raw, &mut intermediate_trackers, &*bind_group_guard, None) .map_pass_err(scope)?; let groups_size_limit = cmd_buf.limits.max_compute_workgroups_per_dimension; @@ -703,7 +688,7 @@ impl Global { .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) .map_pass_err(scope)?; - let indirect_buffer: &Buffer = state + let indirect_buffer = state .scope .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) @@ -731,7 +716,7 @@ impl Global { buffer_memory_init_actions.extend( indirect_buffer.initialization_status.read().create_action( - buffer_id, + indirect_buffer, offset..(offset + stride), MemoryInitKind::NeedsInitializedMemory, ), @@ -742,8 +727,6 @@ impl Global { raw, &mut intermediate_trackers, &*bind_group_guard, - &*buffer_guard, - &*texture_guard, Some(buffer_id), ) .map_pass_err(scope)?; @@ -849,17 +832,10 @@ impl Global { fixup_discarded_surfaces( pending_discard_init_fixups.into_iter(), transit, - &texture_guard, &mut tracker.textures, device, ); - CommandBuffer::insert_barriers_from_tracker( - transit, - tracker, - &intermediate_trackers, - &*buffer_guard, - &*texture_guard, - ); + CommandBuffer::insert_barriers_from_tracker(transit, tracker, &intermediate_trackers); // Close the command buffer, and swap it with the previous. encoder.close_and_swap(); diff --git a/wgpu-core/src/command/memory_init.rs b/wgpu-core/src/command/memory_init.rs index dd70628479..f10c85e2be 100644 --- a/wgpu-core/src/command/memory_init.rs +++ b/wgpu-core/src/command/memory_init.rs @@ -1,14 +1,12 @@ -use std::{collections::hash_map::Entry, ops::Range, vec::Drain}; +use std::{collections::hash_map::Entry, ops::Range, sync::Arc, vec::Drain}; use hal::CommandEncoder; use crate::{ device::Device, hal_api::HalApi, - id::{self, TextureId}, init_tracker::*, - resource::{Buffer, Texture}, - storage::Storage, + resource::{Resource, Texture}, track::{TextureTracker, Tracker}, FastHashMap, }; @@ -18,31 +16,39 @@ use super::{clear::clear_texture, BakedCommands, DestroyedBufferError, Destroyed /// Surface that was discarded by `StoreOp::Discard` of a preceding renderpass. /// Any read access to this surface needs to be preceded by a texture initialization. #[derive(Clone)] -pub(crate) struct TextureSurfaceDiscard { - pub texture: TextureId, +pub(crate) struct TextureSurfaceDiscard { + pub texture: Arc>, pub mip_level: u32, pub layer: u32, } -pub(crate) type SurfacesInDiscardState = Vec; +pub(crate) type SurfacesInDiscardState = Vec>; -#[derive(Default)] -pub(crate) struct CommandBufferTextureMemoryActions { +pub(crate) struct CommandBufferTextureMemoryActions { /// The tracker actions that we need to be executed before the command /// buffer is executed. - init_actions: Vec, + init_actions: Vec>, /// All the discards that haven't been followed by init again within the /// command buffer i.e. everything in this list resets the texture init /// state *after* the command buffer execution - discards: Vec, + discards: Vec>, } -impl CommandBufferTextureMemoryActions { - pub(crate) fn drain_init_actions(&mut self) -> Drain { +impl Default for CommandBufferTextureMemoryActions { + fn default() -> Self { + Self { + init_actions: Default::default(), + discards: Default::default(), + } + } +} + +impl CommandBufferTextureMemoryActions { + pub(crate) fn drain_init_actions(&mut self) -> Drain> { self.init_actions.drain(..) } - pub(crate) fn discard(&mut self, discard: TextureSurfaceDiscard) { + pub(crate) fn discard(&mut self, discard: TextureSurfaceDiscard) { self.discards.push(discard); } @@ -50,11 +56,10 @@ impl CommandBufferTextureMemoryActions { // Returns previously discarded surface that need to be initialized *immediately* now. // Only returns a non-empty list if action is MemoryInitKind::NeedsInitializedMemory. #[must_use] - pub(crate) fn register_init_action( + pub(crate) fn register_init_action( &mut self, - action: &TextureInitTrackerAction, - texture_guard: &Storage, TextureId>, - ) -> SurfacesInDiscardState { + action: &TextureInitTrackerAction, + ) -> SurfacesInDiscardState { let mut immediately_necessary_clears = SurfacesInDiscardState::new(); // Note that within a command buffer we may stack arbitrary memory init @@ -64,18 +69,20 @@ impl CommandBufferTextureMemoryActions { // We don't need to add MemoryInitKind::NeedsInitializedMemory to // init_actions if a surface is part of the discard list. But that would // mean splitting up the action which is more than we'd win here. - self.init_actions - .extend(match texture_guard.get(action.id) { - Ok(texture) => texture.initialization_status.read().check_action(action), - Err(_) => return immediately_necessary_clears, // texture no longer exists - }); + self.init_actions.extend( + action + .texture + .initialization_status + .read() + .check_action(action), + ); // We expect very few discarded surfaces at any point in time which is // why a simple linear search is likely best. (i.e. most of the time // self.discards is empty!) let init_actions = &mut self.init_actions; self.discards.retain(|discarded_surface| { - if discarded_surface.texture == action.id + if discarded_surface.texture.as_info().id() == action.texture.as_info().id() && action.range.layer_range.contains(&discarded_surface.layer) && action .range @@ -89,7 +96,7 @@ impl CommandBufferTextureMemoryActions { // because it might have been uninitialized prior to // discarding init_actions.push(TextureInitTrackerAction { - id: discarded_surface.texture, + texture: discarded_surface.texture.clone(), range: TextureInitRange { mip_range: discarded_surface.mip_level ..(discarded_surface.mip_level + 1), @@ -109,20 +116,16 @@ impl CommandBufferTextureMemoryActions { // Shortcut for register_init_action when it is known that the action is an // implicit init, not requiring any immediate resource init. - pub(crate) fn register_implicit_init( + pub(crate) fn register_implicit_init( &mut self, - id: TextureId, + texture: &Arc>, range: TextureInitRange, - texture_guard: &Storage, TextureId>, ) { - let must_be_empty = self.register_init_action( - &TextureInitTrackerAction { - id, - range, - kind: MemoryInitKind::ImplicitlyInitialized, - }, - texture_guard, - ); + let must_be_empty = self.register_init_action(&TextureInitTrackerAction { + texture: texture.clone(), + range, + kind: MemoryInitKind::ImplicitlyInitialized, + }); assert!(must_be_empty.is_empty()); } } @@ -133,18 +136,16 @@ impl CommandBufferTextureMemoryActions { // Takes care of barriers as well! pub(crate) fn fixup_discarded_surfaces< A: HalApi, - InitIter: Iterator, + InitIter: Iterator>, >( inits: InitIter, encoder: &mut A::CommandEncoder, - texture_guard: &Storage, TextureId>, texture_tracker: &mut TextureTracker, device: &Device, ) { for init in inits { clear_texture( - texture_guard, - init.texture, + &init.texture, TextureInitRange { mip_range: init.mip_level..(init.mip_level + 1), layer_range: init.layer..(init.layer + 1), @@ -164,17 +165,13 @@ impl BakedCommands { pub(crate) fn initialize_buffer_memory( &mut self, device_tracker: &mut Tracker, - buffer_guard: &Storage, id::BufferId>, ) -> Result<(), DestroyedBufferError> { // Gather init ranges for each buffer so we can collapse them. // It is not possible to do this at an earlier point since previously // executed command buffer change the resource init state. let mut uninitialized_ranges_per_buffer = FastHashMap::default(); for buffer_use in self.buffer_memory_init_actions.drain(..) { - let buffer = buffer_guard - .get(buffer_use.id) - .map_err(|_| DestroyedBufferError(buffer_use.id))?; - let mut initialization_status = buffer.initialization_status.write(); + let mut initialization_status = buffer_use.buffer.initialization_status.write(); // align the end to 4 let end_remainder = buffer_use.range.end % wgt::COPY_BUFFER_ALIGNMENT; @@ -188,21 +185,22 @@ impl BakedCommands { match buffer_use.kind { MemoryInitKind::ImplicitlyInitialized => {} MemoryInitKind::NeedsInitializedMemory => { - match uninitialized_ranges_per_buffer.entry(buffer_use.id) { + match uninitialized_ranges_per_buffer.entry(buffer_use.buffer.as_info().id()) { Entry::Vacant(e) => { - e.insert( + e.insert(( + buffer_use.buffer.clone(), uninitialized_ranges.collect::>>(), - ); + )); } Entry::Occupied(mut e) => { - e.get_mut().extend(uninitialized_ranges); + e.get_mut().1.extend(uninitialized_ranges); } } } } } - for (buffer_id, mut ranges) in uninitialized_ranges_per_buffer { + for (buffer_id, (buffer, mut ranges)) in uninitialized_ranges_per_buffer { // Collapse touching ranges. ranges.sort_by_key(|r| r.start); for i in (1..ranges.len()).rev() { @@ -221,19 +219,16 @@ impl BakedCommands { // must already know about it. let transition = device_tracker .buffers - .set_single(buffer_guard, buffer_id, hal::BufferUses::COPY_DST) + .set_single(&buffer, hal::BufferUses::COPY_DST) .unwrap() .1; - let buffer = buffer_guard - .get(buffer_id) - .map_err(|_| DestroyedBufferError(buffer_id))?; let raw_buf = buffer.raw.as_ref().ok_or(DestroyedBufferError(buffer_id))?; unsafe { self.encoder.transition_buffers( transition - .map(|pending| pending.into_hal(buffer)) + .map(|pending| pending.into_hal(&buffer)) .into_iter(), ); } @@ -269,15 +264,11 @@ impl BakedCommands { pub(crate) fn initialize_texture_memory( &mut self, device_tracker: &mut Tracker, - texture_guard: &Storage, TextureId>, device: &Device, ) -> Result<(), DestroyedTextureError> { let mut ranges: Vec = Vec::new(); for texture_use in self.texture_memory_actions.drain_init_actions() { - let texture = texture_guard - .get(texture_use.id) - .map_err(|_| DestroyedTextureError(texture_use.id))?; - let mut initialization_status = texture.initialization_status.write(); + let mut initialization_status = texture_use.texture.initialization_status.write(); let use_range = texture_use.range; let affected_mip_trackers = initialization_status .mips @@ -307,8 +298,7 @@ impl BakedCommands { // TODO: Could we attempt some range collapsing here? for range in ranges.drain(..) { clear_texture( - texture_guard, - texture_use.id, + &texture_use.texture, range, &mut self.encoder, &mut device_tracker.textures, @@ -323,10 +313,8 @@ impl BakedCommands { // cmdbuf start, we discard init states for textures it left discarded // after its execution. for surface_discard in self.texture_memory_actions.discards.iter() { - let texture = texture_guard - .get(surface_discard.texture) - .map_err(|_| DestroyedTextureError(surface_discard.texture))?; - texture + surface_discard + .texture .initialization_status .write() .discard(surface_discard.mip_level, surface_discard.layer); diff --git a/wgpu-core/src/command/mod.rs b/wgpu-core/src/command/mod.rs index 12c11093f8..9dc8122a03 100644 --- a/wgpu-core/src/command/mod.rs +++ b/wgpu-core/src/command/mod.rs @@ -26,15 +26,7 @@ use crate::id::CommandBufferId; use crate::init_tracker::BufferInitTrackerAction; use crate::resource::{Resource, ResourceInfo}; use crate::track::{Tracker, UsageScope}; -use crate::{ - global::Global, - hal_api::HalApi, - id, - identity::GlobalIdentityHandlerFactory, - resource::{Buffer, Texture}, - storage::Storage, - Label, -}; +use crate::{global::Global, hal_api::HalApi, id, identity::GlobalIdentityHandlerFactory, Label}; use hal::CommandEncoder as _; use parking_lot::Mutex; @@ -104,8 +96,8 @@ pub struct BakedCommands { pub(crate) encoder: A::CommandEncoder, pub(crate) list: Vec, pub(crate) trackers: Tracker, - buffer_memory_init_actions: Vec, - texture_memory_actions: CommandBufferTextureMemoryActions, + buffer_memory_init_actions: Vec>, + texture_memory_actions: CommandBufferTextureMemoryActions, } pub(crate) struct DestroyedBufferError(pub id::BufferId); @@ -115,8 +107,8 @@ pub struct CommandBufferMutable { encoder: CommandEncoder, status: CommandEncoderStatus, pub(crate) trackers: Tracker, - buffer_memory_init_actions: Vec, - texture_memory_actions: CommandBufferTextureMemoryActions, + buffer_memory_init_actions: Vec>, + texture_memory_actions: CommandBufferTextureMemoryActions, pub(crate) pending_query_resets: QueryResetMap, #[cfg(feature = "trace")] pub(crate) commands: Option>, @@ -199,50 +191,33 @@ impl CommandBuffer { raw: &mut A::CommandEncoder, base: &mut Tracker, head: &Tracker, - buffer_guard: &Storage, id::BufferId>, - texture_guard: &Storage, id::TextureId>, ) { profiling::scope!("insert_barriers"); base.buffers.set_from_tracker(&head.buffers); - base.textures - .set_from_tracker(texture_guard, &head.textures); + base.textures.set_from_tracker(&head.textures); - Self::drain_barriers(raw, base, buffer_guard, texture_guard); + Self::drain_barriers(raw, base); } pub(crate) fn insert_barriers_from_scope( raw: &mut A::CommandEncoder, base: &mut Tracker, head: &UsageScope, - buffer_guard: &Storage, id::BufferId>, - texture_guard: &Storage, id::TextureId>, ) { profiling::scope!("insert_barriers"); base.buffers.set_from_usage_scope(&head.buffers); - base.textures - .set_from_usage_scope(texture_guard, &head.textures); + base.textures.set_from_usage_scope(&head.textures); - Self::drain_barriers(raw, base, buffer_guard, texture_guard); + Self::drain_barriers(raw, base); } - pub(crate) fn drain_barriers( - raw: &mut A::CommandEncoder, - base: &mut Tracker, - buffer_guard: &Storage, id::BufferId>, - texture_guard: &Storage, id::TextureId>, - ) { + pub(crate) fn drain_barriers(raw: &mut A::CommandEncoder, base: &mut Tracker) { profiling::scope!("drain_barriers"); - let buffer_barriers = base.buffers.drain().map(|pending| { - let buf = unsafe { buffer_guard.get_unchecked(pending.id) }; - pending.into_hal(buf) - }); - let texture_barriers = base.textures.drain().map(|pending| { - let tex = unsafe { texture_guard.get_unchecked(pending.id) }; - pending.into_hal(tex) - }); + let buffer_barriers = base.buffers.drain_transitions(); + let texture_barriers = base.textures.drain_transitions(); unsafe { raw.transition_buffers(buffer_barriers); @@ -252,13 +227,10 @@ impl CommandBuffer { } impl CommandBuffer { - fn get_encoder( - hub: &Hub, + fn get_encoder( + hub: &Hub, id: id::CommandEncoderId, - ) -> Result, CommandEncoderError> - where - G: GlobalIdentityHandlerFactory, - { + ) -> Result, CommandEncoderError> { let storage = hub.command_buffers.read(); match storage.get(id) { Ok(cmd_buf) => match cmd_buf.data.lock().as_ref().unwrap().status { diff --git a/wgpu-core/src/command/query.rs b/wgpu-core/src/command/query.rs index d3254ab5bc..3d4404b41e 100644 --- a/wgpu-core/src/command/query.rs +++ b/wgpu-core/src/command/query.rs @@ -422,9 +422,12 @@ impl Global { let (dst_buffer, dst_pending) = { let buffer_guard = hub.buffers.read(); + let dst_buffer = buffer_guard + .get(destination) + .map_err(|_| QueryError::InvalidBuffer(destination))?; tracker .buffers - .set_single(&*buffer_guard, destination, hal::BufferUses::COPY_DST) + .set_single(dst_buffer, hal::BufferUses::COPY_DST) .ok_or(QueryError::InvalidBuffer(destination))? }; let dst_barrier = dst_pending.map(|pending| pending.into_hal(&dst_buffer)); @@ -468,7 +471,7 @@ impl Global { // TODO(https://github.com/gfx-rs/wgpu/issues/3993): Need to track initialization state. buffer_memory_init_actions.extend(dst_buffer.initialization_status.read().create_action( - destination, + &dst_buffer, buffer_start_offset..buffer_end_offset, MemoryInitKind::ImplicitlyInitialized, )); diff --git a/wgpu-core/src/command/render.rs b/wgpu-core/src/command/render.rs index 9c30983f11..08dd5806be 100644 --- a/wgpu-core/src/command/render.rs +++ b/wgpu-core/src/command/render.rs @@ -43,6 +43,7 @@ use serde::Deserialize; #[cfg(any(feature = "serial-pass", feature = "trace"))] use serde::Serialize; +use std::sync::Arc; use std::{borrow::Cow, fmt, iter, marker::PhantomData, mem, num::NonZeroU32, ops::Range, str}; use super::{ @@ -683,16 +684,16 @@ where } } -struct RenderAttachment<'a> { - texture_id: &'a id::TextureId, +struct RenderAttachment<'a, A: HalApi> { + texture: Arc>, selector: &'a TextureSelector, usage: hal::TextureUses, } impl TextureView { - fn to_render_attachment(&self, usage: hal::TextureUses) -> RenderAttachment { + fn to_render_attachment(&self, usage: hal::TextureUses) -> RenderAttachment { RenderAttachment { - texture_id: &self.parent_id, + texture: self.parent.as_ref().unwrap().clone(), selector: &self.selector, usage, } @@ -706,13 +707,13 @@ struct RenderPassInfo<'a, A: HalApi> { context: RenderPassContext, usage_scope: UsageScope, /// All render attachments, including depth/stencil - render_attachments: AttachmentDataVec>, + render_attachments: AttachmentDataVec>, is_depth_read_only: bool, is_stencil_read_only: bool, extent: wgt::Extent3d, _phantom: PhantomData, - pending_discard_init_fixups: SurfacesInDiscardState, + pending_discard_init_fixups: SurfacesInDiscardState, divergent_discarded_depth_stencil_aspect: Option<(wgt::TextureAspect, &'a TextureView)>, multiview: Option, } @@ -720,27 +721,24 @@ struct RenderPassInfo<'a, A: HalApi> { impl<'a, A: HalApi> RenderPassInfo<'a, A> { fn add_pass_texture_init_actions( channel: &PassChannel, - texture_memory_actions: &mut CommandBufferTextureMemoryActions, + texture_memory_actions: &mut CommandBufferTextureMemoryActions, view: &TextureView, - texture_guard: &Storage, id::TextureId>, - pending_discard_init_fixups: &mut SurfacesInDiscardState, + pending_discard_init_fixups: &mut SurfacesInDiscardState, ) { if channel.load_op == LoadOp::Load { pending_discard_init_fixups.extend(texture_memory_actions.register_init_action( &TextureInitTrackerAction { - id: view.parent_id, + texture: view.parent.as_ref().unwrap().clone(), range: TextureInitRange::from(view.selector.clone()), // Note that this is needed even if the target is discarded, kind: MemoryInitKind::NeedsInitializedMemory, }, - texture_guard, )); } else if channel.store_op == StoreOp::Store { // Clear + Store texture_memory_actions.register_implicit_init( - view.parent_id, + view.parent.as_ref().unwrap(), TextureInitRange::from(view.selector.clone()), - texture_guard, ); } if channel.store_op == StoreOp::Discard { @@ -748,7 +746,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { // discard right away be alright since the texture can't be used // during the pass anyways texture_memory_actions.discard(TextureSurfaceDiscard { - texture: view.parent_id, + texture: view.parent.as_ref().unwrap().clone(), mip_level: view.selector.mips.start, layer: view.selector.layers.start, }); @@ -764,7 +762,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { occlusion_query_set: Option, encoder: &mut CommandEncoder, trackers: &mut Tracker, - texture_memory_actions: &mut CommandBufferTextureMemoryActions, + texture_memory_actions: &mut CommandBufferTextureMemoryActions, pending_query_resets: &mut QueryResetMap, view_guard: &'a Storage, id::TextureViewId>, buffer_guard: &'a Storage, id::BufferId>, @@ -779,7 +777,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { let mut is_depth_read_only = false; let mut is_stencil_read_only = false; - let mut render_attachments = AttachmentDataVec::::new(); + let mut render_attachments = AttachmentDataVec::>::new(); let mut discarded_surfaces = AttachmentDataVec::new(); let mut pending_discard_init_fixups = SurfacesInDiscardState::new(); let mut divergent_discarded_depth_stencil_aspect = None; @@ -881,7 +879,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { &at.depth, texture_memory_actions, view, - texture_guard, &mut pending_discard_init_fixups, ); } else if !ds_aspects.contains(hal::FormatAspects::DEPTH) { @@ -889,7 +886,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { &at.stencil, texture_memory_actions, view, - texture_guard, &mut pending_discard_init_fixups, ); } else { @@ -918,14 +914,11 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { at.depth.load_op == LoadOp::Load || at.stencil.load_op == LoadOp::Load; if need_init_beforehand { pending_discard_init_fixups.extend( - texture_memory_actions.register_init_action( - &TextureInitTrackerAction { - id: view.parent_id, - range: TextureInitRange::from(view.selector.clone()), - kind: MemoryInitKind::NeedsInitializedMemory, - }, - texture_guard, - ), + texture_memory_actions.register_init_action(&TextureInitTrackerAction { + texture: view.parent.as_ref().unwrap().clone(), + range: TextureInitRange::from(view.selector.clone()), + kind: MemoryInitKind::NeedsInitializedMemory, + }), ); } @@ -940,9 +933,8 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { if at.depth.store_op != at.stencil.store_op { if !need_init_beforehand { texture_memory_actions.register_implicit_init( - view.parent_id, + view.parent.as_ref().unwrap(), TextureInitRange::from(view.selector.clone()), - texture_guard, ); } divergent_discarded_depth_stencil_aspect = Some(( @@ -956,7 +948,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { } else if at.depth.store_op == StoreOp::Discard { // Both are discarded using the regular path. discarded_surfaces.push(TextureSurfaceDiscard { - texture: view.parent_id, + texture: view.parent.as_ref().unwrap().clone(), mip_level: view.selector.mips.start, layer: view.selector.layers.start, }); @@ -1023,7 +1015,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { &at.channel, texture_memory_actions, color_view, - texture_guard, &mut pending_discard_init_fixups, ); render_attachments @@ -1083,9 +1074,8 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { } texture_memory_actions.register_implicit_init( - resolve_view.parent_id, + resolve_view.parent.as_ref().unwrap(), TextureInitRange::from(resolve_view.selector.clone()), - texture_guard, ); render_attachments .push(resolve_view.to_render_attachment(hal::TextureUses::COLOR_TARGET)); @@ -1198,30 +1188,21 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> { fn finish( mut self, raw: &mut A::CommandEncoder, - texture_guard: &Storage, id::TextureId>, - ) -> Result<(UsageScope, SurfacesInDiscardState), RenderPassErrorInner> { + ) -> Result<(UsageScope, SurfacesInDiscardState), RenderPassErrorInner> { profiling::scope!("RenderPassInfo::finish"); unsafe { raw.end_render_pass(); } for ra in self.render_attachments { - if !texture_guard.contains(*ra.texture_id) { - return Err(RenderPassErrorInner::SurfaceTextureDropped); - } - let texture = &texture_guard[*ra.texture_id]; + let texture = &ra.texture; check_texture_usage(texture.desc.usage, TextureUsages::RENDER_ATTACHMENT)?; // the tracker set of the pass is always in "extend" mode unsafe { self.usage_scope .textures - .merge_single( - texture_guard, - *ra.texture_id, - Some(ra.selector.clone()), - ra.usage, - ) + .merge_single(texture, Some(ra.selector.clone()), ra.usage) .map_err(UsageConflict::from)? }; } @@ -1436,7 +1417,7 @@ impl Global { // merge the resource tracker in unsafe { info.usage_scope - .merge_bind_group(&*texture_guard, &bind_group.used) + .merge_bind_group(&bind_group.used) .map_pass_err(scope)?; } //Note: stateless trackers are not merged: the lifetime reference @@ -1444,18 +1425,16 @@ impl Global { buffer_memory_init_actions.extend( bind_group.used_buffer_ranges.iter().filter_map(|action| { - match buffer_guard.get(action.id) { - Ok(buffer) => { - buffer.initialization_status.read().check_action(action) - } - Err(_) => None, - } + action + .buffer + .initialization_status + .read() + .check_action(action) }), ); for action in bind_group.used_texture_ranges.iter() { - info.pending_discard_init_fixups.extend( - texture_memory_actions.register_init_action(action, &texture_guard), - ); + info.pending_discard_init_fixups + .extend(texture_memory_actions.register_init_action(action)); } let pipeline_layout = state.binder.pipeline_layout.clone(); @@ -1603,7 +1582,7 @@ impl Global { size, } => { let scope = PassErrorScope::SetIndexBuffer(buffer_id); - let buffer: &Buffer = info + let buffer = info .usage_scope .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDEX) @@ -1627,7 +1606,7 @@ impl Global { buffer_memory_init_actions.extend( buffer.initialization_status.read().create_action( - buffer_id, + buffer, offset..end, MemoryInitKind::NeedsInitializedMemory, ), @@ -1649,7 +1628,7 @@ impl Global { size, } => { let scope = PassErrorScope::SetVertexBuffer(buffer_id); - let buffer: &Buffer = info + let buffer = info .usage_scope .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::VERTEX) @@ -1678,7 +1657,7 @@ impl Global { buffer_memory_init_actions.extend( buffer.initialization_status.read().create_action( - buffer_id, + buffer, offset..(offset + vertex_state.total_size), MemoryInitKind::NeedsInitializedMemory, ), @@ -1921,7 +1900,7 @@ impl Global { .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) .map_pass_err(scope)?; - let indirect_buffer: &Buffer = info + let indirect_buffer = info .usage_scope .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) @@ -1949,7 +1928,7 @@ impl Global { buffer_memory_init_actions.extend( indirect_buffer.initialization_status.read().create_action( - buffer_id, + indirect_buffer, offset..end_offset, MemoryInitKind::NeedsInitializedMemory, ), @@ -1991,7 +1970,7 @@ impl Global { .require_downlevel_flags(wgt::DownlevelFlags::INDIRECT_EXECUTION) .map_pass_err(scope)?; - let indirect_buffer: &Buffer = info + let indirect_buffer = info .usage_scope .buffers .merge_single(&*buffer_guard, buffer_id, hal::BufferUses::INDIRECT) @@ -2004,7 +1983,7 @@ impl Global { .ok_or(RenderCommandError::DestroyedBuffer(buffer_id)) .map_pass_err(scope)?; - let count_buffer: &Buffer = info + let count_buffer = info .usage_scope .buffers .merge_single( @@ -2033,7 +2012,7 @@ impl Global { } buffer_memory_init_actions.extend( indirect_buffer.initialization_status.read().create_action( - buffer_id, + indirect_buffer, offset..end_offset, MemoryInitKind::NeedsInitializedMemory, ), @@ -2051,7 +2030,7 @@ impl Global { } buffer_memory_init_actions.extend( count_buffer.initialization_status.read().create_action( - count_buffer_id, + count_buffer, count_buffer_offset..end_count_offset, MemoryInitKind::NeedsInitializedMemory, ), @@ -2224,40 +2203,33 @@ impl Global { bundle .buffer_memory_init_actions .iter() - .filter_map(|action| match buffer_guard.get(action.id) { - Ok(buffer) => { - buffer.initialization_status.read().check_action(action) - } - Err(_) => None, + .filter_map(|action| { + action + .buffer + .initialization_status + .read() + .check_action(action) }), ); for action in bundle.texture_memory_init_actions.iter() { - info.pending_discard_init_fixups.extend( - texture_memory_actions.register_init_action(action, &texture_guard), - ); + info.pending_discard_init_fixups + .extend(texture_memory_actions.register_init_action(action)); } - unsafe { - bundle.execute( - raw, - &*bind_group_guard, - &*render_pipeline_guard, - &*buffer_guard, - ) - } - .map_err(|e| match e { - ExecutionError::DestroyedBuffer(id) => { - RenderCommandError::DestroyedBuffer(id) - } - ExecutionError::Unimplemented(what) => { - RenderCommandError::Unimplemented(what) - } - }) - .map_pass_err(scope)?; + unsafe { bundle.execute(raw) } + .map_err(|e| match e { + ExecutionError::DestroyedBuffer(id) => { + RenderCommandError::DestroyedBuffer(id) + } + ExecutionError::Unimplemented(what) => { + RenderCommandError::Unimplemented(what) + } + }) + .map_pass_err(scope)?; unsafe { info.usage_scope - .merge_render_bundle(&*texture_guard, &bundle.used) + .merge_render_bundle(&bundle.used) .map_pass_err(scope)?; tracker .add_from_render_bundle(&bundle.used) @@ -2270,15 +2242,13 @@ impl Global { log::trace!("Merging renderpass into cmd_buf {:?}", encoder_id); let (trackers, pending_discard_init_fixups) = - info.finish(raw, &*texture_guard).map_pass_err(init_scope)?; + info.finish(raw).map_pass_err(init_scope)?; encoder.close(); (trackers, pending_discard_init_fixups) }; let query_set_guard = hub.query_sets.read(); - let buffer_guard = hub.buffers.read(); - let texture_guard = hub.textures.read(); let cmd_buf = hub.command_buffers.get(encoder_id).unwrap(); let mut cmd_buf_data = cmd_buf.data.lock(); @@ -2294,7 +2264,6 @@ impl Global { fixup_discarded_surfaces( pending_discard_init_fixups.into_iter(), transit, - &texture_guard, &mut tracker.textures, &cmd_buf.device, ); @@ -2309,13 +2278,7 @@ impl Global { .map_err(RenderCommandError::InvalidQuerySet) .map_pass_err(PassErrorScope::QueryReset)?; - super::CommandBuffer::insert_barriers_from_scope( - transit, - tracker, - &scope, - &*buffer_guard, - &*texture_guard, - ); + super::CommandBuffer::insert_barriers_from_scope(transit, tracker, &scope); } *status = CommandEncoderStatus::Recording; diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 2a4a790783..4984e3bebf 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -440,14 +440,15 @@ fn handle_texture_init( init_kind: MemoryInitKind, encoder: &mut CommandEncoder, trackers: &mut Tracker, - texture_memory_actions: &mut CommandBufferTextureMemoryActions, + texture_memory_actions: &mut CommandBufferTextureMemoryActions, device: &Device, copy_texture: &ImageCopyTexture, copy_size: &Extent3d, texture_guard: &Storage, TextureId>, ) { + let texture = texture_guard.get(copy_texture.texture).unwrap(); let init_action = TextureInitTrackerAction { - id: copy_texture.texture, + texture: texture.clone(), range: TextureInitRange { mip_range: copy_texture.mip_level..copy_texture.mip_level + 1, layer_range: copy_texture.origin.z @@ -457,16 +458,14 @@ fn handle_texture_init( }; // Register the init action. - let immediate_inits = - texture_memory_actions.register_init_action(&{ init_action }, texture_guard); + let immediate_inits = texture_memory_actions.register_init_action(&{ init_action }); // In rare cases we may need to insert an init operation immediately onto the command buffer. if !immediate_inits.is_empty() { let cmd_buf_raw = encoder.open(); for init in immediate_inits { clear_texture( - texture_guard, - init.texture, + &init.texture, TextureInitRange { mip_range: init.mip_level..(init.mip_level + 1), layer_range: init.layer..(init.layer + 1), @@ -488,7 +487,7 @@ fn handle_texture_init( fn handle_src_texture_init( encoder: &mut CommandEncoder, trackers: &mut Tracker, - texture_memory_actions: &mut CommandBufferTextureMemoryActions, + texture_memory_actions: &mut CommandBufferTextureMemoryActions, device: &Device, source: &ImageCopyTexture, copy_size: &Extent3d, @@ -518,7 +517,7 @@ fn handle_src_texture_init( fn handle_dst_texture_init( encoder: &mut CommandEncoder, trackers: &mut Tracker, - texture_memory_actions: &mut CommandBufferTextureMemoryActions, + texture_memory_actions: &mut CommandBufferTextureMemoryActions, device: &Device, destination: &ImageCopyTexture, copy_size: &Extent3d, @@ -591,10 +590,13 @@ impl Global { let (src_buffer, src_pending) = { let buffer_guard = hub.buffers.read(); + let src_buffer = buffer_guard + .get(source) + .map_err(|_| TransferError::InvalidBuffer(source))?; cmd_buf_data .trackers .buffers - .set_single(&*buffer_guard, source, hal::BufferUses::COPY_SRC) + .set_single(src_buffer, hal::BufferUses::COPY_SRC) .ok_or(TransferError::InvalidBuffer(source))? }; let src_raw = src_buffer @@ -609,10 +611,13 @@ impl Global { let (dst_buffer, dst_pending) = { let buffer_guard = hub.buffers.read(); + let dst_buffer = buffer_guard + .get(destination) + .map_err(|_| TransferError::InvalidBuffer(destination))?; cmd_buf_data .trackers .buffers - .set_single(&*buffer_guard, destination, hal::BufferUses::COPY_DST) + .set_single(dst_buffer, hal::BufferUses::COPY_DST) .ok_or(TransferError::InvalidBuffer(destination))? }; let dst_raw = dst_buffer @@ -683,14 +688,14 @@ impl Global { // Make sure source is initialized memory and mark dest as initialized. cmd_buf_data.buffer_memory_init_actions.extend( dst_buffer.initialization_status.read().create_action( - destination, + &dst_buffer, destination_offset..(destination_offset + size), MemoryInitKind::ImplicitlyInitialized, ), ); cmd_buf_data.buffer_memory_init_actions.extend( src_buffer.initialization_status.read().create_action( - source, + &src_buffer, source_offset..(source_offset + size), MemoryInitKind::NeedsInitializedMemory, ), @@ -775,9 +780,12 @@ impl Global { let (src_buffer, src_pending) = { let buffer_guard = hub.buffers.read(); + let src_buffer = buffer_guard + .get(source.buffer) + .map_err(|_| TransferError::InvalidBuffer(source.buffer))?; tracker .buffers - .set_single(&*buffer_guard, source.buffer, hal::BufferUses::COPY_SRC) + .set_single(src_buffer, hal::BufferUses::COPY_SRC) .ok_or(TransferError::InvalidBuffer(source.buffer))? }; let src_raw = src_buffer @@ -791,12 +799,7 @@ impl Global { let dst_pending = tracker .textures - .set_single( - dst_texture, - destination.texture, - dst_range, - hal::TextureUses::COPY_DST, - ) + .set_single(dst_texture, dst_range, hal::TextureUses::COPY_DST) .ok_or(TransferError::InvalidTexture(destination.texture))?; let dst_raw = dst_texture .inner @@ -840,7 +843,7 @@ impl Global { } buffer_memory_init_actions.extend(src_buffer.initialization_status.read().create_action( - source.buffer, + &src_buffer, source.layout.offset..(source.layout.offset + required_buffer_bytes_in_copy), MemoryInitKind::NeedsInitializedMemory, )); @@ -927,12 +930,7 @@ impl Global { let src_pending = tracker .textures - .set_single( - src_texture, - source.texture, - src_range, - hal::TextureUses::COPY_SRC, - ) + .set_single(src_texture, src_range, hal::TextureUses::COPY_SRC) .ok_or(TransferError::InvalidTexture(source.texture))?; let src_raw = src_texture .inner @@ -960,13 +958,12 @@ impl Global { let (dst_buffer, dst_pending) = { let buffer_guard = hub.buffers.read(); + let dst_buffer = buffer_guard + .get(destination.buffer) + .map_err(|_| TransferError::InvalidBuffer(destination.buffer))?; tracker .buffers - .set_single( - &*buffer_guard, - destination.buffer, - hal::BufferUses::COPY_DST, - ) + .set_single(dst_buffer, hal::BufferUses::COPY_DST) .ok_or(TransferError::InvalidBuffer(destination.buffer))? }; let dst_raw = dst_buffer @@ -1009,7 +1006,7 @@ impl Global { } buffer_memory_init_actions.extend(dst_buffer.initialization_status.read().create_action( - destination.buffer, + &dst_buffer, destination.layout.offset..(destination.layout.offset + required_buffer_bytes_in_copy), MemoryInitKind::ImplicitlyInitialized, )); @@ -1140,12 +1137,7 @@ impl Global { let src_pending = cmd_buf_data .trackers .textures - .set_single( - src_texture, - source.texture, - src_range, - hal::TextureUses::COPY_SRC, - ) + .set_single(src_texture, src_range, hal::TextureUses::COPY_SRC) .ok_or(TransferError::InvalidTexture(source.texture))?; let src_raw = src_texture .inner @@ -1166,12 +1158,7 @@ impl Global { let dst_pending = cmd_buf_data .trackers .textures - .set_single( - dst_texture, - destination.texture, - dst_range, - hal::TextureUses::COPY_DST, - ) + .set_single(dst_texture, dst_range, hal::TextureUses::COPY_DST) .ok_or(TransferError::InvalidTexture(destination.texture))?; let dst_raw = dst_texture .inner diff --git a/wgpu-core/src/device/global.rs b/wgpu-core/src/device/global.rs index 7ef51165d3..1453ea9849 100644 --- a/wgpu-core/src/device/global.rs +++ b/wgpu-core/src/device/global.rs @@ -10,27 +10,21 @@ use crate::{ init_tracker::TextureInitTracker, instance::{self, Adapter, Surface}, pipeline, present, - resource::{self, Buffer, BufferAccessResult, BufferMapState}, + resource::{self, BufferAccessResult}, resource::{BufferAccessError, BufferMapOperation, Resource}, validation::check_buffer_usage, FastHashMap, Label, LabelHelpers as _, }; -use hal::{CommandEncoder as _, Device as _}; +use hal::Device as _; use parking_lot::RwLock; use smallvec::SmallVec; use wgt::{BufferAddress, TextureFormat}; -use std::{ - borrow::Cow, - iter, mem, - ops::Range, - ptr, - sync::{atomic::Ordering, Arc}, -}; +use std::{borrow::Cow, iter, ops::Range, ptr, sync::Arc}; -use super::{BufferMapPendingClosure, ImplicitPipelineIds, InvalidDevice, UserClosures}; +use super::{ImplicitPipelineIds, InvalidDevice, UserClosures}; impl Global { pub fn adapter_is_surface_supported( @@ -136,7 +130,7 @@ impl Global { profiling::scope!("Device::create_buffer"); let hub = A::hub(self); - let fid = hub.buffers.prepare(id_in); + let fid = hub.buffers.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -152,7 +146,7 @@ impl Global { #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { let mut desc = desc.clone(); - let mapped_at_creation = mem::replace(&mut desc.mapped_at_creation, false); + let mapped_at_creation = std::mem::replace(&mut desc.mapped_at_creation, false); if mapped_at_creation && !desc.usage.contains(wgt::BufferUsages::MAP_WRITE) { desc.usage |= wgt::BufferUsages::COPY_DST; } @@ -286,7 +280,7 @@ impl Global { /// [`wgpu_types::BufferUsages`]: wgt::BufferUsages pub fn create_buffer_error(&self, id_in: Input, label: Label) { let hub = A::hub(self); - let fid = hub.buffers.prepare(id_in); + let fid = hub.buffers.prepare::(id_in); fid.assign_error(label.borrow_or_default()); } @@ -297,7 +291,7 @@ impl Global { label: Label, ) { let hub = A::hub(self); - let fid = hub.render_bundles.prepare(id_in); + let fid = hub.render_bundles.prepare::(id_in); fid.assign_error(label.borrow_or_default()); } @@ -307,7 +301,7 @@ impl Global { /// See `create_buffer_error` for more context and explaination. pub fn create_texture_error(&self, id_in: Input, label: Label) { let hub = A::hub(self); - let fid = hub.textures.prepare(id_in); + let fid = hub.textures.prepare::(id_in); fid.assign_error(label.borrow_or_default()); } @@ -444,59 +438,14 @@ impl Global { ) -> Result<(), resource::DestroyError> { profiling::scope!("Buffer::destroy"); - let map_closure; - // Restrict the locks to this scope. - { - let hub = A::hub(self); - - //TODO: lock pending writes separately, keep the device read-only - - log::debug!("Buffer {:?} is asked to be dropped", buffer_id); - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| resource::DestroyError::Invalid)?; - - let device = &buffer.device; - - map_closure = match &*buffer.map_state.lock() { - &BufferMapState::Waiting(..) // To get the proper callback behavior. - | &BufferMapState::Init { .. } - | &BufferMapState::Active { .. } - => { - self.buffer_unmap_inner(buffer_id, &buffer, device) - .unwrap_or(None) - } - _ => None, - }; - - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::FreeBuffer(buffer_id)); - } - if buffer.raw.is_none() { - return Err(resource::DestroyError::AlreadyDestroyed); - } - - let temp = queue::TempResource::Buffer(buffer.clone()); - let mut pending_writes = device.pending_writes.lock(); - let pending_writes = pending_writes.as_mut().unwrap(); - if pending_writes.dst_buffers.contains_key(&buffer_id) { - pending_writes.temp_resources.push(temp); - } else { - let last_submit_index = buffer.info.submission_index(); - device - .lock_life() - .schedule_resource_destruction(temp, last_submit_index); - } - } - - // Note: outside the scope where locks are held when calling the callback - if let Some((operation, status)) = map_closure { - operation.callback.call(status); - } + let hub = A::hub(self); - Ok(()) + log::debug!("Buffer {:?} is asked to be dropped", buffer_id); + let buffer = hub + .buffers + .get(buffer_id) + .map_err(|_| resource::DestroyError::Invalid)?; + buffer.destroy() } pub fn buffer_drop(&self, buffer_id: id::BufferId, wait: bool) { @@ -505,22 +454,15 @@ impl Global { let hub = A::hub(self); - let (last_submit_index, buffer) = { - let mut buffer_guard = hub.buffers.write(); - match buffer_guard.get(buffer_id) { - Ok(buffer) => { - let last_submit_index = buffer.info.submission_index(); - (last_submit_index, buffer.clone()) - } - Err(_) => { - hub.buffers.unregister_locked(buffer_id, &mut *buffer_guard); - return; - } + if let Some(buffer) = hub.buffers.unregister(buffer_id) { + if buffer.is_unique() { + buffer.destroy().ok(); } - }; - let device = &buffer.device; - { + let last_submit_index = buffer.info.submission_index(); + + let device = buffer.device.clone(); + if device .pending_writes .lock() @@ -529,23 +471,20 @@ impl Global { .dst_buffers .contains_key(&buffer_id) { - device - .lock_life() - .future_suspected_buffers - .push(buffer.clone()); + device.lock_life().future_suspected_buffers.push(buffer); } else { device .lock_life() .suspected_resources .buffers - .insert(buffer_id, buffer.clone()); + .insert(buffer_id, buffer); } - } - if wait { - match device.wait_for_submit(last_submit_index) { - Ok(()) => (), - Err(e) => log::error!("Failed to wait for buffer {:?}: {:?}", buffer_id, e), + if wait { + match device.wait_for_submit(last_submit_index) { + Ok(()) => (), + Err(e) => log::error!("Failed to wait for buffer {:?}: {:?}", buffer_id, e), + } } } } @@ -560,7 +499,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.textures.prepare(id_in); + let fid = hub.textures.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -608,7 +547,7 @@ impl Global { array_layer_count: Some(1), }, }; - let view = device.create_texture_view(&resource, id, &desc).unwrap(); + let view = device.create_texture_view(&resource, &desc).unwrap(); clear_views.push(Arc::new(view)); } } @@ -648,7 +587,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.textures.prepare(id_in); + let fid = hub.textures.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -717,7 +656,7 @@ impl Global { profiling::scope!("Device::create_buffer"); let hub = A::hub(self); - let fid = hub.buffers.prepare(id_in); + let fid = hub.buffers.prepare::(id_in); let error = loop { let device_guard = hub.devices.read(); @@ -827,45 +766,34 @@ impl Global { let hub = A::hub(self); - let (last_submit_index, texture) = { - let mut texture_guard = hub.textures.write(); - match texture_guard.get(texture_id) { - Ok(texture) => { - let last_submit_index = texture.info.submission_index(); - (last_submit_index, texture.clone()) - } - Err(_) => { - hub.textures - .unregister_locked(texture_id, &mut *texture_guard); - return; - } - } - }; + if let Some(texture) = hub.textures.unregister(texture_id) { + let last_submit_index = texture.info.submission_index(); - let device = &texture.device; - { - let mut life_lock = device.lock_life(); - if device - .pending_writes - .lock() - .as_ref() - .unwrap() - .dst_textures - .contains_key(&texture_id) + let device = &texture.device; { - life_lock.future_suspected_textures.push(texture.clone()); - } else { - life_lock - .suspected_resources - .textures - .insert(texture_id, texture.clone()); + let mut life_lock = device.lock_life(); + if device + .pending_writes + .lock() + .as_ref() + .unwrap() + .dst_textures + .contains_key(&texture_id) + { + life_lock.future_suspected_textures.push(texture.clone()); + } else { + life_lock + .suspected_resources + .textures + .insert(texture_id, texture.clone()); + } } - } - if wait { - match device.wait_for_submit(last_submit_index) { - Ok(()) => (), - Err(e) => log::error!("Failed to wait for texture {:?}: {:?}", texture_id, e), + if wait { + match device.wait_for_submit(last_submit_index) { + Ok(()) => (), + Err(e) => log::error!("Failed to wait for texture {:?}: {:?}", texture_id, e), + } } } } @@ -880,7 +808,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.texture_views.prepare(id_in); + let fid = hub.texture_views.prepare::(id_in); let error = loop { let texture = match hub.textures.get(texture_id) { @@ -897,7 +825,7 @@ impl Global { }); } - let view = match device.create_texture_view(&texture, texture_id, desc) { + let view = match device.create_texture_view(&texture, desc) { Ok(view) => view, Err(e) => break e, }; @@ -925,36 +853,25 @@ impl Global { let hub = A::hub(self); - let (last_submit_index, view) = { - let mut texture_view_guard = hub.texture_views.write(); - match texture_view_guard.get(texture_view_id) { - Ok(view) => { - let last_submit_index = view.info.submission_index(); - (last_submit_index, view.clone()) - } - Err(_) => { - hub.texture_views - .unregister_locked(texture_view_id, &mut *texture_view_guard); - return Ok(()); + if let Some(view) = hub.texture_views.unregister(texture_view_id) { + let last_submit_index = view.info.submission_index(); + + view.device + .lock_life() + .suspected_resources + .texture_views + .insert(texture_view_id, view.clone()); + + if wait { + match view.device.wait_for_submit(last_submit_index) { + Ok(()) => (), + Err(e) => log::error!( + "Failed to wait for texture view {:?}: {:?}", + texture_view_id, + e + ), } } - }; - - view.device - .lock_life() - .suspected_resources - .texture_views - .insert(texture_view_id, view.clone()); - - if wait { - match view.device.wait_for_submit(last_submit_index) { - Ok(()) => (), - Err(e) => log::error!( - "Failed to wait for texture view {:?}: {:?}", - texture_view_id, - e - ), - } } Ok(()) } @@ -968,7 +885,7 @@ impl Global { profiling::scope!("Device::create_sampler"); let hub = A::hub(self); - let fid = hub.samplers.prepare(id_in); + let fid = hub.samplers.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1006,24 +923,14 @@ impl Global { let hub = A::hub(self); - let sampler = { - let mut sampler_guard = hub.samplers.write(); - match sampler_guard.get(sampler_id) { - Ok(sampler) => sampler.clone(), - Err(_) => { - hub.samplers - .unregister_locked(sampler_id, &mut *sampler_guard); - return; - } - } - }; - - sampler - .device - .lock_life() - .suspected_resources - .samplers - .insert(sampler_id, sampler.clone()); + if let Some(sampler) = hub.samplers.unregister(sampler_id) { + sampler + .device + .lock_life() + .suspected_resources + .samplers + .insert(sampler_id, sampler.clone()); + } } pub fn device_create_bind_group_layout( @@ -1038,7 +945,7 @@ impl Global { profiling::scope!("Device::create_bind_group_layout"); let hub = A::hub(self); - let fid = hub.bind_group_layouts.prepare(id_in); + let fid = hub.bind_group_layouts.prepare::(id_in); let error = 'outer: loop { let device = match hub.devices.get(device_id) { @@ -1068,20 +975,9 @@ impl Global { let mut compatible_layout = None; { let bgl_guard = hub.bind_group_layouts.read(); - if let Some((id, layout)) = + if let Some((_id, layout)) = Device::deduplicate_bind_group_layout(device_id, &entry_map, &*bgl_guard) { - // If there is an equivalent BGL, just bump the refcount and return it. - // This is only applicable if ids are generated in wgpu. In practice: - // - wgpu users take this branch and return the existing - // id without using the indirection layer in BindGroupLayout. - // - Other users like gecko or the replay tool use don't take - // the branch and instead rely on the indirection to use the - // proper bind group layout id. - if G::ids_are_generated_in_wgpu() { - return (id, None); - } - compatible_layout = Some(layout.clone()); } } @@ -1116,24 +1012,14 @@ impl Global { let hub = A::hub(self); - let layout = { - let mut bind_group_layout_guard = hub.bind_group_layouts.write(); - match bind_group_layout_guard.get(bind_group_layout_id) { - Ok(layout) => layout.clone(), - Err(_) => { - hub.bind_group_layouts - .unregister_locked(bind_group_layout_id, &mut *bind_group_layout_guard); - return; - } - } - }; - - layout - .device - .lock_life() - .suspected_resources - .bind_group_layouts - .insert(bind_group_layout_id, layout.clone()); + if let Some(layout) = hub.bind_group_layouts.unregister(bind_group_layout_id) { + layout + .device + .lock_life() + .suspected_resources + .bind_group_layouts + .insert(bind_group_layout_id, layout.clone()); + } } pub fn device_create_pipeline_layout( @@ -1148,7 +1034,7 @@ impl Global { profiling::scope!("Device::create_pipeline_layout"); let hub = A::hub(self); - let fid = hub.pipeline_layouts.prepare(id_in); + let fid = hub.pipeline_layouts.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1189,25 +1075,14 @@ impl Global { ); let hub = A::hub(self); - - let layout = { - let mut pipeline_layout_guard = hub.pipeline_layouts.write(); - match pipeline_layout_guard.get(pipeline_layout_id) { - Ok(layout) => layout.clone(), - Err(_) => { - hub.pipeline_layouts - .unregister_locked(pipeline_layout_id, &mut *pipeline_layout_guard); - return; - } - } - }; - - layout - .device - .lock_life() - .suspected_resources - .pipeline_layouts - .insert(pipeline_layout_id, layout.clone()); + if let Some(layout) = hub.pipeline_layouts.unregister(pipeline_layout_id) { + layout + .device + .lock_life() + .suspected_resources + .pipeline_layouts + .insert(pipeline_layout_id, layout.clone()); + } } pub fn device_create_bind_group( @@ -1219,7 +1094,7 @@ impl Global { profiling::scope!("Device::create_bind_group"); let hub = A::hub(self); - let fid = hub.bind_groups.prepare(id_in); + let fid = hub.bind_groups.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1271,24 +1146,14 @@ impl Global { let hub = A::hub(self); - let bind_group = { - let mut bind_group_guard = hub.bind_groups.write(); - match bind_group_guard.get(bind_group_id) { - Ok(bind_group) => bind_group.clone(), - Err(_) => { - hub.bind_groups - .unregister_locked(bind_group_id, &mut *bind_group_guard); - return; - } - } - }; - - bind_group - .device - .lock_life() - .suspected_resources - .bind_groups - .insert(bind_group_id, bind_group.clone()); + if let Some(bind_group) = hub.bind_groups.unregister(bind_group_id) { + bind_group + .device + .lock_life() + .suspected_resources + .bind_groups + .insert(bind_group_id, bind_group.clone()); + } } pub fn device_create_shader_module( @@ -1304,7 +1169,7 @@ impl Global { profiling::scope!("Device::create_shader_module"); let hub = A::hub(self); - let fid = hub.shader_modules.prepare(id_in); + let fid = hub.shader_modules.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1367,7 +1232,7 @@ impl Global { profiling::scope!("Device::create_shader_module"); let hub = A::hub(self); - let fid = hub.shader_modules.prepare(id_in); + let fid = hub.shader_modules.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1420,7 +1285,7 @@ impl Global { profiling::scope!("Device::create_command_encoder"); let hub = A::hub(self); - let fid = hub.command_buffers.prepare(id_in); + let fid = hub.command_buffers.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1471,10 +1336,11 @@ impl Global { let hub = A::hub(self); - let cmd_buf = hub.command_buffers.unregister(command_encoder_id).unwrap(); - cmd_buf - .device - .untrack(&cmd_buf.data.lock().as_ref().unwrap().trackers); + if let Some(cmd_buf) = hub.command_buffers.unregister(command_encoder_id) { + cmd_buf + .device + .untrack(&cmd_buf.data.lock().as_ref().unwrap().trackers); + } } pub fn command_buffer_drop(&self, command_buffer_id: id::CommandBufferId) { @@ -1512,7 +1378,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.render_bundles.prepare(id_in); + let fid = hub.render_bundles.prepare::(id_in); let error = loop { let device = match hub.devices.get(bundle_encoder.parent()) { @@ -1557,24 +1423,14 @@ impl Global { log::debug!("RenderBundle {:?} is asked to be dropped", render_bundle_id); let hub = A::hub(self); - let bundle = { - let mut bundle_guard = hub.render_bundles.write(); - match bundle_guard.get(render_bundle_id) { - Ok(bundle) => bundle.clone(), - Err(_) => { - hub.render_bundles - .unregister_locked(render_bundle_id, &mut *bundle_guard); - return; - } - } - }; - - bundle - .device - .lock_life() - .suspected_resources - .render_bundles - .insert(render_bundle_id, bundle.clone()); + if let Some(bundle) = hub.render_bundles.unregister(render_bundle_id) { + bundle + .device + .lock_life() + .suspected_resources + .render_bundles + .insert(render_bundle_id, bundle.clone()); + } } pub fn device_create_query_set( @@ -1586,7 +1442,7 @@ impl Global { profiling::scope!("Device::create_query_set"); let hub = A::hub(self); - let fid = hub.query_sets.prepare(id_in); + let fid = hub.query_sets.prepare::(id_in); let error = loop { let device = match hub.devices.get(device_id) { @@ -1626,25 +1482,21 @@ impl Global { log::debug!("QuerySet {:?} is asked to be dropped", query_set_id); let hub = A::hub(self); - let query_set_guard = hub.query_sets.read(); - let query_set = { - let query_set = query_set_guard.get(query_set_id).unwrap(); - query_set - }; + if let Some(query_set) = hub.query_sets.unregister(query_set_id) { + let device = &query_set.device; - let device = &query_set.device; + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::DestroyQuerySet(query_set_id)); + } - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - trace.add(trace::Action::DestroyQuerySet(query_set_id)); + device + .lock_life() + .suspected_resources + .query_sets + .insert(query_set_id, query_set.clone()); } - - device - .lock_life() - .suspected_resources - .query_sets - .insert(query_set_id, query_set.clone()); } pub fn query_set_label(&self, id: id::QuerySetId) -> String { @@ -1665,7 +1517,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.render_pipelines.prepare(id_in); + let fid = hub.render_pipelines.prepare::(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); let error = loop { @@ -1723,7 +1575,10 @@ impl Global { Err(_) => break binding_model::GetBindGroupLayoutError::InvalidPipeline, }; let id = match pipeline.layout.bind_group_layouts.get(index as usize) { - Some(id) => id.as_info().id(), + Some(bg) => hub + .bind_group_layouts + .prepare::(id_in) + .assign_existing(bg), None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index), }; @@ -1732,7 +1587,7 @@ impl Global { let id = hub .bind_group_layouts - .prepare(id_in) + .prepare::(id_in) .assign_error(""); (id, Some(error)) } @@ -1749,29 +1604,20 @@ impl Global { ); let hub = A::hub(self); - let (pipeline, layout) = { - let mut pipeline_guard = hub.render_pipelines.write(); - match pipeline_guard.get(render_pipeline_id) { - Ok(pipeline) => (pipeline.clone(), pipeline.layout.clone()), - Err(_) => { - hub.render_pipelines - .unregister_locked(render_pipeline_id, &mut *pipeline_guard); - return; - } - } - }; - let layout_id = layout.as_info().id(); - let device = &pipeline.device; - let mut life_lock = device.lock_life(); - life_lock - .suspected_resources - .render_pipelines - .insert(render_pipeline_id, pipeline.clone()); + if let Some(pipeline) = hub.render_pipelines.unregister(render_pipeline_id) { + let layout_id = pipeline.layout.as_info().id(); + let device = &pipeline.device; + let mut life_lock = device.lock_life(); + life_lock + .suspected_resources + .render_pipelines + .insert(render_pipeline_id, pipeline.clone()); - life_lock - .suspected_resources - .pipeline_layouts - .insert(layout_id, layout); + life_lock + .suspected_resources + .pipeline_layouts + .insert(layout_id, pipeline.layout.clone()); + } } pub fn device_create_compute_pipeline( @@ -1788,7 +1634,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.compute_pipelines.prepare(id_in); + let fid = hub.compute_pipelines.prepare::(id_in); let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub)); let error = loop { @@ -1846,17 +1692,20 @@ impl Global { Err(_) => break binding_model::GetBindGroupLayoutError::InvalidPipeline, }; - let layout = match pipeline.layout.bind_group_layouts.get(index as usize) { - Some(id) => id, + let id = match pipeline.layout.bind_group_layouts.get(index as usize) { + Some(bg) => hub + .bind_group_layouts + .prepare::(id_in) + .assign_existing(bg), None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index), }; - return (layout.as_info().id(), None); + return (id, None); }; let id = hub .bind_group_layouts - .prepare(id_in) + .prepare::(id_in) .assign_error(""); (id, Some(error)) } @@ -1873,28 +1722,19 @@ impl Global { ); let hub = A::hub(self); - let (pipeline, layout) = { - let mut pipeline_guard = hub.compute_pipelines.write(); - match pipeline_guard.get(compute_pipeline_id) { - Ok(pipeline) => (pipeline.clone(), pipeline.layout.clone()), - Err(_) => { - hub.compute_pipelines - .unregister_locked(compute_pipeline_id, &mut *pipeline_guard); - return; - } - } - }; - let device = &pipeline.device; - let mut life_lock = device.lock_life(); - life_lock - .suspected_resources - .compute_pipelines - .insert(compute_pipeline_id, pipeline.clone()); - let layout_id = layout.as_info().id(); - life_lock - .suspected_resources - .pipeline_layouts - .insert(layout_id, layout); + if let Some(pipeline) = hub.compute_pipelines.unregister(compute_pipeline_id) { + let layout_id = pipeline.layout.as_info().id(); + let device = &pipeline.device; + let mut life_lock = device.lock_life(); + life_lock + .suspected_resources + .compute_pipelines + .insert(compute_pipeline_id, pipeline.clone()); + life_lock + .suspected_resources + .pipeline_layouts + .insert(layout_id, pipeline.layout.clone()); + } } pub fn surface_configure( @@ -2405,12 +2245,9 @@ impl Global { { let mut trackers = buffer.device.as_ref().trackers.lock(); - let buffer_guard = hub.buffers.read(); - trackers - .buffers - .set_single(&*buffer_guard, buffer_id, internal_use); + trackers.buffers.set_single(&buffer, internal_use); //TODO: Check if draining ALL buffers is correct! - trackers.buffers.drain(); + let _ = trackers.buffers.drain_transitions(); } buffer @@ -2487,114 +2324,6 @@ impl Global { } } } - - fn buffer_unmap_inner( - &self, - buffer_id: id::BufferId, - buffer: &Arc>, - device: &Device, - ) -> Result, BufferAccessError> { - log::debug!("Buffer {:?} map state -> Idle", buffer_id); - match mem::replace( - &mut *buffer.map_state.lock(), - resource::BufferMapState::Idle, - ) { - resource::BufferMapState::Init { - ptr, - stage_buffer, - needs_flush, - } => { - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - let data = trace.make_binary("bin", unsafe { - std::slice::from_raw_parts(ptr.as_ptr(), buffer.size as usize) - }); - trace.add(trace::Action::WriteBuffer { - id: buffer_id, - data, - range: 0..buffer.size, - queued: true, - }); - } - let _ = ptr; - if needs_flush { - unsafe { - device - .raw() - .flush_mapped_ranges(stage_buffer.raw(), iter::once(0..buffer.size)); - } - } - - let raw_buf = buffer.raw.as_ref().ok_or(BufferAccessError::Destroyed)?; - - buffer - .info - .use_at(device.active_submission_index.load(Ordering::Relaxed) + 1); - let region = wgt::BufferSize::new(buffer.size).map(|size| hal::BufferCopy { - src_offset: 0, - dst_offset: 0, - size, - }); - let transition_src = hal::BufferBarrier { - buffer: stage_buffer.raw(), - usage: hal::BufferUses::MAP_WRITE..hal::BufferUses::COPY_SRC, - }; - let transition_dst = hal::BufferBarrier { - buffer: raw_buf, - usage: hal::BufferUses::empty()..hal::BufferUses::COPY_DST, - }; - let mut pending_writes = device.pending_writes.lock(); - let pending_writes = pending_writes.as_mut().unwrap(); - let encoder = pending_writes.activate(); - unsafe { - encoder.transition_buffers( - iter::once(transition_src).chain(iter::once(transition_dst)), - ); - if buffer.size > 0 { - encoder.copy_buffer_to_buffer( - stage_buffer.raw(), - raw_buf, - region.into_iter(), - ); - } - } - pending_writes.consume_temp(queue::TempResource::Buffer(stage_buffer)); - pending_writes.dst_buffers.insert(buffer_id, buffer.clone()); - } - resource::BufferMapState::Idle => { - return Err(BufferAccessError::NotMapped); - } - resource::BufferMapState::Waiting(pending) => { - return Ok(Some((pending.op, Err(BufferAccessError::MapAborted)))); - } - resource::BufferMapState::Active { ptr, range, host } => { - if host == HostMap::Write { - #[cfg(feature = "trace")] - if let Some(ref mut trace) = *device.trace.lock() { - let size = range.end - range.start; - let data = trace.make_binary("bin", unsafe { - std::slice::from_raw_parts(ptr.as_ptr(), size as usize) - }); - trace.add(trace::Action::WriteBuffer { - id: buffer_id, - data, - range: range.clone(), - queued: false, - }); - } - let _ = (ptr, range); - } - unsafe { - device - .raw() - .unmap_buffer(buffer.raw()) - .map_err(DeviceError::from)? - }; - } - } - Ok(None) - } - pub fn buffer_unmap(&self, buffer_id: id::BufferId) -> BufferAccessResult { profiling::scope!("unmap", "Buffer"); @@ -2607,9 +2336,8 @@ impl Global { .buffers .get(buffer_id) .map_err(|_| BufferAccessError::Invalid)?; - let device = &buffer.device; - closure = self.buffer_unmap_inner(buffer_id, &buffer, device) + closure = buffer.buffer_unmap_inner() } // Note: outside the scope where locks are held when calling the callback diff --git a/wgpu-core/src/device/life.rs b/wgpu-core/src/device/life.rs index cc9c6b9a02..a3dd69cf66 100644 --- a/wgpu-core/src/device/life.rs +++ b/wgpu-core/src/device/life.rs @@ -10,7 +10,6 @@ use crate::{ hal_api::HalApi, hub::Hub, id::{self}, - identity::GlobalIdentityHandlerFactory, pipeline::{ComputePipeline, RenderPipeline}, resource::{self, Buffer, QuerySet, Resource, Sampler, Texture, TextureView}, track::Tracker, @@ -466,54 +465,52 @@ impl LifetimeTracker { } impl LifetimeTracker { - fn triage_suspected_render_bundles( + fn triage_suspected_render_bundles( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, mut f: F, ) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::RenderBundleId), { self.suspected_resources .render_bundles - .retain(|bundle_id, bundle| { - let id = bundle.info.id(); + .retain(|&bundle_id, bundle| { let is_removed = { let mut trackers = trackers.lock(); - trackers.bundles.remove_abandoned(id) + trackers + .bundles + .remove_abandoned(bundle_id, hub.render_bundles.contains(bundle_id)) }; if is_removed { - log::info!("Bundle {:?} is removed from registry", id); - f(bundle_id); - - if let Ok(res) = hub.render_bundles.get(id) { - for v in res.used.buffers.used_resources() { - self.suspected_resources - .buffers - .insert(v.as_info().id(), v.clone()); - } - for v in res.used.textures.used_resources() { - self.suspected_resources - .textures - .insert(v.as_info().id(), v.clone()); - } - for v in res.used.bind_groups.used_resources() { - self.suspected_resources - .bind_groups - .insert(v.as_info().id(), v.clone()); - } - for v in res.used.render_pipelines.used_resources() { - self.suspected_resources - .render_pipelines - .insert(v.as_info().id(), v.clone()); - } - for v in res.used.query_sets.used_resources() { - self.suspected_resources - .query_sets - .insert(v.as_info().id(), v.clone()); - } + log::info!("Bundle {:?} is not tracked anymore", bundle_id); + f(&bundle_id); + + for v in bundle.used.buffers.used_resources() { + self.suspected_resources + .buffers + .insert(v.as_info().id(), v.clone()); + } + for v in bundle.used.textures.used_resources() { + self.suspected_resources + .textures + .insert(v.as_info().id(), v.clone()); + } + for v in bundle.used.bind_groups.used_resources() { + self.suspected_resources + .bind_groups + .insert(v.as_info().id(), v.clone()); + } + for v in bundle.used.render_pipelines.used_resources() { + self.suspected_resources + .render_pipelines + .insert(v.as_info().id(), v.clone()); + } + for v in bundle.used.query_sets.used_resources() { + self.suspected_resources + .query_sets + .insert(v.as_info().id(), v.clone()); } } !is_removed @@ -521,266 +518,258 @@ impl LifetimeTracker { self } - fn triage_suspected_bind_groups( + fn triage_suspected_bind_groups( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, mut f: F, ) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::BindGroupId), { self.suspected_resources .bind_groups - .retain(|bind_group_id, bind_group| { - let id = bind_group.info.id(); + .retain(|&bind_group_id, bind_group| { let is_removed = { let mut trackers = trackers.lock(); - trackers.bind_groups.remove_abandoned(id) + trackers + .bind_groups + .remove_abandoned(bind_group_id, hub.bind_groups.contains(bind_group_id)) }; if is_removed { - log::info!("BindGroup {:?} is removed from registry", id); - f(bind_group_id); - - if let Ok(res) = hub.bind_groups.get(id) { - for v in res.used.buffers.used_resources() { - self.suspected_resources - .buffers - .insert(v.as_info().id(), v.clone()); - } - for v in res.used.textures.used_resources() { - self.suspected_resources - .textures - .insert(v.as_info().id(), v.clone()); - } - for v in res.used.views.used_resources() { - self.suspected_resources - .texture_views - .insert(v.as_info().id(), v.clone()); - } - for v in res.used.samplers.used_resources() { - self.suspected_resources - .samplers - .insert(v.as_info().id(), v.clone()); - } + log::info!("BindGroup {:?} is not tracked anymore", bind_group_id); + f(&bind_group_id); + for v in bind_group.used.buffers.used_resources() { self.suspected_resources - .bind_group_layouts - .insert(res.layout.as_info().id(), res.layout.clone()); - - let submit_index = res.info.submission_index(); - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .bind_groups - .push(res); + .buffers + .insert(v.as_info().id(), v.clone()); + } + for v in bind_group.used.textures.used_resources() { + self.suspected_resources + .textures + .insert(v.as_info().id(), v.clone()); } + for v in bind_group.used.views.used_resources() { + self.suspected_resources + .texture_views + .insert(v.as_info().id(), v.clone()); + } + for v in bind_group.used.samplers.used_resources() { + self.suspected_resources + .samplers + .insert(v.as_info().id(), v.clone()); + } + + self.suspected_resources + .bind_group_layouts + .insert(bind_group.layout.as_info().id(), bind_group.layout.clone()); + + let submit_index = bind_group.info.submission_index(); + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources) + .bind_groups + .push(bind_group.clone()); } !is_removed }); self } - fn triage_suspected_texture_views( + fn triage_suspected_texture_views( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, mut f: F, ) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::TextureViewId), { self.suspected_resources .texture_views - .retain(|view_id, view| { - let id = view.info.id(); + .retain(|&view_id, view| { let is_removed = { let mut trackers = trackers.lock(); - trackers.views.remove_abandoned(id) + trackers + .views + .remove_abandoned(view_id, hub.texture_views.contains(view_id)) }; if is_removed { - log::info!("TextureView {:?} is removed from registry", id); - f(view_id); - - if let Ok(res) = hub.texture_views.get(id) { - if let Some(parent_texture) = res.parent.as_ref() { - self.suspected_resources - .textures - .insert(parent_texture.as_info().id(), parent_texture.clone()); - } - let submit_index = res.info.submission_index(); - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .texture_views - .push(res); + log::info!("TextureView {:?} is not tracked anymore", view_id); + f(&view_id); + + if let Some(parent_texture) = view.parent.as_ref() { + self.suspected_resources + .textures + .insert(parent_texture.as_info().id(), parent_texture.clone()); } + let submit_index = view.info.submission_index(); + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources) + .texture_views + .push(view.clone()); } !is_removed }); self } - fn triage_suspected_textures( + fn triage_suspected_textures( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, mut f: F, ) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::TextureId), { self.suspected_resources .textures - .retain(|texture_id, texture| { - let id = texture.info.id(); + .retain(|&texture_id, texture| { let is_removed = { let mut trackers = trackers.lock(); - trackers.textures.remove_abandoned(id) + trackers + .textures + .remove_abandoned(texture_id, hub.textures.contains(texture_id)) }; if is_removed { - log::info!("Texture {:?} is removed from registry", id); - f(texture_id); - - if let Ok(res) = hub.textures.get(id) { - let submit_index = res.info.submission_index(); - let non_referenced_resources = self - .active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources); - - if let &resource::TextureClearMode::RenderPass { - ref clear_views, .. - } = &*res.clear_mode.read() - { - non_referenced_resources - .texture_views - .extend(clear_views.iter().cloned()); - } - non_referenced_resources.textures.push(res); + log::info!("Texture {:?} is not tracked anymore", texture_id); + f(&texture_id); + + let submit_index = texture.info.submission_index(); + let non_referenced_resources = self + .active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources); + + if let &resource::TextureClearMode::RenderPass { + ref clear_views, .. + } = &*texture.clear_mode.read() + { + non_referenced_resources + .texture_views + .extend(clear_views.iter().cloned()); } + non_referenced_resources.textures.push(texture.clone()); } !is_removed }); self } - fn triage_suspected_samplers( + fn triage_suspected_samplers( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, mut f: F, ) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::SamplerId), { self.suspected_resources .samplers - .retain(|sampler_id, sampler| { - let id = sampler.info.id(); + .retain(|&sampler_id, sampler| { let is_removed = { let mut trackers = trackers.lock(); - trackers.samplers.remove_abandoned(id) + trackers + .samplers + .remove_abandoned(sampler_id, hub.samplers.contains(sampler_id)) }; if is_removed { - log::info!("Sampler {:?} is removed from registry", id); - f(sampler_id); - - if let Ok(res) = hub.samplers.get(id) { - let submit_index = res.info.submission_index(); - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .samplers - .push(res); - } + log::info!("Sampler {:?} is not tracked anymore", sampler_id); + f(&sampler_id); + + let submit_index = sampler.info.submission_index(); + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources) + .samplers + .push(sampler.clone()); } !is_removed }); self } - fn triage_suspected_buffers( + fn triage_suspected_buffers( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, mut f: F, ) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::BufferId), { self.suspected_resources .buffers - .retain(|buffer_id, buffer| { - let id = buffer.info.id(); + .retain(|&buffer_id, buffer| { let is_removed = { let mut trackers = trackers.lock(); - trackers.buffers.remove_abandoned(id) + trackers + .buffers + .remove_abandoned(buffer_id, hub.buffers.contains(buffer_id)) }; if is_removed { - log::info!("Buffer {:?} is removed from registry", id); - f(buffer_id); - - if let Ok(res) = hub.buffers.get(id) { - let submit_index = res.info.submission_index(); - if let resource::BufferMapState::Init { - ref stage_buffer, .. - } = *res.map_state.lock() - { - self.free_resources.buffers.push(stage_buffer.clone()); - } - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .buffers - .push(res); + log::info!("Buffer {:?} is not tracked anymore", buffer_id); + f(&buffer_id); + + let submit_index = buffer.info.submission_index(); + if let resource::BufferMapState::Init { + ref stage_buffer, .. + } = *buffer.map_state.lock() + { + self.free_resources.buffers.push(stage_buffer.clone()); } + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources) + .buffers + .push(buffer.clone()); } !is_removed }); self } - fn triage_suspected_compute_pipelines( + fn triage_suspected_compute_pipelines( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, mut f: F, ) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::ComputePipelineId), { self.suspected_resources.compute_pipelines.retain( - |compute_pipeline_id, compute_pipeline| { - let id = compute_pipeline.info.id(); + |&compute_pipeline_id, compute_pipeline| { let is_removed = { let mut trackers = trackers.lock(); - trackers.compute_pipelines.remove_abandoned(id) + trackers.compute_pipelines.remove_abandoned( + compute_pipeline_id, + hub.compute_pipelines.contains(compute_pipeline_id), + ) }; if is_removed { - log::info!("ComputePipeline {:?} is removed from registry", id); - f(compute_pipeline_id); - - if let Ok(res) = hub.compute_pipelines.get(id) { - let submit_index = res.info.submission_index(); - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .compute_pipes - .push(res); - } + log::info!( + "ComputePipeline {:?} is not tracked anymore", + compute_pipeline_id + ); + f(&compute_pipeline_id); + + let submit_index = compute_pipeline.info.submission_index(); + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources) + .compute_pipes + .push(compute_pipeline.clone()); } !is_removed }, @@ -788,69 +777,65 @@ impl LifetimeTracker { self } - fn triage_suspected_render_pipelines( + fn triage_suspected_render_pipelines( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, mut f: F, ) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::RenderPipelineId), { self.suspected_resources .render_pipelines - .retain(|render_pipeline_id, render_pipeline| { - let id = render_pipeline.info.id(); + .retain(|&render_pipeline_id, render_pipeline| { let is_removed = { let mut trackers = trackers.lock(); - trackers.render_pipelines.remove_abandoned(id) + trackers.render_pipelines.remove_abandoned( + render_pipeline_id, + hub.render_pipelines.contains(render_pipeline_id), + ) }; if is_removed { - log::info!("RenderPipeline {:?} is removed from registry", id); - f(render_pipeline_id); - - if let Ok(res) = hub.render_pipelines.get(id) { - let submit_index = res.info.submission_index(); - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .render_pipes - .push(res); - } + log::info!( + "RenderPipeline {:?} is not tracked anymore", + render_pipeline_id + ); + f(&render_pipeline_id); + + let submit_index = render_pipeline.info.submission_index(); + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources) + .render_pipes + .push(render_pipeline.clone()); } !is_removed }); self } - fn triage_suspected_pipeline_layouts(&mut self, hub: &Hub, mut f: F) -> &mut Self + fn triage_suspected_pipeline_layouts(&mut self, mut f: F) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::PipelineLayoutId), { - let mut pipeline_layouts_locked = hub.pipeline_layouts.write(); self.suspected_resources .pipeline_layouts .retain(|pipeline_layout_id, pipeline_layout| { - let id = pipeline_layout.info.id(); //Note: this has to happen after all the suspected pipelines are destroyed - if pipeline_layouts_locked.is_unique(id).unwrap() { - log::debug!("PipelineLayout {:?} will be removed from registry", id); + if pipeline_layout.is_unique() { f(pipeline_layout_id); - if let Some(lay) = hub - .pipeline_layouts - .unregister_locked(id, &mut *pipeline_layouts_locked) - { - for bgl in &lay.bind_group_layouts { - self.suspected_resources - .bind_group_layouts - .insert(bgl.as_info().id(), bgl.clone()); - } - self.free_resources.pipeline_layouts.push(lay); + for bgl in &pipeline_layout.bind_group_layouts { + self.suspected_resources + .bind_group_layouts + .insert(bgl.as_info().id(), bgl.clone()); } + self.free_resources + .pipeline_layouts + .push(pipeline_layout.clone()); + return false; } true @@ -858,23 +843,19 @@ impl LifetimeTracker { self } - fn triage_suspected_bind_group_layouts(&mut self, hub: &Hub, mut f: F) -> &mut Self + fn triage_suspected_bind_group_layouts(&mut self, mut f: F) -> &mut Self where - G: GlobalIdentityHandlerFactory, F: FnMut(&id::BindGroupLayoutId), { - let mut bind_group_layouts_locked = hub.bind_group_layouts.write(); - self.suspected_resources.bind_group_layouts.retain( |bind_group_layout_id, bind_group_layout| { - let id = bind_group_layout.info.id(); //Note: this has to happen after all the suspected pipelines are destroyed //Note: nothing else can bump the refcount since the guard is locked exclusively //Note: same BGL can appear multiple times in the list, but only the last // encounter could drop the refcount to 0. //Note: this has to happen after all the suspected pipelines are destroyed - if bind_group_layouts_locked.is_unique(id).unwrap() { + if bind_group_layout.is_unique() { // If This layout points to a compatible one, go over the latter // to decrement the ref count and potentially destroy it. //bgl_to_check = bind_group_layout.compatible_layout; @@ -885,12 +866,10 @@ impl LifetimeTracker { ); f(bind_group_layout_id); - if let Some(lay) = hub + self.free_resources .bind_group_layouts - .unregister_locked(*bind_group_layout_id, &mut *bind_group_layouts_locked) - { - self.free_resources.bind_group_layouts.push(lay); - } + .push(bind_group_layout.clone()); + return false; } true @@ -899,35 +878,32 @@ impl LifetimeTracker { self } - fn triage_suspected_query_sets( + fn triage_suspected_query_sets( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, - ) -> &mut Self - where - G: GlobalIdentityHandlerFactory, - { + ) -> &mut Self { self.suspected_resources .query_sets - .retain(|_query_set_id, query_set| { - let id = query_set.info.id(); + .retain(|&query_set_id, query_set| { let is_removed = { let mut trackers = trackers.lock(); - trackers.query_sets.remove_abandoned(id) + trackers + .query_sets + .remove_abandoned(query_set_id, hub.query_sets.contains(query_set_id)) }; if is_removed { - log::info!("QuerySet {:?} is removed from registry", id); + log::info!("QuerySet {:?} is not tracked anymore", query_set_id); // #[cfg(feature = "trace")] // trace.map(|t| t.add(trace::Action::DestroyComputePipeline(id))); - if let Ok(res) = hub.query_sets.get(id) { - let submit_index = res.info.submission_index(); - self.active - .iter_mut() - .find(|a| a.index == submit_index) - .map_or(&mut self.free_resources, |a| &mut a.last_resources) - .query_sets - .push(res); - } + + let submit_index = query_set.info.submission_index(); + self.active + .iter_mut() + .find(|a| a.index == submit_index) + .map_or(&mut self.free_resources, |a| &mut a.last_resources) + .query_sets + .push(query_set.clone()); } !is_removed }); @@ -973,9 +949,9 @@ impl LifetimeTracker { /// [`self.active`]: LifetimeTracker::active /// [`triage_submissions`]: LifetimeTracker::triage_submissions /// [`self.free_resources`]: LifetimeTracker::free_resources - pub(crate) fn triage_suspected( + pub(crate) fn triage_suspected( &mut self, - hub: &Hub, + hub: &Hub, trackers: &Mutex>, #[cfg(feature = "trace")] mut trace: Option<&mut trace::Trace>, ) { @@ -1029,13 +1005,13 @@ impl LifetimeTracker { t.add(trace::Action::DestroyRenderPipeline(*_id)); } }); - self.triage_suspected_pipeline_layouts(hub, |_id| { + self.triage_suspected_pipeline_layouts(|_id| { #[cfg(feature = "trace")] if let Some(ref mut t) = trace { t.add(trace::Action::DestroyPipelineLayout(*_id)); } }); - self.triage_suspected_bind_group_layouts(hub, |_id| { + self.triage_suspected_bind_group_layouts(|_id| { #[cfg(feature = "trace")] if let Some(ref mut t) = trace { t.add(trace::Action::DestroyBindGroupLayout(*_id)); @@ -1076,9 +1052,9 @@ impl LifetimeTracker { /// /// See the documentation for [`LifetimeTracker`] for details. #[must_use] - pub(crate) fn handle_mapping( + pub(crate) fn handle_mapping( &mut self, - hub: &Hub, + hub: &Hub, raw: &A::Device, trackers: &Mutex>, ) -> Vec { @@ -1092,14 +1068,14 @@ impl LifetimeTracker { let buffer_id = buffer.info.id(); let is_removed = { let mut trackers = trackers.lock(); - trackers.buffers.remove_abandoned(buffer_id) + trackers + .buffers + .remove_abandoned(buffer_id, hub.buffers.contains(buffer_id)) }; if is_removed { *buffer.map_state.lock() = resource::BufferMapState::Idle; - log::info!("Buffer {:?} is removed from registry", buffer_id); - if let Ok(buf) = hub.buffers.get(buffer_id) { - self.free_resources.buffers.push(buf); - } + log::info!("Buffer {:?} is not tracked anymore", buffer_id); + self.free_resources.buffers.push(buffer.clone()); } else { let mapping = match std::mem::replace( &mut *buffer.map_state.lock(), diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 10807833f9..ee657eaa81 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -342,13 +342,13 @@ pub struct ImplicitPipelineIds<'a, G: GlobalIdentityHandlerFactory> { } impl ImplicitPipelineIds<'_, G> { - fn prepare(self, hub: &Hub) -> ImplicitPipelineContext { + fn prepare(self, hub: &Hub) -> ImplicitPipelineContext { ImplicitPipelineContext { - root_id: hub.pipeline_layouts.prepare(self.root_id).into_id(), + root_id: hub.pipeline_layouts.prepare::(self.root_id).into_id(), group_ids: self .group_ids .iter() - .map(|id_in| hub.bind_group_layouts.prepare(id_in.clone()).into_id()) + .map(|id_in| hub.bind_group_layouts.prepare::(*id_in).into_id()) .collect(), } } diff --git a/wgpu-core/src/device/queue.rs b/wgpu-core/src/device/queue.rs index cb9d1fb85e..46908b9f27 100644 --- a/wgpu-core/src/device/queue.rs +++ b/wgpu-core/src/device/queue.rs @@ -471,7 +471,7 @@ impl Global { let (staging_buffer, staging_buffer_ptr) = prepare_staging_buffer(device, buffer_size.get())?; - let fid = hub.staging_buffers.prepare(id_in); + let fid = hub.staging_buffers.prepare::(id_in); let (id, _) = fid.assign(staging_buffer); log::info!("Created StagingBuffer {:?}", id); @@ -589,10 +589,13 @@ impl Global { let (dst, transition) = { let buffer_guard = hub.buffers.read(); + let dst = buffer_guard + .get(buffer_id) + .map_err(|_| TransferError::InvalidBuffer(buffer_id))?; let mut trackers = device.trackers.lock(); trackers .buffers - .set_single(&buffer_guard, buffer_id, hal::BufferUses::COPY_DST) + .set_single(dst, hal::BufferUses::COPY_DST) .ok_or(TransferError::InvalidBuffer(buffer_id))? }; let dst_raw = dst @@ -774,10 +777,8 @@ impl Global { .collect::>>() { let mut trackers = device.trackers.lock(); - let texture_guard = hub.textures.read(); crate::command::clear_texture( - &*texture_guard, - destination.texture, + &dst, TextureInitRange { mip_range: destination.mip_level..(destination.mip_level + 1), layer_range, @@ -883,12 +884,7 @@ impl Global { let mut trackers = device.trackers.lock(); let transition = trackers .textures - .set_single( - &dst, - destination.texture, - selector, - hal::TextureUses::COPY_DST, - ) + .set_single(&dst, selector, hal::TextureUses::COPY_DST) .ok_or(TransferError::InvalidTexture(destination.texture))?; unsafe { encoder.transition_textures(transition.map(|pending| pending.into_hal(&dst))); @@ -1245,14 +1241,8 @@ impl Global { } if should_extend { unsafe { - let texture_guard = hub.textures.read(); used_surface_textures - .merge_single( - &*texture_guard, - id, - None, - hal::TextureUses::PRESENT, - ) + .merge_single(texture, None, hal::TextureUses::PRESENT) .unwrap(); }; } @@ -1268,19 +1258,16 @@ impl Global { } } { - let texture_view_guard = hub.texture_views.read(); - let sampler_guard = hub.samplers.read(); - for bg in cmd_buf_trackers.bind_groups.used_resources() { bg.info.use_at(submit_index); // We need to update the submission indices for the contained // state-less (!) resources as well, so that they don't get // deleted too early if the parent bind group goes out of scope. - for sub_id in bg.used.views.used() { - texture_view_guard[sub_id].info.use_at(submit_index); + for view in bg.used.views.used_resources() { + view.info.use_at(submit_index); } - for sub_id in bg.used.samplers.used() { - sampler_guard[sub_id].info.use_at(submit_index); + for sampler in bg.used.samplers.used_resources() { + sampler.info.use_at(submit_index); } if bg.is_unique() { device @@ -1354,15 +1341,14 @@ impl Global { .map_err(DeviceError::from)? }; log::trace!("Stitching command buffer {:?} before submission", cmb_id); - let buffer_guard = hub.buffers.read(); - let texture_guard = hub.textures.read(); + //Note: locking the trackers has to be done after the storages let mut trackers = device.trackers.lock(); baked - .initialize_buffer_memory(&mut *trackers, &*buffer_guard) + .initialize_buffer_memory(&mut *trackers) .map_err(|err| QueueSubmitError::DestroyedBuffer(err.0))?; baked - .initialize_texture_memory(&mut *trackers, &*texture_guard, device) + .initialize_texture_memory(&mut *trackers, device) .map_err(|err| QueueSubmitError::DestroyedTexture(err.0))?; //Note: stateless trackers are not merged: // device already knows these resources exist. @@ -1370,8 +1356,6 @@ impl Global { &mut baked.encoder, &mut *trackers, &baked.trackers, - &*buffer_guard, - &*texture_guard, ); let transit = unsafe { baked.encoder.end_encoding().unwrap() }; @@ -1389,11 +1373,8 @@ impl Global { }; trackers .textures - .set_from_usage_scope(&*texture_guard, &used_surface_textures); - let texture_barriers = trackers.textures.drain().map(|pending| { - let tex = unsafe { texture_guard.get_unchecked(pending.id) }; - pending.into_hal(tex) - }); + .set_from_usage_scope(&used_surface_textures); + let texture_barriers = trackers.textures.drain_transitions(); let present = unsafe { baked.encoder.transition_textures(texture_barriers); baked.encoder.end_encoding().unwrap() @@ -1430,12 +1411,7 @@ impl Global { has_work.store(true, Ordering::Relaxed); unsafe { used_surface_textures - .merge_single( - &*texture_guard, - id, - None, - hal::TextureUses::PRESENT, - ) + .merge_single(texture, None, hal::TextureUses::PRESENT) .unwrap() }; } @@ -1447,11 +1423,8 @@ impl Global { trackers .textures - .set_from_usage_scope(&*texture_guard, &used_surface_textures); - let texture_barriers = trackers.textures.drain().map(|pending| { - let tex = unsafe { texture_guard.get_unchecked(pending.id) }; - pending.into_hal(tex) - }); + .set_from_usage_scope(&used_surface_textures); + let texture_barriers = trackers.textures.drain_transitions(); unsafe { pending_writes diff --git a/wgpu-core/src/device/resource.rs b/wgpu-core/src/device/resource.rs index 9666ba4774..3b8d51cda5 100644 --- a/wgpu-core/src/device/resource.rs +++ b/wgpu-core/src/device/resource.rs @@ -15,16 +15,16 @@ use crate::{ hal_api::HalApi, hub::Hub, id::{self, DeviceId, QueueId}, - identity::GlobalIdentityHandlerFactory, init_tracker::{ BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange, TextureInitTracker, TextureInitTrackerAction, }, instance::Adapter, pipeline, + registry::Registry, resource::ResourceInfo, resource::{ - self, Buffer, QuerySet, Resource, Sampler, Texture, TextureInner, TextureView, + self, Buffer, QuerySet, Resource, Sampler, Texture, TextureView, TextureViewNotRenderableReason, }, storage::Storage, @@ -284,9 +284,9 @@ impl Device { /// submissions still in flight. (We have to take the locks needed to /// produce this information for other reasons, so we might as well just /// return it to our callers.) - pub(crate) fn maintain<'this, G: GlobalIdentityHandlerFactory>( + pub(crate) fn maintain<'this>( &'this self, - hub: &Hub, + hub: &Hub, fence: &A::Fence, maintain: wgt::Maintain, ) -> Result<(UserClosures, bool), WaitIdleError> { @@ -764,31 +764,34 @@ impl Device { Ok(texture) } - pub(crate) fn create_texture_inner_view( + pub(crate) fn create_texture_view( self: &Arc, - texture: &A::Texture, - texture_id: id::TextureId, - texture_desc: &wgt::TextureDescriptor<(), Vec>, - texture_usage: &hal::TextureUses, - texture_format: &wgt::TextureFormatFeatures, + texture: &Arc>, desc: &resource::TextureViewDescriptor, ) -> Result, resource::CreateTextureViewError> { + let texture_raw = texture + .inner + .as_ref() + .unwrap() + .as_raw() + .ok_or(resource::CreateTextureViewError::InvalidTexture)?; // resolve TextureViewDescriptor defaults // https://gpuweb.github.io/gpuweb/#abstract-opdef-resolving-gputextureviewdescriptor-defaults let resolved_format = desc.format.unwrap_or_else(|| { - texture_desc + texture + .desc .format .aspect_specific_format(desc.range.aspect) - .unwrap_or(texture_desc.format) + .unwrap_or(texture.desc.format) }); let resolved_dimension = desc .dimension - .unwrap_or_else(|| match texture_desc.dimension { + .unwrap_or_else(|| match texture.desc.dimension { wgt::TextureDimension::D1 => wgt::TextureViewDimension::D1, wgt::TextureDimension::D2 => { - if texture_desc.array_layer_count() == 1 { + if texture.desc.array_layer_count() == 1 { wgt::TextureViewDimension::D2 } else { wgt::TextureViewDimension::D2Array @@ -798,7 +801,8 @@ impl Device { }); let resolved_mip_level_count = desc.range.mip_level_count.unwrap_or_else(|| { - texture_desc + texture + .desc .mip_level_count .saturating_sub(desc.range.base_mip_level) }); @@ -812,7 +816,8 @@ impl Device { | wgt::TextureViewDimension::D3 => 1, wgt::TextureViewDimension::Cube => 6, wgt::TextureViewDimension::D2Array | wgt::TextureViewDimension::CubeArray => { - texture_desc + texture + .desc .array_layer_count() .saturating_sub(desc.range.base_array_layer) } @@ -820,32 +825,33 @@ impl Device { // validate TextureViewDescriptor - let aspects = hal::FormatAspects::new(texture_desc.format, desc.range.aspect); + let aspects = hal::FormatAspects::new(texture.desc.format, desc.range.aspect); if aspects.is_empty() { return Err(resource::CreateTextureViewError::InvalidAspect { - texture_format: texture_desc.format, + texture_format: texture.desc.format, requested_aspect: desc.range.aspect, }); } let format_is_good = if desc.range.aspect == wgt::TextureAspect::All { - resolved_format == texture_desc.format - || texture_desc.view_formats.contains(&resolved_format) + resolved_format == texture.desc.format + || texture.desc.view_formats.contains(&resolved_format) } else { Some(resolved_format) - == texture_desc + == texture + .desc .format .aspect_specific_format(desc.range.aspect) }; if !format_is_good { return Err(resource::CreateTextureViewError::FormatReinterpretation { - texture: texture_desc.format, + texture: texture.desc.format, view: resolved_format, }); } // check if multisampled texture is seen as anything but 2D - if texture_desc.sample_count > 1 && resolved_dimension != wgt::TextureViewDimension::D2 { + if texture.desc.sample_count > 1 && resolved_dimension != wgt::TextureViewDimension::D2 { return Err( resource::CreateTextureViewError::InvalidMultisampledTextureViewDimension( resolved_dimension, @@ -854,11 +860,11 @@ impl Device { } // check if the dimension is compatible with the texture - if texture_desc.dimension != resolved_dimension.compatible_texture_dimension() { + if texture.desc.dimension != resolved_dimension.compatible_texture_dimension() { return Err( resource::CreateTextureViewError::InvalidTextureViewDimension { view: resolved_dimension, - texture: texture_desc.dimension, + texture: texture.desc.dimension, }, ); } @@ -895,7 +901,7 @@ impl Device { match resolved_dimension { TextureViewDimension::Cube | TextureViewDimension::CubeArray => { - if texture_desc.size.width != texture_desc.size.height { + if texture.desc.size.width != texture.desc.size.height { return Err(resource::CreateTextureViewError::InvalidCubeTextureViewSize); } } @@ -911,7 +917,7 @@ impl Device { .base_mip_level .saturating_add(resolved_mip_level_count); - let level_end = texture_desc.mip_level_count; + let level_end = texture.desc.mip_level_count; if mip_level_end > level_end { return Err(resource::CreateTextureViewError::TooManyMipLevels { requested: mip_level_end, @@ -928,7 +934,7 @@ impl Device { .base_array_layer .saturating_add(resolved_array_layer_count); - let layer_end = texture_desc.array_layer_count(); + let layer_end = texture.desc.array_layer_count(); if array_layer_end > layer_end { return Err(resource::CreateTextureViewError::TooManyArrayLayers { requested: array_layer_end, @@ -938,11 +944,12 @@ impl Device { // https://gpuweb.github.io/gpuweb/#abstract-opdef-renderable-texture-view let render_extent = 'b: loop { - if !texture_desc + if !texture + .desc .usage .contains(wgt::TextureUsages::RENDER_ATTACHMENT) { - break 'b Err(TextureViewNotRenderableReason::Usage(texture_desc.usage)); + break 'b Err(TextureViewNotRenderableReason::Usage(texture.desc.usage)); } if !(resolved_dimension == TextureViewDimension::D2 @@ -968,11 +975,13 @@ impl Device { )); } - if aspects != hal::FormatAspects::from(texture_desc.format) { + if aspects != hal::FormatAspects::from(texture.desc.format) { break 'b Err(TextureViewNotRenderableReason::Aspects(aspects)); } - break 'b Ok(texture_desc.compute_render_extent(desc.range.base_mip_level)); + break 'b Ok(texture + .desc + .compute_render_extent(desc.range.base_mip_level)); }; // filter the usages based on the other criteria @@ -994,18 +1003,18 @@ impl Device { } else { hal::TextureUses::RESOURCE }; - *texture_usage & mask_copy & mask_dimension & mask_mip_level + texture.hal_usage & mask_copy & mask_dimension & mask_mip_level }; log::debug!( "Create view for texture {:?} filters usages to {:?}", - texture_id, + texture.as_info().id(), usage ); // use the combined depth-stencil format for the view - let format = if resolved_format.is_depth_stencil_component(texture_desc.format) { - texture_desc.format + let format = if resolved_format.is_depth_stencil_component(texture.desc.format) { + texture.desc.format } else { resolved_format }; @@ -1030,7 +1039,7 @@ impl Device { self.raw .as_ref() .unwrap() - .create_texture_view(texture, &hal_desc) + .create_texture_view(texture_raw, &hal_desc) .map_err(|_| resource::CreateTextureViewError::OutOfMemory)? }; @@ -1041,51 +1050,21 @@ impl Device { Ok(TextureView { raw: Some(raw), - parent: None, - parent_id: texture_id, + parent: Some(texture.clone()), device: self.clone(), desc: resource::HalTextureViewDescriptor { format: resolved_format, dimension: resolved_dimension, range: resolved_range, }, - format_features: *texture_format, + format_features: texture.format_features, render_extent, - samples: texture_desc.sample_count, + samples: texture.desc.sample_count, selector, info: ResourceInfo::new(desc.label.borrow_or_default()), }) } - pub(crate) fn create_texture_view( - self: &Arc, - texture: &Arc>, - texture_id: id::TextureId, - desc: &resource::TextureViewDescriptor, - ) -> Result, resource::CreateTextureViewError> { - let texture_raw = texture - .inner - .as_ref() - .unwrap() - .as_raw() - .ok_or(resource::CreateTextureViewError::InvalidTexture)?; - - let mut result = self.create_texture_inner_view( - texture_raw, - texture_id, - &texture.desc, - &texture.hal_usage, - &texture.format_features, - desc, - ); - if let TextureInner::Native { .. } = *texture.inner.as_ref().unwrap() { - if let Ok(ref mut texture_view) = result { - texture_view.parent = Some(texture.clone()); - } - } - result - } - pub(crate) fn create_sampler( self: &Arc, desc: &resource::SamplerDescriptor, @@ -1644,7 +1623,7 @@ impl Device { bb: &binding_model::BufferBinding, binding: u32, decl: &wgt::BindGroupLayoutEntry, - used_buffer_ranges: &mut Vec, + used_buffer_ranges: &mut Vec>, dynamic_binding_info: &mut Vec, late_buffer_binding_sizes: &mut FastHashMap, used: &mut BindGroupStates, @@ -1755,7 +1734,7 @@ impl Device { assert_eq!(bb.offset % wgt::COPY_BUFFER_ALIGNMENT, 0); used_buffer_ranges.extend(buffer.initialization_status.read().create_action( - bb.buffer_id, + buffer, bb.offset..bb.offset + bind_size, MemoryInitKind::NeedsInitializedMemory, )); @@ -1769,29 +1748,28 @@ impl Device { pub(crate) fn create_texture_binding( view: &TextureView, - texture_guard: &Storage, id::TextureId>, internal_use: hal::TextureUses, pub_usage: wgt::TextureUsages, used: &mut BindGroupStates, - used_texture_ranges: &mut Vec, + used_texture_ranges: &mut Vec>, ) -> Result<(), binding_model::CreateBindGroupError> { + let texture_id = view.parent.as_ref().unwrap().as_info().id(); // Careful here: the texture may no longer have its own ref count, // if it was deleted by the user. let texture = used .textures .add_single( - texture_guard, - view.parent_id, + view.parent.as_ref().unwrap(), Some(view.selector.clone()), internal_use, ) .ok_or(binding_model::CreateBindGroupError::InvalidTexture( - view.parent_id, + texture_id, ))?; check_texture_usage(texture.desc.usage, pub_usage)?; used_texture_ranges.push(TextureInitTrackerAction { - id: view.parent_id, + texture: texture.clone(), range: TextureInitRange { mip_range: view.desc.range.mip_range(texture.desc.mip_level_count), layer_range: view @@ -1805,11 +1783,11 @@ impl Device { Ok(()) } - pub(crate) fn create_bind_group( + pub(crate) fn create_bind_group( self: &Arc, layout: &Arc>, desc: &binding_model::BindGroupDescriptor, - hub: &Hub, + hub: &Hub, ) -> Result, binding_model::CreateBindGroupError> { use crate::binding_model::{BindingResource as Br, CreateBindGroupError as Error}; { @@ -1833,7 +1811,6 @@ impl Device { let mut used = BindGroupStates::new(); let buffer_guard = hub.buffers.read(); - let texture_guard = hub.textures.read(); let texture_view_guard = hub.texture_views.read(); let sampler_guard = hub.samplers.read(); @@ -1963,7 +1940,6 @@ impl Device { )?; Self::create_texture_binding( view, - &texture_guard, internal_use, pub_usage, &mut used, @@ -1991,7 +1967,6 @@ impl Device { "SampledTextureArray, ReadonlyStorageTextureArray or WriteonlyStorageTextureArray")?; Self::create_texture_binding( view, - &texture_guard, internal_use, pub_usage, &mut used, @@ -2328,8 +2303,8 @@ impl Device { self: &Arc, implicit_context: Option, mut derived_group_layouts: ArrayVec, - bgl_guard: &mut Storage, id::BindGroupLayoutId>, - pipeline_layout_guard: &mut Storage, id::PipelineLayoutId>, + bgl_registry: &Registry>, + pipeline_layout_registry: &Registry>, ) -> Result { while derived_group_layouts .last() @@ -2349,15 +2324,20 @@ impl Device { } for (bgl_id, map) in ids.group_ids.iter_mut().zip(derived_group_layouts) { - match Device::deduplicate_bind_group_layout(self.info.id(), &map, bgl_guard) { + let bgl = match Device::deduplicate_bind_group_layout( + self.info.id(), + &map, + &bgl_registry.read(), + ) { Some((dedup_id, _)) => { *bgl_id = dedup_id; + None } - None => { - let bgl = self.create_bind_group_layout(None, map)?; - bgl_guard.force_replace(*bgl_id, bgl); - } + None => Some(self.create_bind_group_layout(None, map)?), }; + if let Some(bgl) = bgl { + bgl_registry.force_replace(*bgl_id, bgl); + } } let layout_desc = binding_model::PipelineLayoutDescriptor { @@ -2365,25 +2345,23 @@ impl Device { bind_group_layouts: Cow::Borrowed(&ids.group_ids[..group_count]), push_constant_ranges: Cow::Borrowed(&[]), //TODO? }; - let layout = self.create_pipeline_layout(&layout_desc, bgl_guard)?; - pipeline_layout_guard.force_replace(ids.root_id, layout); + let layout = self.create_pipeline_layout(&layout_desc, &bgl_registry.read())?; + pipeline_layout_registry.force_replace(ids.root_id, layout); Ok(ids.root_id) } - pub(crate) fn create_compute_pipeline( + pub(crate) fn create_compute_pipeline( self: &Arc, desc: &pipeline::ComputePipelineDescriptor, implicit_context: Option, - hub: &Hub, + hub: &Hub, ) -> Result, pipeline::CreateComputePipelineError> { - //TODO: only lock mutable if the layout is derived - let mut pipeline_layout_guard = hub.pipeline_layouts.write(); - let mut bgl_guard = hub.bind_group_layouts.write(); - // This has to be done first, or otherwise the IDs may be pointing to entries // that are not even in the storage. if let Some(ref ids) = implicit_context { + let mut pipeline_layout_guard = hub.pipeline_layouts.write(); pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_FAILURE); + let mut bgl_guard = hub.bind_group_layouts.write(); for &bgl_id in ids.group_ids.iter() { bgl_guard.insert_error(bgl_id, IMPLICIT_FAILURE); } @@ -2404,11 +2382,11 @@ impl Device { { let flag = wgt::ShaderStages::COMPUTE; + let pipeline_layout_guard = hub.pipeline_layouts.read(); let provided_layouts = match desc.layout { Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts( pipeline_layout_guard .get(pipeline_layout_id) - .as_ref() .map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?, )), None => { @@ -2436,10 +2414,11 @@ impl Device { None => self.derive_pipeline_layout( implicit_context, derived_group_layouts, - &mut *bgl_guard, - &mut *pipeline_layout_guard, + &hub.bind_group_layouts, + &hub.pipeline_layouts, )?, }; + let pipeline_layout_guard = hub.pipeline_layouts.read(); let layout = pipeline_layout_guard .get(pipeline_layout_id) .map_err(|_| pipeline::CreateComputePipelineError::InvalidLayout)?; @@ -2484,22 +2463,21 @@ impl Device { Ok(pipeline) } - pub(crate) fn create_render_pipeline( + pub(crate) fn create_render_pipeline( self: &Arc, adapter: &Adapter, desc: &pipeline::RenderPipelineDescriptor, implicit_context: Option, - hub: &Hub, + hub: &Hub, ) -> Result, pipeline::CreateRenderPipelineError> { use wgt::TextureFormatFeatureFlags as Tfff; - //TODO: only lock mutable if the layout is derived - let mut pipeline_layout_guard = hub.pipeline_layouts.write(); - let mut bgl_guard = hub.bind_group_layouts.write(); - // This has to be done first, or otherwise the IDs may be pointing to entries // that are not even in the storage. if let Some(ref ids) = implicit_context { + //TODO: only lock mutable if the layout is derived + let mut pipeline_layout_guard = hub.pipeline_layouts.write(); + let mut bgl_guard = hub.bind_group_layouts.write(); pipeline_layout_guard.insert_error(ids.root_id, IMPLICIT_FAILURE); for &bgl_id in ids.group_ids.iter() { bgl_guard.insert_error(bgl_id, IMPLICIT_FAILURE); @@ -2762,6 +2740,7 @@ impl Device { } })?; + let pipeline_layout_guard = hub.pipeline_layouts.read(); let provided_layouts = match desc.layout { Some(pipeline_layout_id) => { let pipeline_layout = pipeline_layout_guard @@ -2810,6 +2789,7 @@ impl Device { error: validation::StageError::InvalidModule, })?; + let pipeline_layout_guard = hub.pipeline_layouts.read(); let provided_layouts = match desc.layout { Some(pipeline_layout_id) => Some(Device::get_introspection_bind_group_layouts( pipeline_layout_guard @@ -2889,13 +2869,17 @@ impl Device { None => self.derive_pipeline_layout( implicit_context, derived_group_layouts, - &mut *bgl_guard, - &mut *pipeline_layout_guard, + &hub.bind_group_layouts, + &hub.pipeline_layouts, )?, }; - let layout = pipeline_layout_guard - .get(pipeline_layout_id) - .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)?; + let layout = { + let pipeline_layout_guard = hub.pipeline_layouts.read(); + pipeline_layout_guard + .get(pipeline_layout_id) + .map_err(|_| pipeline::CreateRenderPipelineError::InvalidLayout)? + .clone() + }; // Multiview is only supported if the feature is enabled if desc.multiview.is_some() { @@ -2919,7 +2903,7 @@ impl Device { } let late_sized_buffer_groups = - Device::make_late_sized_buffer_groups(&shader_binding_sizes, layout); + Device::make_late_sized_buffer_groups(&shader_binding_sizes, &layout); let pipeline_desc = hal::RenderPipelineDescriptor { label: desc.label.borrow_option(), diff --git a/wgpu-core/src/global.rs b/wgpu-core/src/global.rs index 3991e4f6f8..2244a089cd 100644 --- a/wgpu-core/src/global.rs +++ b/wgpu-core/src/global.rs @@ -1,4 +1,4 @@ -use std::sync::Arc; +use std::{marker::PhantomData, sync::Arc}; use crate::{ hal_api::HalApi, @@ -6,13 +6,13 @@ use crate::{ id::SurfaceId, identity::GlobalIdentityHandlerFactory, instance::{Instance, Surface}, - registry::Registry, - storage::{Element, StorageReport}, + registry::{Registry, RegistryReport}, + storage::Element, }; #[derive(Debug, PartialEq, Eq)] pub struct GlobalReport { - pub surfaces: StorageReport, + pub surfaces: RegistryReport, #[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))] pub vulkan: Option, #[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))] @@ -25,10 +25,40 @@ pub struct GlobalReport { pub gl: Option, } +impl GlobalReport { + pub fn surfaces(&self) -> &RegistryReport { + &self.surfaces + } + pub fn hub_report(&self) -> &HubReport { + #[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))] + if self.vulkan.is_some() { + return self.vulkan.as_ref().unwrap(); + } + #[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))] + if self.metal.is_some() { + return self.metal.as_ref().unwrap(); + } + #[cfg(all(feature = "dx12", windows))] + if self.dx12.is_some() { + return self.dx12.as_ref().unwrap(); + } + #[cfg(all(feature = "dx11", windows))] + if self.dx11.is_some() { + return self.dx11.as_ref().unwrap(); + } + #[cfg(feature = "gles")] + if self.gl.is_some() { + return self.gl.as_ref().unwrap(); + } + unreachable!(); + } +} + pub struct Global { pub instance: Instance, - pub surfaces: Registry, - pub(crate) hubs: Hubs, + pub surfaces: Registry, + pub(crate) hubs: Hubs, + _phantom: PhantomData, } impl Global { @@ -38,6 +68,7 @@ impl Global { instance: Instance::new(name, instance_desc), surfaces: Registry::without_backend(&factory), hubs: Hubs::new(&factory), + _phantom: PhantomData, } } @@ -54,6 +85,7 @@ impl Global { instance: A::create_instance_from_hal(name, hal_instance), surfaces: Registry::without_backend(&factory), hubs: Hubs::new(&factory), + _phantom: PhantomData, } } @@ -73,6 +105,7 @@ impl Global { instance, surfaces: Registry::without_backend(&factory), hubs: Hubs::new(&factory), + _phantom: PhantomData, } } diff --git a/wgpu-core/src/hal_api.rs b/wgpu-core/src/hal_api.rs index df0acdac75..870557b442 100644 --- a/wgpu-core/src/hal_api.rs +++ b/wgpu-core/src/hal_api.rs @@ -11,7 +11,7 @@ pub trait HalApi: hal::Api + 'static { const VARIANT: Backend; fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance; fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance>; - fn hub(global: &Global) -> &Hub; + fn hub(global: &Global) -> &Hub; fn get_surface(surface: &Surface) -> Option<&HalSurface>; } @@ -23,7 +23,7 @@ impl HalApi for hal::api::Empty { fn instance_as_hal(_: &Instance) -> Option<&Self::Instance> { unimplemented!("called empty api") } - fn hub(_: &Global) -> &Hub { + fn hub(_: &Global) -> &Hub { unimplemented!("called empty api") } fn get_surface(_: &Surface) -> Option<&HalSurface> { @@ -44,7 +44,7 @@ impl HalApi for hal::api::Vulkan { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.vulkan.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.vulkan } fn get_surface(surface: &Surface) -> Option<&HalSurface> { @@ -65,7 +65,7 @@ impl HalApi for hal::api::Metal { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.metal.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.metal } fn get_surface(surface: &Surface) -> Option<&HalSurface> { @@ -86,7 +86,7 @@ impl HalApi for hal::api::Dx12 { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.dx12.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.dx12 } fn get_surface(surface: &Surface) -> Option<&HalSurface> { @@ -107,7 +107,7 @@ impl HalApi for hal::api::Dx11 { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.dx11.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.dx11 } fn get_surface(surface: &Surface) -> Option<&HalSurface> { @@ -129,7 +129,7 @@ impl HalApi for hal::api::Gles { fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> { instance.gl.as_ref() } - fn hub(global: &Global) -> &Hub { + fn hub(global: &Global) -> &Hub { &global.hubs.gl } fn get_surface(surface: &Surface) -> Option<&HalSurface> { diff --git a/wgpu-core/src/hub.rs b/wgpu-core/src/hub.rs index 568c395ffe..62cdfc2f0e 100644 --- a/wgpu-core/src/hub.rs +++ b/wgpu-core/src/hub.rs @@ -158,31 +158,31 @@ use crate::{ identity::GlobalIdentityHandlerFactory, instance::{Adapter, HalSurface, Surface}, pipeline::{ComputePipeline, RenderPipeline, ShaderModule}, - registry::Registry, + registry::{Registry, RegistryReport}, resource::{Buffer, QuerySet, Sampler, StagingBuffer, Texture, TextureView}, - storage::{Element, Storage, StorageReport}, + storage::{Element, Storage}, }; use std::fmt::Debug; #[derive(Debug, PartialEq, Eq)] pub struct HubReport { - pub adapters: StorageReport, - pub devices: StorageReport, - pub queues: StorageReport, - pub pipeline_layouts: StorageReport, - pub shader_modules: StorageReport, - pub bind_group_layouts: StorageReport, - pub bind_groups: StorageReport, - pub command_buffers: StorageReport, - pub render_bundles: StorageReport, - pub render_pipelines: StorageReport, - pub compute_pipelines: StorageReport, - pub query_sets: StorageReport, - pub buffers: StorageReport, - pub textures: StorageReport, - pub texture_views: StorageReport, - pub samplers: StorageReport, + pub adapters: RegistryReport, + pub devices: RegistryReport, + pub queues: RegistryReport, + pub pipeline_layouts: RegistryReport, + pub shader_modules: RegistryReport, + pub bind_group_layouts: RegistryReport, + pub bind_groups: RegistryReport, + pub command_buffers: RegistryReport, + pub render_bundles: RegistryReport, + pub render_pipelines: RegistryReport, + pub compute_pipelines: RegistryReport, + pub query_sets: RegistryReport, + pub buffers: RegistryReport, + pub textures: RegistryReport, + pub texture_views: RegistryReport, + pub samplers: RegistryReport, } impl HubReport { @@ -216,28 +216,28 @@ impl HubReport { /// /// /// [`A::hub(global)`]: HalApi::hub -pub struct Hub { - pub adapters: Registry, F>, - pub devices: Registry, F>, - pub queues: Registry, F>, - pub pipeline_layouts: Registry, F>, - pub shader_modules: Registry, F>, - pub bind_group_layouts: Registry, F>, - pub bind_groups: Registry, F>, - pub command_buffers: Registry, F>, - pub render_bundles: Registry, F>, - pub render_pipelines: Registry, F>, - pub compute_pipelines: Registry, F>, - pub query_sets: Registry, F>, - pub buffers: Registry, F>, - pub staging_buffers: Registry, F>, - pub textures: Registry, F>, - pub texture_views: Registry, F>, - pub samplers: Registry, F>, +pub struct Hub { + pub adapters: Registry>, + pub devices: Registry>, + pub queues: Registry>, + pub pipeline_layouts: Registry>, + pub shader_modules: Registry>, + pub bind_group_layouts: Registry>, + pub bind_groups: Registry>, + pub command_buffers: Registry>, + pub render_bundles: Registry>, + pub render_pipelines: Registry>, + pub compute_pipelines: Registry>, + pub query_sets: Registry>, + pub buffers: Registry>, + pub staging_buffers: Registry>, + pub textures: Registry>, + pub texture_views: Registry>, + pub samplers: Registry>, } -impl Hub { - fn new(factory: &F) -> Self { +impl Hub { + fn new(factory: &F) -> Self { Self { adapters: Registry::new(A::VARIANT, factory), devices: Registry::new(A::VARIANT, factory), @@ -341,17 +341,17 @@ impl Hub { } } -pub struct Hubs { +pub struct Hubs { #[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))] - pub(crate) vulkan: Hub, + pub(crate) vulkan: Hub, #[cfg(all(feature = "metal", any(target_os = "macos", target_os = "ios")))] - pub(crate) metal: Hub, + pub(crate) metal: Hub, #[cfg(all(feature = "dx12", windows))] - pub(crate) dx12: Hub, + pub(crate) dx12: Hub, #[cfg(all(feature = "dx11", windows))] - pub(crate) dx11: Hub, + pub(crate) dx11: Hub, #[cfg(feature = "gles")] - pub(crate) gl: Hub, + pub(crate) gl: Hub, #[cfg(all( not(all(feature = "vulkan", not(target_arch = "wasm32"))), not(all(feature = "metal", any(target_os = "macos", target_os = "ios"))), @@ -359,11 +359,11 @@ pub struct Hubs { not(all(feature = "dx11", windows)), not(feature = "gles"), ))] - pub(crate) empty: Hub, + pub(crate) empty: Hub, } -impl Hubs { - pub(crate) fn new(factory: &F) -> Self { +impl Hubs { + pub(crate) fn new(factory: &F) -> Self { Self { #[cfg(all(feature = "vulkan", not(target_arch = "wasm32")))] vulkan: Hub::new(factory), diff --git a/wgpu-core/src/id.rs b/wgpu-core/src/id.rs index 5d33309096..116fb00fa2 100644 --- a/wgpu-core/src/id.rs +++ b/wgpu-core/src/id.rs @@ -1,5 +1,10 @@ use crate::{Epoch, Index}; -use std::{cmp::Ordering, fmt, marker::PhantomData}; +use std::{ + any::Any, + cmp::Ordering, + fmt::{self, Debug}, + marker::PhantomData, +}; use wgt::Backend; #[cfg(feature = "id32")] @@ -66,7 +71,7 @@ type Dummy = hal::api::Empty; all(feature = "serde", not(feature = "replay")), derive(serde::Deserialize) )] -pub struct Id(NonZeroId, PhantomData); +pub struct Id(NonZeroId, PhantomData); // This type represents Id in a more readable (and editable) way. #[allow(dead_code)] @@ -77,7 +82,7 @@ enum SerialId { Id(Index, Epoch, Backend), } #[cfg(feature = "trace")] -impl From> for SerialId { +impl From> for SerialId { fn from(id: Id) -> Self { let (index, epoch, backend) = id.unzip(); Self::Id(index, epoch, backend) @@ -131,7 +136,7 @@ impl Clone for Id { } } -impl fmt::Debug for Id { +impl Debug for Id { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { self.unzip().fmt(formatter) } @@ -168,14 +173,14 @@ impl Ord for Id { /// Most `wgpu-core` clients should not use this trait. Unusual clients that /// need to construct `Id` values directly, or access their components, like the /// WGPU recording player, may use this trait to do so. -pub trait TypedId: Copy + std::fmt::Debug { +pub trait TypedId: Copy + Debug + Any { fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self; fn unzip(self) -> (Index, Epoch, Backend); fn into_raw(self) -> NonZeroId; } #[allow(trivial_numeric_casts)] -impl TypedId for Id { +impl TypedId for Id { fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self { assert_eq!(0, epoch >> EPOCH_BITS); assert_eq!(0, (index as IdType) >> INDEX_BITS); diff --git a/wgpu-core/src/identity.rs b/wgpu-core/src/identity.rs index fe10bedb0e..54facc7410 100644 --- a/wgpu-core/src/identity.rs +++ b/wgpu-core/src/identity.rs @@ -2,7 +2,7 @@ use parking_lot::Mutex; use wgt::Backend; use crate::{id, Epoch, Index}; -use std::fmt::Debug; +use std::{fmt::Debug, marker::PhantomData, sync::Arc}; /// A simple structure to allocate [`Id`] identifiers. /// @@ -32,7 +32,7 @@ use std::fmt::Debug; /// [`alloc`]: IdentityManager::alloc /// [`free`]: IdentityManager::free #[derive(Debug, Default)] -pub struct IdentityManager { +pub(super) struct IdentityValues { /// Available index values. If empty, then `epochs.len()` is the next index /// to allocate. free: Vec, @@ -45,14 +45,17 @@ pub struct IdentityManager { /// If index `i` is currently unused, `epochs[i]` is the epoch to use in its /// next `Id`. epochs: Vec, + + count: usize, } -impl IdentityManager { +impl IdentityValues { /// Allocate a fresh, never-before-seen id with the given `backend`. /// /// The backend is incorporated into the id, so that ids allocated with /// different `backend` values are always distinct. pub fn alloc(&mut self, backend: Backend) -> I { + self.count += 1; match self.free.pop() { Some(index) => I::zip(index, self.epochs[index as usize], backend), None => { @@ -65,7 +68,7 @@ impl IdentityManager { } /// Free `id`. It will never be returned from `alloc` again. - pub fn free(&mut self, id: I) { + pub fn release(&mut self, id: I) { let (index, epoch, _backend) = id.unzip(); let pe = &mut self.epochs[index as usize]; assert_eq!(*pe, epoch); @@ -74,56 +77,51 @@ impl IdentityManager { if epoch < id::EPOCH_MASK { *pe = epoch + 1; self.free.push(index); + self.count -= 1; } } -} - -/// A type that can build true ids from proto-ids, and free true ids. -/// -/// For some implementations, the true id is based on the proto-id. -/// The caller is responsible for providing well-allocated proto-ids. -/// -/// For other implementations, the proto-id carries no information -/// (it's `()`, say), and this `IdentityHandler` type takes care of -/// allocating a fresh true id. -/// -/// See the module-level documentation for details. -pub trait IdentityHandler: Debug { - /// The type of proto-id consumed by this filter, to produce a true id. - type Input: Clone + Debug; - /// Given a proto-id value `id`, return a true id for `backend`. - fn process(&self, id: Self::Input, backend: Backend) -> I; + pub fn count(&self) -> usize { + self.count + } +} - /// Free the true id `id`. - fn free(&self, id: I); +#[derive(Debug)] +pub struct IdentityManager { + pub(super) values: Mutex, + _phantom: PhantomData, } -impl IdentityHandler for Mutex { - type Input = (); - fn process(&self, _id: Self::Input, backend: Backend) -> I { - self.lock().alloc(backend) +impl IdentityManager { + pub fn process(&self, backend: Backend) -> I { + self.values.lock().alloc(backend) + } + pub fn free(&self, id: I) { + self.values.lock().release(id) } - fn free(&self, id: I) { - self.lock().free(id) +} + +impl IdentityManager { + pub fn new() -> Self { + Self { + values: Mutex::new(IdentityValues::default()), + _phantom: PhantomData, + } } } /// A type that can produce [`IdentityHandler`] filters for ids of type `I`. /// /// See the module-level documentation for details. -pub trait IdentityHandlerFactory { - /// The type of filter this factory constructs. - /// - /// "Filter" and "handler" seem to both mean the same thing here: - /// something that can produce true ids from proto-ids. - type Filter: IdentityHandler; - +pub trait IdentityHandlerFactory { + type Input: Copy; /// Create an [`IdentityHandler`] implementation that can /// transform proto-ids into ids of type `I`. /// /// [`IdentityHandler`]: IdentityHandler - fn spawn(&self) -> Self::Filter; + fn spawn(&self) -> Option>>; + + fn input_to_id(id_in: Self::Input) -> I; } /// A global identity handler factory based on [`IdentityManager`]. @@ -134,10 +132,15 @@ pub trait IdentityHandlerFactory { #[derive(Debug)] pub struct IdentityManagerFactory; -impl IdentityHandlerFactory for IdentityManagerFactory { - type Filter = Mutex; - fn spawn(&self) -> Self::Filter { - Mutex::new(IdentityManager::default()) +impl IdentityHandlerFactory for IdentityManagerFactory { + type Input = (); + + fn spawn(&self) -> Option>> { + Some(Arc::new(IdentityManager::new())) + } + + fn input_to_id(_id_in: Self::Input) -> I { + unreachable!("It should not be called") } } @@ -162,27 +165,22 @@ pub trait GlobalIdentityHandlerFactory: + IdentityHandlerFactory + IdentityHandlerFactory { - fn ids_are_generated_in_wgpu() -> bool; } -impl GlobalIdentityHandlerFactory for IdentityManagerFactory { - fn ids_are_generated_in_wgpu() -> bool { - true - } -} +impl GlobalIdentityHandlerFactory for IdentityManagerFactory {} -pub type Input = <>::Filter as IdentityHandler>::Input; +pub type Input = >::Input; #[test] fn test_epoch_end_of_life() { use id::TypedId as _; - let mut man = IdentityManager::default(); - man.epochs.push(id::EPOCH_MASK); - man.free.push(0); - let id1 = man.alloc::(Backend::Empty); + let man = IdentityManager::::new(); + man.values.lock().epochs.push(id::EPOCH_MASK); + man.values.lock().free.push(0); + let id1 = man.values.lock().alloc::(Backend::Empty); assert_eq!(id1.unzip().0, 0); - man.free(id1); - let id2 = man.alloc::(Backend::Empty); + man.values.lock().release(id1); + let id2 = man.values.lock().alloc::(Backend::Empty); // confirm that the index 0 is no longer re-used assert_eq!(id2.unzip().0, 1); } diff --git a/wgpu-core/src/init_tracker/buffer.rs b/wgpu-core/src/init_tracker/buffer.rs index ea9b9f6a8d..2c0fa8d372 100644 --- a/wgpu-core/src/init_tracker/buffer.rs +++ b/wgpu-core/src/init_tracker/buffer.rs @@ -1,10 +1,10 @@ use super::{InitTracker, MemoryInitKind}; -use crate::id::BufferId; -use std::ops::Range; +use crate::{hal_api::HalApi, resource::Buffer}; +use std::{ops::Range, sync::Arc}; #[derive(Debug, Clone)] -pub(crate) struct BufferInitTrackerAction { - pub id: BufferId, +pub(crate) struct BufferInitTrackerAction { + pub buffer: Arc>, pub range: Range, pub kind: MemoryInitKind, } @@ -14,22 +14,26 @@ pub(crate) type BufferInitTracker = InitTracker; impl BufferInitTracker { /// Checks if an action has/requires any effect on the initialization status /// and shrinks its range if possible. - pub(crate) fn check_action( + pub(crate) fn check_action( &self, - action: &BufferInitTrackerAction, - ) -> Option { - self.create_action(action.id, action.range.clone(), action.kind) + action: &BufferInitTrackerAction, + ) -> Option> { + self.create_action(&action.buffer, action.range.clone(), action.kind) } /// Creates an action if it would have any effect on the initialization /// status and shrinks the range if possible. - pub(crate) fn create_action( + pub(crate) fn create_action( &self, - id: BufferId, + buffer: &Arc>, query_range: Range, kind: MemoryInitKind, - ) -> Option { + ) -> Option> { self.check(query_range) - .map(|range| BufferInitTrackerAction { id, range, kind }) + .map(|range| BufferInitTrackerAction { + buffer: buffer.clone(), + range, + kind, + }) } } diff --git a/wgpu-core/src/init_tracker/texture.rs b/wgpu-core/src/init_tracker/texture.rs index 17368e1014..a859b5f784 100644 --- a/wgpu-core/src/init_tracker/texture.rs +++ b/wgpu-core/src/init_tracker/texture.rs @@ -1,7 +1,7 @@ use super::{InitTracker, MemoryInitKind}; -use crate::{id::TextureId, track::TextureSelector}; +use crate::{hal_api::HalApi, resource::Texture, track::TextureSelector}; use arrayvec::ArrayVec; -use std::ops::Range; +use std::{ops::Range, sync::Arc}; #[derive(Debug, Clone)] pub(crate) struct TextureInitRange { @@ -35,8 +35,8 @@ impl From for TextureInitRange { } #[derive(Debug, Clone)] -pub(crate) struct TextureInitTrackerAction { - pub(crate) id: TextureId, +pub(crate) struct TextureInitTrackerAction { + pub(crate) texture: Arc>, pub(crate) range: TextureInitRange, pub(crate) kind: MemoryInitKind, } @@ -57,10 +57,10 @@ impl TextureInitTracker { } } - pub(crate) fn check_action( + pub(crate) fn check_action( &self, - action: &TextureInitTrackerAction, - ) -> Option { + action: &TextureInitTrackerAction, + ) -> Option> { let mut mip_range_start = std::usize::MAX; let mut mip_range_end = std::usize::MIN; let mut layer_range_start = std::u32::MAX; @@ -85,7 +85,7 @@ impl TextureInitTracker { if mip_range_start < mip_range_end && layer_range_start < layer_range_end { Some(TextureInitTrackerAction { - id: action.id, + texture: action.texture.clone(), range: TextureInitRange { mip_range: mip_range_start as u32..mip_range_end as u32, layer_range: layer_range_start..layer_range_end, diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 91c85727bc..18fa39ba2f 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -428,10 +428,10 @@ pub enum AdapterInputs<'a, I> { Mask(Backends, fn(Backend) -> I), } -impl AdapterInputs<'_, I> { +impl AdapterInputs<'_, I> { fn find(&self, b: Backend) -> Option { match *self { - Self::IdSet(ids, ref fun) => ids.iter().find(|id| fun(id) == b).cloned(), + Self::IdSet(ids, ref fun) => ids.iter().find(|id| fun(id) == b).copied(), Self::Mask(bits, ref fun) => { if bits.contains(b.into()) { Some(fun(b)) @@ -530,7 +530,7 @@ impl Global { raw: hal_surface.unwrap(), }; - let (id, _) = self.surfaces.prepare(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); id } @@ -565,7 +565,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); id } @@ -601,7 +601,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); Ok(id) } @@ -637,7 +637,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); Ok(id) } @@ -668,7 +668,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); id } @@ -701,7 +701,7 @@ impl Global { }, }; - let (id, _) = self.surfaces.prepare(id_in).assign(surface); + let (id, _) = self.surfaces.prepare::(id_in).assign(surface); id } @@ -765,7 +765,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.clone()).assign(adapter); + let (id, _) = hub.adapters.prepare::(id_backend).assign(adapter); list.push(id); } } @@ -815,7 +815,7 @@ impl Global { log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info); let (id, _) = HalApi::hub(self) .adapters - .prepare(new_id.unwrap()) + .prepare::(new_id.unwrap()) .assign(adapter); Some(id) } @@ -829,7 +829,7 @@ impl Global { ) -> Result { profiling::scope!("Instance::pick_adapter"); - fn gather( + fn gather( _: A, instance: Option<&A::Instance>, inputs: &AdapterInputs, @@ -1007,7 +1007,7 @@ impl Global { ) -> AdapterId { profiling::scope!("Instance::create_adapter_from_hal"); - let fid = A::hub(self).adapters.prepare(input); + let fid = A::hub(self).adapters.prepare::(input); let (id, _adapter): (crate::id::Id>, Arc>) = match A::VARIANT { @@ -1128,8 +1128,8 @@ impl Global { profiling::scope!("Adapter::request_device"); let hub = A::hub(self); - let device_fid = hub.devices.prepare(device_id_in); - let queue_fid = hub.queues.prepare(queue_id_in); + let device_fid = hub.devices.prepare::(device_id_in); + let queue_fid = hub.queues.prepare::(queue_id_in); let error = loop { let adapter = match hub.adapters.get(adapter_id) { @@ -1175,8 +1175,8 @@ impl Global { profiling::scope!("Global::create_device_from_hal"); let hub = A::hub(self); - let devices_fid = hub.devices.prepare(device_id_in); - let queues_fid = hub.queues.prepare(queue_id_in); + let devices_fid = hub.devices.prepare::(device_id_in); + let queues_fid = hub.queues.prepare::(queue_id_in); let error = loop { let adapter = match hub.adapters.get(adapter_id) { diff --git a/wgpu-core/src/present.rs b/wgpu-core/src/present.rs index b768797a37..4ba25db38f 100644 --- a/wgpu-core/src/present.rs +++ b/wgpu-core/src/present.rs @@ -117,7 +117,7 @@ impl Global { let hub = A::hub(self); - let fid = hub.textures.prepare(texture_id_in); + let fid = hub.textures.prepare::(texture_id_in); let surface = self .surfaces diff --git a/wgpu-core/src/registry.rs b/wgpu-core/src/registry.rs index 627ef0def9..770738977c 100644 --- a/wgpu-core/src/registry.rs +++ b/wgpu-core/src/registry.rs @@ -5,11 +5,27 @@ use wgt::Backend; use crate::{ id, - identity::{IdentityHandler, IdentityHandlerFactory}, + identity::{IdentityHandlerFactory, IdentityManager}, resource::Resource, - storage::{InvalidId, Storage, StorageReport}, + storage::{Element, InvalidId, Storage}, }; +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] +pub struct RegistryReport { + pub num_allocated: usize, + pub num_kept_from_user: usize, + pub num_released_from_user: usize, + pub num_error: usize, + pub element_size: usize, +} + +impl RegistryReport { + pub fn is_empty(&self) -> bool { + self.num_allocated + self.num_kept_from_user + self.num_released_from_user + self.num_error + == 0 + } +} + /// Registry is the primary holder of each resource type /// Every resource is now arcanized so the last arc released /// will in the end free the memory and release the inner raw resource @@ -22,14 +38,14 @@ use crate::{ /// any other dependent resource /// #[derive(Debug)] -pub struct Registry, F: IdentityHandlerFactory> { - identity: F::Filter, +pub struct Registry> { + identity: Option>>, storage: RwLock>, backend: Backend, } -impl, F: IdentityHandlerFactory> Registry { - pub(crate) fn new(backend: Backend, factory: &F) -> Self { +impl> Registry { + pub(crate) fn new>(backend: Backend, factory: &F) -> Self { Self { identity: factory.spawn(), storage: RwLock::new(Storage::new()), @@ -37,7 +53,7 @@ impl, F: IdentityHandlerFactory> Registry Self { + pub(crate) fn without_backend>(factory: &F) -> Self { Self::new(Backend::Empty, factory) } } @@ -45,6 +61,7 @@ impl, F: IdentityHandlerFactory> Registry> { id: I, + identity: Option>>, data: &'a RwLock>, } @@ -59,27 +76,41 @@ impl> FutureId<'_, I, T> { } pub fn assign(self, mut value: T) -> (I, Arc) { - value.as_info_mut().set_id(self.id); + value.as_info_mut().set_id(self.id, &self.identity); self.data.write().insert(self.id, Arc::new(value)); (self.id, self.data.read().get(self.id).unwrap().clone()) } + pub fn assign_existing(self, value: &Arc) -> I { + #[cfg(debug_assertions)] + debug_assert!(!self.data.read().contains(self.id)); + self.data.write().insert(self.id, value.clone()); + self.id + } + pub fn assign_error(self, label: &str) -> I { self.data.write().insert_error(self.id, label); self.id } } -impl, F: IdentityHandlerFactory> Registry { - pub(crate) fn prepare( - &self, - id_in: >::Input, - ) -> FutureId { +impl> Registry { + pub(crate) fn prepare(&self, id_in: F::Input) -> FutureId + where + F: IdentityHandlerFactory, + { FutureId { - id: self.identity.process(id_in, self.backend), + id: match self.identity.as_ref() { + Some(identity) => identity.process(self.backend), + _ => F::input_to_id(id_in), + }, + identity: self.identity.clone(), data: &self.storage, } } + pub(crate) fn contains(&self, id: I) -> bool { + self.read().contains(id) + } pub(crate) fn try_get(&self, id: I) -> Result>, InvalidId> { self.read().try_get(id).map(|o| o.cloned()) } @@ -93,16 +124,15 @@ impl, F: IdentityHandlerFactory> Regist self.storage.write() } pub fn unregister_locked(&self, id: I, storage: &mut Storage) -> Option> { - let value = storage.remove(id); - //Note: careful about the order here! - self.identity.free(id); - //Returning None is legal if it's an error ID - value + storage.remove(id) + } + pub fn force_replace(&self, id: I, mut value: T) { + let mut storage = self.storage.write(); + value.as_info_mut().set_id(id, &self.identity); + storage.force_replace(id, value) } pub(crate) fn unregister(&self, id: I) -> Option> { let value = self.storage.write().remove(id); - //Note: careful about the order here! - self.identity.free(id); //Returning None is legal if it's an error ID value } @@ -128,7 +158,22 @@ impl, F: IdentityHandlerFactory> Regist } } - pub(crate) fn generate_report(&self) -> StorageReport { - self.storage.read().generate_report() + pub(crate) fn generate_report(&self) -> RegistryReport { + let storage = self.storage.read(); + let mut report = RegistryReport { + element_size: std::mem::size_of::(), + ..Default::default() + }; + if let Some(identity) = self.identity.as_ref() { + report.num_allocated = identity.values.lock().count(); + } + for element in storage.map.iter() { + match *element { + Element::Occupied(..) => report.num_kept_from_user += 1, + Element::Vacant => report.num_released_from_user += 1, + Element::Error(..) => report.num_error += 1, + } + } + report } } diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 4632473092..7b582e5cf7 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -1,18 +1,25 @@ +#[cfg(feature = "trace")] +use crate::device::trace; use crate::{ - device::{Device, DeviceError, HostMap, MissingDownlevelFlags, MissingFeatures}, + device::{ + queue, BufferMapPendingClosure, Device, DeviceError, HostMap, MissingDownlevelFlags, + MissingFeatures, + }, global::Global, hal_api::HalApi, id::{ AdapterId, BufferId, DeviceId, QuerySetId, SamplerId, StagingBufferId, SurfaceId, TextureId, TextureViewId, TypedId, }, - identity::GlobalIdentityHandlerFactory, + identity::{GlobalIdentityHandlerFactory, IdentityManager}, init_tracker::{BufferInitTracker, TextureInitTracker}, + resource, track::TextureSelector, validation::MissingBufferUsageError, Label, SubmissionIndex, }; +use hal::CommandEncoder; use parking_lot::{Mutex, RwLock}; use smallvec::SmallVec; use thiserror::Error; @@ -20,6 +27,7 @@ use thiserror::Error; use std::{ borrow::Borrow, fmt::Debug, + iter, mem, ops::Range, ptr::NonNull, sync::{ @@ -50,6 +58,7 @@ use std::{ #[derive(Debug)] pub struct ResourceInfo { id: Option, + identity: Option>>, /// The index of the last queue submission in which the resource /// was used. /// @@ -64,11 +73,22 @@ pub struct ResourceInfo { pub(crate) label: String, } +impl Drop for ResourceInfo { + fn drop(&mut self) { + if let Some(identity) = self.identity.as_ref() { + let id = self.id.as_ref().unwrap(); + identity.free(*id); + log::info!("Freeing {:?}", self.label()); + } + } +} + impl ResourceInfo { #[allow(unused_variables)] pub(crate) fn new(label: &str) -> Self { Self { id: None, + identity: None, submission_index: AtomicUsize::new(0), #[cfg(debug_assertions)] label: label.to_string(), @@ -95,8 +115,9 @@ impl ResourceInfo { self.id.unwrap() } - pub(crate) fn set_id(&mut self, id: Id) { + pub(crate) fn set_id(&mut self, id: Id, identity: &Option>>) { self.id = Some(id); + self.identity = identity.clone(); } /// Record that this resource will be used by the queue submission with the @@ -419,6 +440,157 @@ impl Buffer { pub(crate) fn raw(&self) -> &A::Buffer { self.raw.as_ref().unwrap() } + + pub(crate) fn buffer_unmap_inner( + self: &Arc, + ) -> Result, BufferAccessError> { + use hal::Device; + + let device = &self.device; + let buffer_id = self.info.id(); + log::debug!("Buffer {:?} map state -> Idle", buffer_id); + match mem::replace(&mut *self.map_state.lock(), resource::BufferMapState::Idle) { + resource::BufferMapState::Init { + ptr, + stage_buffer, + needs_flush, + } => { + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + let data = trace.make_binary("bin", unsafe { + std::slice::from_raw_parts(ptr.as_ptr(), self.size as usize) + }); + trace.add(trace::Action::WriteBuffer { + id: buffer_id, + data, + range: 0..self.size, + queued: true, + }); + } + let _ = ptr; + if needs_flush { + unsafe { + device + .raw() + .flush_mapped_ranges(stage_buffer.raw(), iter::once(0..self.size)); + } + } + + let raw_buf = self.raw.as_ref().ok_or(BufferAccessError::Destroyed)?; + + self.info + .use_at(device.active_submission_index.load(Ordering::Relaxed) + 1); + let region = wgt::BufferSize::new(self.size).map(|size| hal::BufferCopy { + src_offset: 0, + dst_offset: 0, + size, + }); + let transition_src = hal::BufferBarrier { + buffer: stage_buffer.raw(), + usage: hal::BufferUses::MAP_WRITE..hal::BufferUses::COPY_SRC, + }; + let transition_dst = hal::BufferBarrier { + buffer: raw_buf, + usage: hal::BufferUses::empty()..hal::BufferUses::COPY_DST, + }; + let mut pending_writes = device.pending_writes.lock(); + let pending_writes = pending_writes.as_mut().unwrap(); + let encoder = pending_writes.activate(); + unsafe { + encoder.transition_buffers( + iter::once(transition_src).chain(iter::once(transition_dst)), + ); + if self.size > 0 { + encoder.copy_buffer_to_buffer( + stage_buffer.raw(), + raw_buf, + region.into_iter(), + ); + } + } + pending_writes.consume_temp(queue::TempResource::Buffer(stage_buffer)); + pending_writes.dst_buffers.insert(buffer_id, self.clone()); + } + resource::BufferMapState::Idle => { + return Err(BufferAccessError::NotMapped); + } + resource::BufferMapState::Waiting(pending) => { + return Ok(Some((pending.op, Err(BufferAccessError::MapAborted)))); + } + resource::BufferMapState::Active { ptr, range, host } => { + if host == HostMap::Write { + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + let size = range.end - range.start; + let data = trace.make_binary("bin", unsafe { + std::slice::from_raw_parts(ptr.as_ptr(), size as usize) + }); + trace.add(trace::Action::WriteBuffer { + id: buffer_id, + data, + range: range.clone(), + queued: false, + }); + } + let _ = (ptr, range); + } + unsafe { + device + .raw() + .unmap_buffer(self.raw()) + .map_err(DeviceError::from)? + }; + } + } + Ok(None) + } + + pub(crate) fn destroy(self: &Arc) -> Result<(), DestroyError> { + let map_closure; + // Restrict the locks to this scope. + { + let device = &self.device; + let buffer_id = self.info.id(); + + map_closure = match &*self.map_state.lock() { + &BufferMapState::Waiting(..) // To get the proper callback behavior. + | &BufferMapState::Init { .. } + | &BufferMapState::Active { .. } + => { + self.buffer_unmap_inner() + .unwrap_or(None) + } + _ => None, + }; + + #[cfg(feature = "trace")] + if let Some(ref mut trace) = *device.trace.lock() { + trace.add(trace::Action::FreeBuffer(buffer_id)); + } + if self.raw.is_none() { + return Err(resource::DestroyError::AlreadyDestroyed); + } + + let temp = queue::TempResource::Buffer(self.clone()); + let mut pending_writes = device.pending_writes.lock(); + let pending_writes = pending_writes.as_mut().unwrap(); + if pending_writes.dst_buffers.contains_key(&buffer_id) { + pending_writes.temp_resources.push(temp); + } else { + let last_submit_index = self.info.submission_index(); + device + .lock_life() + .schedule_resource_destruction(temp, last_submit_index); + } + } + + // Note: outside the scope where locks are held when calling the callback + if let Some((operation, status)) = map_closure { + operation.callback.call(status); + } + + Ok(()) + } } #[derive(Clone, Debug, Error)] @@ -855,9 +1027,6 @@ pub struct TextureView { pub(crate) raw: Option, // if it's a surface texture - it's none pub(crate) parent: Option>>, - // The parent's refcount is held alive, but the parent may still be deleted - // if it's a surface texture. TODO: make this cleaner. - pub(crate) parent_id: TextureId, pub(crate) device: Arc>, //TODO: store device_id for quick access? pub(crate) desc: HalTextureViewDescriptor, diff --git a/wgpu-core/src/storage.rs b/wgpu-core/src/storage.rs index dbf85482df..de78905a27 100644 --- a/wgpu-core/src/storage.rs +++ b/wgpu-core/src/storage.rs @@ -1,4 +1,4 @@ -use std::{marker::PhantomData, mem, ops, sync::Arc}; +use std::{marker::PhantomData, ops, sync::Arc}; use wgt::Backend; @@ -21,20 +21,6 @@ pub(crate) enum Element { Error(Epoch, String), } -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub struct StorageReport { - pub num_occupied: usize, - pub num_vacant: usize, - pub num_error: usize, - pub element_size: usize, -} - -impl StorageReport { - pub fn is_empty(&self) -> bool { - self.num_occupied + self.num_vacant + self.num_error == 0 - } -} - #[derive(Clone, Debug)] pub(crate) struct InvalidId; @@ -83,6 +69,7 @@ where T: Resource, I: id::TypedId, { + #[allow(dead_code)] pub(crate) fn contains(&self, id: I) -> bool { let (index, epoch, _) = id.unzip(); match self.map.get(index as usize) { @@ -117,24 +104,6 @@ where result } - /// Get refcount of an item with specified ID - /// And return true if it's 1 or false otherwise - pub(crate) fn is_unique(&self, id: I) -> Result { - let (index, epoch, _) = id.unzip(); - let (result, storage_epoch) = match self.map.get(index as usize) { - Some(&Element::Occupied(ref v, epoch)) => (Ok(v.is_unique()), epoch), - Some(&Element::Vacant) => panic!("{}[{:?}] does not exist", self.kind, id), - Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch), - None => return Err(InvalidId), - }; - assert_eq!( - epoch, storage_epoch, - "{}[{:?}] is no longer alive", - self.kind, id - ); - result - } - /// 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: I) -> Result<&Arc, InvalidId> { @@ -153,14 +122,6 @@ where result } - pub(crate) unsafe fn get_unchecked(&self, id: u32) -> &Arc { - match self.map[id as usize] { - Element::Occupied(ref v, _) => v, - Element::Vacant => panic!("{}[{}] does not exist", self.kind, id), - Element::Error(_, _) => panic!(""), - } - } - pub(crate) fn label_for_invalid_id(&self, id: I) -> &str { let (index, _, _) = id.unzip(); match self.map.get(index as usize) { @@ -180,22 +141,25 @@ where } pub(crate) fn insert(&mut self, id: I, value: Arc) { + log::info!("User is inserting {}{:?}", T::TYPE, id); let (index, epoch, _backend) = id.unzip(); self.insert_impl(index as usize, Element::Occupied(value, epoch)) } pub(crate) fn insert_error(&mut self, id: I, label: &str) { + log::info!("User is insering as error {}{:?}", T::TYPE, id); let (index, epoch, _) = id.unzip(); self.insert_impl(index as usize, Element::Error(epoch, label.to_string())) } - pub(crate) fn force_replace(&mut self, id: I, mut value: T) { + pub(crate) fn force_replace(&mut self, id: I, value: T) { + log::info!("User is replacing {}{:?}", T::TYPE, id); let (index, epoch, _) = id.unzip(); - value.as_info_mut().set_id(id); self.map[index as usize] = Element::Occupied(Arc::new(value), epoch); } pub(crate) fn remove(&mut self, id: I) -> Option> { + log::info!("User is removing {}{:?}", T::TYPE, id); let (index, epoch, _) = id.unzip(); match std::mem::replace(&mut self.map[index as usize], Element::Vacant) { Element::Occupied(value, storage_epoch) => { @@ -207,21 +171,6 @@ where } } - // Prevents panic on out of range access, allows Vacant elements. - pub(crate) fn _try_remove(&mut self, id: I) -> Option> { - let (index, epoch, _) = id.unzip(); - if index as usize >= self.map.len() { - None - } else if let Element::Occupied(value, storage_epoch) = - std::mem::replace(&mut self.map[index as usize], Element::Vacant) - { - assert_eq!(epoch, storage_epoch); - Some(value) - } else { - None - } - } - pub(crate) fn iter(&self, backend: Backend) -> impl Iterator)> { self.map .iter() @@ -241,19 +190,4 @@ where pub(crate) fn len(&self) -> usize { self.map.len() } - - pub(crate) fn generate_report(&self) -> StorageReport { - let mut report = StorageReport { - element_size: mem::size_of::(), - ..Default::default() - }; - for element in self.map.iter() { - match *element { - Element::Occupied(..) => report.num_occupied += 1, - Element::Vacant => report.num_vacant += 1, - Element::Error(..) => report.num_error += 1, - } - } - report - } } diff --git a/wgpu-core/src/track/buffer.rs b/wgpu-core/src/track/buffer.rs index 32e5dce28b..973684419b 100644 --- a/wgpu-core/src/track/buffer.rs +++ b/wgpu-core/src/track/buffer.rs @@ -5,20 +5,20 @@ * one subresource, they have no selector. !*/ -use std::{borrow::Cow, marker::PhantomData, sync::Arc, vec::Drain}; +use std::{borrow::Cow, marker::PhantomData, sync::Arc}; use super::PendingTransition; use crate::{ hal_api::HalApi, id::{BufferId, TypedId}, - resource::Buffer, + resource::{Buffer, Resource}, storage::Storage, track::{ invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider, ResourceUses, UsageConflict, }, }; -use hal::BufferUses; +use hal::{BufferBarrier, BufferUses}; use wgt::{strict_assert, strict_assert_eq}; impl ResourceUses for BufferUses { @@ -43,7 +43,7 @@ impl ResourceUses for BufferUses { /// Stores all the buffers that a bind group stores. #[derive(Debug)] pub(crate) struct BufferBindGroupState { - buffers: Vec<(BufferId, Arc>, BufferUses)>, + buffers: Vec<(Arc>, BufferUses)>, _phantom: PhantomData, } @@ -60,19 +60,22 @@ impl BufferBindGroupState { /// /// When this list of states is merged into a tracker, the memory /// accesses will be in a constant assending order. + #[allow(clippy::pattern_type_mismatch)] pub(crate) fn optimize(&mut self) { self.buffers - .sort_unstable_by_key(|&(id, _, _)| id.unzip().0); + .sort_unstable_by_key(|(b, _)| b.as_info().id().unzip().0); } /// Returns a list of all buffers tracked. May contain duplicates. + #[allow(clippy::pattern_type_mismatch)] pub fn used_ids(&self) -> impl Iterator + '_ { - self.buffers.iter().map(|&(id, _, _)| id) + self.buffers.iter().map(|(ref b, _)| b.as_info().id()) } /// Returns a list of all buffers tracked. May contain duplicates. + #[allow(clippy::pattern_type_mismatch)] pub fn used_resources(&self) -> impl Iterator>> + '_ { - self.buffers.iter().map(|&(_id, ref buffer, _u)| buffer) + self.buffers.iter().map(|(ref buffer, _u)| buffer) } /// Adds the given resource with the given state. @@ -81,10 +84,10 @@ impl BufferBindGroupState { storage: &'a Storage, BufferId>, id: BufferId, state: BufferUses, - ) -> Option<&'a Buffer> { + ) -> Option<&'a Arc>> { let buffer = storage.get(id).ok()?; - self.buffers.push((id, buffer.clone(), state)); + self.buffers.push((buffer.clone(), state)); Some(buffer) } @@ -133,6 +136,20 @@ impl BufferUsageScope { self.metadata.owned_resources() } + pub fn get(&self, id: BufferId) -> Option<&Arc>> { + let index = id.unzip().0 as usize; + if index > self.metadata.size() { + return None; + } + self.tracker_assert_in_bounds(index); + unsafe { + if self.metadata.contains_unchecked(index) { + return Some(self.metadata.get_resource_unchecked(index)); + } + } + None + } + /// Merge the list of buffer states in the given bind group into this usage scope. /// /// If any of the resulting states is invalid, stops the merge and returns a usage @@ -149,8 +166,8 @@ impl BufferUsageScope { &mut self, bind_group: &BufferBindGroupState, ) -> Result<(), UsageConflict> { - for &(id, ref resource, state) in &bind_group.buffers { - let index = id.unzip().0 as usize; + for &(ref resource, state) in &bind_group.buffers { + let index = resource.as_info().id().unzip().0 as usize; unsafe { insert_or_merge( @@ -219,7 +236,7 @@ impl BufferUsageScope { storage: &'a Storage, BufferId>, id: BufferId, new_state: BufferUses, - ) -> Result<&'a Buffer, UsageConflict> { + ) -> Result<&'a Arc>, UsageConflict> { let buffer = storage .get(id) .map_err(|_| UsageConflict::BufferInvalid { id })?; @@ -302,8 +319,12 @@ impl BufferTracker { } /// Drains all currently pending transitions. - pub fn drain(&mut self) -> Drain<'_, PendingTransition> { - self.temp.drain(..) + pub fn drain_transitions(&mut self) -> impl Iterator> { + let buffer_barriers = self.temp.drain(..).map(|pending| { + let buf = unsafe { self.metadata.get_resource_unchecked(pending.id as _) }; + pending.into_hal(buf) + }); + buffer_barriers } /// Inserts a single buffer and its state into the resource tracker. @@ -347,15 +368,8 @@ 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 set_single<'a>( - &mut self, - storage: &'a Storage, BufferId>, - id: BufferId, - state: BufferUses, - ) -> SetSingleResult { - let buffer = storage.get(id).ok()?; - - let index = id.unzip().0 as usize; + pub fn set_single(&mut self, buffer: &Arc>, state: BufferUses) -> SetSingleResult { + let index: usize = buffer.as_info().id().unzip().0 as usize; self.allow_index(index); @@ -385,7 +399,7 @@ impl BufferTracker { /// /// If a transition is needed to get the buffers into the needed state, /// those transitions are stored within the tracker. A subsequent - /// call to [`Self::drain`] is needed to get those transitions. + /// call to [`Self::drain_transitions`] is needed to get those transitions. /// /// If the ID is higher than the length of internal vectors, /// the vectors will be extended. A call to set_size is not needed. @@ -423,7 +437,7 @@ impl BufferTracker { /// /// If a transition is needed to get the buffers into the needed state, /// those transitions are stored within the tracker. A subsequent - /// call to [`Self::drain`] is needed to get those transitions. + /// call to [`Self::drain_transitions`] is needed to get those transitions. /// /// If the ID is higher than the length of internal vectors, /// the vectors will be extended. A call to set_size is not needed. @@ -461,7 +475,7 @@ impl BufferTracker { /// /// If a transition is needed to get the buffers into the needed state, /// those transitions are stored within the tracker. A subsequent - /// call to [`Self::drain`] is needed to get those transitions. + /// call to [`Self::drain_transitions`] is needed to get those transitions. /// /// This is a really funky method used by Compute Passes to generate /// barriers after a call to dispatch without needing to iterate @@ -513,6 +527,21 @@ impl BufferTracker { } } + #[allow(dead_code)] + pub fn get(&self, id: BufferId) -> Option<&Arc>> { + let index = id.unzip().0 as usize; + if index > self.metadata.size() { + return None; + } + self.tracker_assert_in_bounds(index); + unsafe { + if self.metadata.contains_unchecked(index) { + return Some(self.metadata.get_resource_unchecked(index)); + } + } + None + } + /// Removes the buffer `id` from this tracker if it is otherwise unused. /// /// A buffer is 'otherwise unused' when the only references to it are: @@ -534,7 +563,7 @@ impl BufferTracker { /// [`Device::trackers`]: crate::device::Device /// [`self.metadata`]: BufferTracker::metadata /// [`Hub::buffers`]: crate::hub::Hub::buffers - pub fn remove_abandoned(&mut self, id: BufferId) -> bool { + pub fn remove_abandoned(&mut self, id: BufferId, is_in_registry: bool) -> bool { let index = id.unzip().0 as usize; if index > self.metadata.size() { @@ -546,7 +575,10 @@ impl BufferTracker { unsafe { if self.metadata.contains_unchecked(index) { let existing_ref_count = self.metadata.get_ref_count_unchecked(index); - if existing_ref_count <= 3 { + //2 ref count if only in Device Tracker and suspected resource itself and already released from user + //so not appearing in Registry + let min_ref_count = if is_in_registry { 3 } else { 2 }; + if existing_ref_count <= min_ref_count { self.metadata.remove(index); return true; } else { diff --git a/wgpu-core/src/track/mod.rs b/wgpu-core/src/track/mod.rs index 71936dbb86..f51d736a1f 100644 --- a/wgpu-core/src/track/mod.rs +++ b/wgpu-core/src/track/mod.rs @@ -401,14 +401,10 @@ impl RenderBundleScope { /// length of the storage given at the call to `new`. pub unsafe fn merge_bind_group( &mut self, - textures: &Storage, id::TextureId>, bind_group: &BindGroupStates, ) -> Result<(), UsageConflict> { unsafe { self.buffers.merge_bind_group(&bind_group.buffers)? }; - unsafe { - self.textures - .merge_bind_group(textures, &bind_group.textures)? - }; + unsafe { self.textures.merge_bind_group(&bind_group.textures)? }; Ok(()) } @@ -450,13 +446,11 @@ impl UsageScope { /// length of the storage given at the call to `new`. pub unsafe fn merge_bind_group( &mut self, - textures: &Storage, id::TextureId>, bind_group: &BindGroupStates, ) -> Result<(), UsageConflict> { unsafe { self.buffers.merge_bind_group(&bind_group.buffers)?; - self.textures - .merge_bind_group(textures, &bind_group.textures)?; + self.textures.merge_bind_group(&bind_group.textures)?; } Ok(()) @@ -473,12 +467,10 @@ impl UsageScope { /// length of the storage given at the call to `new`. pub unsafe fn merge_render_bundle( &mut self, - textures: &Storage, id::TextureId>, render_bundle: &RenderBundleScope, ) -> Result<(), UsageConflict> { self.buffers.merge_usage_scope(&render_bundle.buffers)?; - self.textures - .merge_usage_scope(textures, &render_bundle.textures)?; + self.textures.merge_usage_scope(&render_bundle.textures)?; Ok(()) } @@ -578,7 +570,6 @@ impl Tracker { /// value given to `set_size` pub unsafe fn set_and_remove_from_usage_scope_sparse( &mut self, - textures: &Storage, id::TextureId>, scope: &mut UsageScope, bind_group: &BindGroupStates, ) { @@ -589,11 +580,8 @@ impl Tracker { ) }; unsafe { - self.textures.set_and_remove_from_usage_scope_sparse( - textures, - &mut scope.textures, - &bind_group.textures, - ) + self.textures + .set_and_remove_from_usage_scope_sparse(&mut scope.textures, &bind_group.textures) }; } diff --git a/wgpu-core/src/track/stateless.rs b/wgpu-core/src/track/stateless.rs index 08d05c4703..f565932f8b 100644 --- a/wgpu-core/src/track/stateless.rs +++ b/wgpu-core/src/track/stateless.rs @@ -32,15 +32,8 @@ impl> StatelessBindGroupSate { } /// Returns a list of all resources tracked. May contain duplicates. - pub fn used(&self) -> impl Iterator + '_ { - self.resources.iter().map(|&(id, _)| id) - } - - /// Returns a list of all resources tracked. May contain duplicates. - pub fn used_resources(&self) -> impl Iterator> + '_ { - self.resources - .iter() - .map(|&(_, ref resource)| resource.clone()) + pub fn used_resources(&self) -> impl Iterator> + '_ { + self.resources.iter().map(|&(_, ref resource)| resource) } /// Adds the given resource. @@ -158,6 +151,20 @@ impl> StatelessTracker { } } + pub fn get(&self, id: Id) -> Option<&Arc> { + let index = id.unzip().0 as usize; + if index > self.metadata.size() { + return None; + } + self.tracker_assert_in_bounds(index); + unsafe { + if self.metadata.contains_unchecked(index) { + return Some(self.metadata.get_resource_unchecked(index)); + } + } + None + } + /// Removes the given resource from the tracker iff we have the last reference to the /// resource and the epoch matches. /// @@ -165,7 +172,7 @@ impl> StatelessTracker { /// /// If the ID is higher than the length of internal vectors, /// false will be returned. - pub fn remove_abandoned(&mut self, id: Id) -> bool { + pub fn remove_abandoned(&mut self, id: Id, is_in_registry: bool) -> bool { let index = id.unzip().0 as usize; if index > self.metadata.size() { @@ -177,8 +184,10 @@ impl> StatelessTracker { unsafe { if self.metadata.contains_unchecked(index) { let existing_ref_count = self.metadata.get_ref_count_unchecked(index); - //3 ref count: Registry, Device Tracker and suspected resource itself - if existing_ref_count <= 3 { + //2 ref count if only in Device Tracker and suspected resource itself and already released from user + //so not appearing in Registry + let min_ref_count = if is_in_registry { 3 } else { 2 }; + if existing_ref_count <= min_ref_count { self.metadata.remove(index); return true; } else { diff --git a/wgpu-core/src/track/texture.rs b/wgpu-core/src/track/texture.rs index 6666f74872..a90888a86d 100644 --- a/wgpu-core/src/track/texture.rs +++ b/wgpu-core/src/track/texture.rs @@ -23,14 +23,13 @@ use super::{range::RangedStates, PendingTransition}; use crate::{ hal_api::HalApi, id::{TextureId, TypedId}, - resource::Texture, - storage::Storage, + resource::{Resource, Texture}, track::{ invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider, ResourceUses, UsageConflict, }, }; -use hal::TextureUses; +use hal::{TextureBarrier, TextureUses}; use arrayvec::ArrayVec; use naga::FastHashMap; @@ -150,7 +149,6 @@ impl ComplexTextureState { #[derive(Debug)] struct TextureBindGroupStateData { - id: TextureId, selector: Option, texture: Arc>, usage: TextureUses, @@ -173,7 +171,8 @@ impl TextureBindGroupState { /// When this list of states is merged into a tracker, the memory /// accesses will be in a constant assending order. pub(crate) fn optimize(&mut self) { - self.textures.sort_unstable_by_key(|v| v.id.unzip().0); + self.textures + .sort_unstable_by_key(|v| v.texture.as_info().id().unzip().0); } /// Returns a list of all textures tracked. May contain duplicates. @@ -184,21 +183,16 @@ impl TextureBindGroupState { /// Adds the given resource with the given state. pub fn add_single<'a>( &mut self, - storage: &'a Storage, TextureId>, - id: TextureId, + texture: &'a Arc>, selector: Option, state: TextureUses, - ) -> Option<&'a Texture> { - let resource = storage.get(id).ok()?; - + ) -> Option<&'a Arc>> { self.textures.push(TextureBindGroupStateData { - id, selector, - texture: resource.clone(), + texture: texture.clone(), usage: state, }); - - Some(resource) + Some(texture) } } @@ -280,11 +274,7 @@ impl TextureUsageScope { /// /// If the given tracker uses IDs higher than the length of internal vectors, /// the vectors will be extended. A call to set_size is not needed. - pub fn merge_usage_scope( - &mut self, - storage: &Storage, TextureId>, - scope: &Self, - ) -> Result<(), UsageConflict> { + pub fn merge_usage_scope(&mut self, scope: &Self) -> Result<(), UsageConflict> { let incoming_size = scope.set.simple.len(); if incoming_size > self.set.simple.len() { self.set_size(incoming_size); @@ -294,7 +284,8 @@ impl TextureUsageScope { self.tracker_assert_in_bounds(index); scope.tracker_assert_in_bounds(index); - let texture_selector = unsafe { texture_selector_from_texture(storage, index) }; + let texture_selector = + unsafe { &scope.metadata.get_resource_unchecked(index).full_range }; unsafe { insert_or_merge( texture_selector, @@ -326,11 +317,10 @@ impl TextureUsageScope { /// method is called. pub unsafe fn merge_bind_group( &mut self, - storage: &Storage, TextureId>, bind_group: &TextureBindGroupState, ) -> Result<(), UsageConflict> { for t in &bind_group.textures { - unsafe { self.merge_single(storage, t.id, t.selector.clone(), t.usage)? }; + unsafe { self.merge_single(&t.texture, t.selector.clone(), t.usage)? }; } Ok(()) @@ -351,17 +341,15 @@ impl TextureUsageScope { /// method is called. pub unsafe fn merge_single( &mut self, - storage: &Storage, TextureId>, - id: TextureId, + texture: &Arc>, selector: Option, new_state: TextureUses, ) -> Result<(), UsageConflict> { - let index = id.unzip().0 as usize; - let resource = storage.get(id).unwrap(); + let index = texture.as_info().id().unzip().0 as usize; self.tracker_assert_in_bounds(index); - let texture_selector = unsafe { texture_selector_from_texture(storage, index) }; + let texture_selector = &texture.full_range; unsafe { insert_or_merge( texture_selector, @@ -370,7 +358,7 @@ impl TextureUsageScope { index, TextureStateProvider::from_option(selector, new_state), ResourceMetadataProvider::Direct { - resource: Cow::Borrowed(resource), + resource: Cow::Borrowed(texture), }, )? }; @@ -450,8 +438,12 @@ impl TextureTracker { } /// Drains all currently pending transitions. - pub fn drain(&mut self) -> Drain> { - self.temp.drain(..) + pub fn drain_transitions(&mut self) -> impl Iterator> { + let texture_barriers = self.temp.drain(..).map(|pending| { + let tex = unsafe { self.metadata.get_resource_unchecked(pending.id as _) }; + pending.into_hal(tex) + }); + texture_barriers } /// Inserts a single texture and a state into the resource tracker. @@ -499,11 +491,10 @@ impl TextureTracker { pub fn set_single( &mut self, texture: &Arc>, - id: TextureId, selector: TextureSelector, new_state: TextureUses, ) -> Option>> { - let index = id.unzip().0 as usize; + let index = texture.as_info().id().unzip().0 as usize; self.allow_index(index); @@ -535,11 +526,11 @@ impl TextureTracker { /// /// If a transition is needed to get the texture into the needed state, /// those transitions are stored within the tracker. A subsequent - /// call to [`Self::drain`] is needed to get those transitions. + /// call to [`Self::drain_transitions`] is needed to get those transitions. /// /// 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 set_from_tracker(&mut self, storage: &Storage, TextureId>, tracker: &Self) { + pub fn set_from_tracker(&mut self, tracker: &Self) { let incoming_size = tracker.start_set.simple.len(); if incoming_size > self.start_set.simple.len() { self.set_size(incoming_size); @@ -549,7 +540,7 @@ impl TextureTracker { self.tracker_assert_in_bounds(index); tracker.tracker_assert_in_bounds(index); unsafe { - let texture_selector = texture_selector_from_texture(storage, index); + let texture_selector = &tracker.metadata.get_resource_unchecked(index).full_range; insert_or_barrier_update( texture_selector, Some(&mut self.start_set), @@ -575,15 +566,11 @@ impl TextureTracker { /// /// If a transition is needed to get the textures into the needed state, /// those transitions are stored within the tracker. A subsequent - /// call to [`Self::drain`] is needed to get those transitions. + /// call to [`Self::drain_transitions`] is needed to get those transitions. /// /// 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 set_from_usage_scope( - &mut self, - storage: &Storage, TextureId>, - scope: &TextureUsageScope, - ) { + pub fn set_from_usage_scope(&mut self, scope: &TextureUsageScope) { let incoming_size = scope.set.simple.len(); if incoming_size > self.start_set.simple.len() { self.set_size(incoming_size); @@ -593,7 +580,7 @@ impl TextureTracker { self.tracker_assert_in_bounds(index); scope.tracker_assert_in_bounds(index); unsafe { - let texture_selector = texture_selector_from_texture(storage, index); + let texture_selector = &scope.metadata.get_resource_unchecked(index).full_range; insert_or_barrier_update( texture_selector, Some(&mut self.start_set), @@ -617,7 +604,7 @@ impl TextureTracker { /// /// If a transition is needed to get the textures into the needed state, /// those transitions are stored within the tracker. A subsequent - /// call to [`Self::drain`] is needed to get those transitions. + /// call to [`Self::drain_transitions`] is needed to get those transitions. /// /// This is a really funky method used by Compute Passes to generate /// barriers after a call to dispatch without needing to iterate @@ -631,7 +618,6 @@ impl TextureTracker { /// method is called. pub unsafe fn set_and_remove_from_usage_scope_sparse( &mut self, - storage: &Storage, TextureId>, scope: &mut TextureUsageScope, bind_group_state: &TextureBindGroupState, ) { @@ -641,13 +627,13 @@ impl TextureTracker { } for t in bind_group_state.textures.iter() { - let index = t.id.unzip().0 as usize; + let index = t.texture.as_info().id().unzip().0 as usize; scope.tracker_assert_in_bounds(index); if unsafe { !scope.metadata.contains_unchecked(index) } { continue; } - let texture_selector = unsafe { texture_selector_from_texture(storage, index) }; + let texture_selector = &t.texture.full_range; unsafe { insert_or_barrier_update( texture_selector, @@ -702,7 +688,7 @@ impl TextureTracker { /// /// If the ID is higher than the length of internal vectors, /// false will be returned. - pub fn remove_abandoned(&mut self, id: TextureId) -> bool { + pub fn remove_abandoned(&mut self, id: TextureId, is_in_registry: bool) -> bool { let index = id.unzip().0 as usize; if index > self.metadata.size() { @@ -714,8 +700,10 @@ impl TextureTracker { unsafe { if self.metadata.contains_unchecked(index) { let existing_ref_count = self.metadata.get_ref_count_unchecked(index); - //3 ref count: Registry, Device Tracker and suspected resource itself - if existing_ref_count <= 3 { + //2 ref count if only in Device Tracker and suspected resource itself and already released from user + //so not appearing in Registry + let min_ref_count = if is_in_registry { 3 } else { 2 }; + if existing_ref_count <= min_ref_count { self.start_set.complex.remove(&index); self.end_set.complex.remove(&index); self.metadata.remove(index); @@ -835,17 +823,6 @@ impl<'a> TextureStateProvider<'a> { } } -/// Helper function that gets what is needed from the texture storage -/// out of the texture storage. -#[inline(always)] -unsafe fn texture_selector_from_texture( - storage: &Storage, TextureId>, - index: usize, -) -> &TextureSelector { - let texture = unsafe { storage.get_unchecked(index as _) }; - &texture.full_range -} - /// Does an insertion operation if the index isn't tracked /// in the current metadata, otherwise merges the given state /// with the current state. If the merging would cause