diff options
Diffstat (limited to 'third_party/rust/wgpu-core/src/device')
-rw-r--r-- | third_party/rust/wgpu-core/src/device/global.rs | 245 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/device/life.rs | 129 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/device/queue.rs | 125 | ||||
-rw-r--r-- | third_party/rust/wgpu-core/src/device/resource.rs | 204 |
4 files changed, 438 insertions, 265 deletions
diff --git a/third_party/rust/wgpu-core/src/device/global.rs b/third_party/rust/wgpu-core/src/device/global.rs index 64fd6d4de7..539b92e0f3 100644 --- a/third_party/rust/wgpu-core/src/device/global.rs +++ b/third_party/rust/wgpu-core/src/device/global.rs @@ -26,9 +26,7 @@ use wgt::{BufferAddress, TextureFormat}; use std::{ borrow::Cow, - iter, - ops::Range, - ptr, + iter, ptr, sync::{atomic::Ordering, Arc}, }; @@ -219,7 +217,7 @@ impl Global { mapped_at_creation: false, }; let stage = match device.create_buffer(&stage_desc, true) { - Ok(stage) => stage, + Ok(stage) => Arc::new(stage), Err(e) => { to_destroy.push(buffer); break e; @@ -232,14 +230,10 @@ impl Global { Ok(mapping) => mapping, Err(e) => { to_destroy.push(buffer); - to_destroy.push(stage); break CreateBufferError::Device(e.into()); } }; - let stage_fid = hub.buffers.request(); - let stage = stage_fid.init(stage); - assert_eq!(buffer.size % wgt::COPY_BUFFER_ALIGNMENT, 0); // Zero initialize memory and then mark both staging and buffer as initialized // (it's guaranteed that this is the case by the time the buffer is usable) @@ -262,7 +256,7 @@ impl Global { .trackers .lock() .buffers - .insert_single(id, resource, buffer_use); + .insert_single(resource, buffer_use); return (id, None); }; @@ -383,7 +377,7 @@ impl Global { .buffers .get(buffer_id) .map_err(|_| BufferAccessError::Invalid)?; - check_buffer_usage(buffer.usage, wgt::BufferUsages::MAP_WRITE)?; + check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::MAP_WRITE)?; //assert!(buffer isn't used by the GPU); #[cfg(feature = "trace")] @@ -446,7 +440,7 @@ impl Global { .buffers .get(buffer_id) .map_err(|_| BufferAccessError::Invalid)?; - check_buffer_usage(buffer.usage, wgt::BufferUsages::MAP_READ)?; + check_buffer_usage(buffer_id, buffer.usage, wgt::BufferUsages::MAP_READ)?; //assert!(buffer isn't used by the GPU); let raw_buf = buffer @@ -529,7 +523,7 @@ impl Global { .lock_life() .suspected_resources .buffers - .insert(buffer_id, buffer); + .insert(buffer.info.tracker_index(), buffer); } if wait { @@ -573,11 +567,11 @@ impl Global { let (id, resource) = fid.assign(texture); api_log!("Device::create_texture({desc:?}) -> {id:?}"); - device.trackers.lock().textures.insert_single( - id, - resource, - hal::TextureUses::UNINITIALIZED, - ); + device + .trackers + .lock() + .textures + .insert_single(resource, hal::TextureUses::UNINITIALIZED); return (id, None); }; @@ -647,11 +641,11 @@ impl Global { let (id, resource) = fid.assign(texture); api_log!("Device::create_texture({desc:?}) -> {id:?}"); - device.trackers.lock().textures.insert_single( - id, - resource, - hal::TextureUses::UNINITIALIZED, - ); + device + .trackers + .lock() + .textures + .insert_single(resource, hal::TextureUses::UNINITIALIZED); return (id, None); }; @@ -704,7 +698,7 @@ impl Global { .trackers .lock() .buffers - .insert_single(id, buffer, hal::BufferUses::empty()); + .insert_single(buffer, hal::BufferUses::empty()); return (id, None); }; @@ -764,7 +758,7 @@ impl Global { .lock_life() .suspected_resources .textures - .insert(texture_id, texture.clone()); + .insert(texture.info.tracker_index(), texture.clone()); } } @@ -824,7 +818,7 @@ impl Global { } api_log!("Texture::create_view({texture_id:?}) -> {id:?}"); - device.trackers.lock().views.insert_single(id, resource); + device.trackers.lock().views.insert_single(resource); return (id, None); }; @@ -854,7 +848,7 @@ impl Global { .lock_life() .suspected_resources .texture_views - .insert(texture_view_id, view.clone()); + .insert(view.info.tracker_index(), view.clone()); if wait { match view.device.wait_for_submit(last_submit_index) { @@ -900,7 +894,7 @@ impl Global { let (id, resource) = fid.assign(sampler); api_log!("Device::create_sampler -> {id:?}"); - device.trackers.lock().samplers.insert_single(id, resource); + device.trackers.lock().samplers.insert_single(resource); return (id, None); }; @@ -925,7 +919,7 @@ impl Global { .lock_life() .suspected_resources .samplers - .insert(sampler_id, sampler.clone()); + .insert(sampler.info.tracker_index(), sampler.clone()); } } @@ -1024,7 +1018,7 @@ impl Global { .lock_life() .suspected_resources .bind_group_layouts - .insert(bind_group_layout_id, layout.clone()); + .insert(layout.info.tracker_index(), layout.clone()); } } @@ -1085,7 +1079,7 @@ impl Global { .lock_life() .suspected_resources .pipeline_layouts - .insert(pipeline_layout_id, layout.clone()); + .insert(layout.info.tracker_index(), layout.clone()); } } @@ -1140,11 +1134,7 @@ impl Global { api_log!("Device::create_bind_group -> {id:?}"); - device - .trackers - .lock() - .bind_groups - .insert_single(id, resource); + device.trackers.lock().bind_groups.insert_single(resource); return (id, None); }; @@ -1168,7 +1158,7 @@ impl Global { .lock_life() .suspected_resources .bind_groups - .insert(bind_group_id, bind_group.clone()); + .insert(bind_group.info.tracker_index(), bind_group.clone()); } } @@ -1332,9 +1322,8 @@ impl Global { if !device.is_valid() { break DeviceError::Lost; } - let queue = match hub.queues.get(device.queue_id.read().unwrap()) { - Ok(queue) => queue, - Err(_) => break DeviceError::InvalidQueueId, + let Some(queue) = device.get_queue() else { + break DeviceError::InvalidQueueId; }; let encoder = match device .command_allocator @@ -1379,6 +1368,7 @@ impl Global { .command_buffers .unregister(command_encoder_id.transmute()) { + cmd_buf.data.lock().as_mut().unwrap().encoder.discard(); cmd_buf .device .untrack(&cmd_buf.data.lock().as_ref().unwrap().trackers); @@ -1450,7 +1440,7 @@ impl Global { let (id, resource) = fid.assign(render_bundle); api_log!("RenderBundleEncoder::finish -> {id:?}"); - device.trackers.lock().bundles.insert_single(id, resource); + device.trackers.lock().bundles.insert_single(resource); return (id, None); }; @@ -1474,7 +1464,7 @@ impl Global { .lock_life() .suspected_resources .render_bundles - .insert(render_bundle_id, bundle.clone()); + .insert(bundle.info.tracker_index(), bundle.clone()); } } @@ -1513,11 +1503,7 @@ impl Global { let (id, resource) = fid.assign(query_set); api_log!("Device::create_query_set -> {id:?}"); - device - .trackers - .lock() - .query_sets - .insert_single(id, resource); + device.trackers.lock().query_sets.insert_single(resource); return (id, None); }; @@ -1544,7 +1530,7 @@ impl Global { .lock_life() .suspected_resources .query_sets - .insert(query_set_id, query_set.clone()); + .insert(query_set.info.tracker_index(), query_set.clone()); } } @@ -1600,7 +1586,7 @@ impl Global { .trackers .lock() .render_pipelines - .insert_single(id, resource); + .insert_single(resource); return (id, None); }; @@ -1672,18 +1658,17 @@ impl Global { let hub = A::hub(self); 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()); + .insert(pipeline.info.tracker_index(), pipeline.clone()); - life_lock - .suspected_resources - .pipeline_layouts - .insert(layout_id, pipeline.layout.clone()); + life_lock.suspected_resources.pipeline_layouts.insert( + pipeline.layout.info.tracker_index(), + pipeline.layout.clone(), + ); } } @@ -1734,7 +1719,7 @@ impl Global { .trackers .lock() .compute_pipelines - .insert_single(id, resource); + .insert_single(resource); return (id, None); }; @@ -1804,17 +1789,16 @@ impl Global { let hub = A::hub(self); 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()); + .insert(pipeline.info.tracker_index(), pipeline.clone()); + life_lock.suspected_resources.pipeline_layouts.insert( + pipeline.layout.info.tracker_index(), + pipeline.layout.clone(), + ); } } @@ -2113,28 +2097,41 @@ impl Global { .get(device_id) .map_err(|_| DeviceError::Invalid)?; - let (closures, queue_empty) = { - if let wgt::Maintain::WaitForSubmissionIndex(submission_index) = maintain { - if submission_index.queue_id != device_id.transmute() { - return Err(WaitIdleError::WrongSubmissionIndex( - submission_index.queue_id, - device_id, - )); - } + if let wgt::Maintain::WaitForSubmissionIndex(submission_index) = maintain { + if submission_index.queue_id != device_id.transmute() { + return Err(WaitIdleError::WrongSubmissionIndex( + submission_index.queue_id, + device_id, + )); } + } - let fence = device.fence.read(); - let fence = fence.as_ref().unwrap(); - device.maintain(fence, maintain)? - }; + let DevicePoll { + closures, + queue_empty, + } = Self::poll_single_device(&device, maintain)?; + + closures.fire(); + + Ok(queue_empty) + } + + fn poll_single_device<A: HalApi>( + device: &crate::device::Device<A>, + maintain: wgt::Maintain<queue::WrappedSubmissionIndex>, + ) -> Result<DevicePoll, WaitIdleError> { + let fence = device.fence.read(); + let fence = fence.as_ref().unwrap(); + let (closures, queue_empty) = device.maintain(fence, maintain)?; // Some deferred destroys are scheduled in maintain so run this right after // to avoid holding on to them until the next device poll. device.deferred_resource_destruction(); - closures.fire(); - - Ok(queue_empty) + Ok(DevicePoll { + closures, + queue_empty, + }) } /// Poll all devices belonging to the backend `A`. @@ -2143,7 +2140,7 @@ impl Global { /// /// Return `all_queue_empty` indicating whether there are more queue /// submissions still in flight. - fn poll_device<A: HalApi>( + fn poll_all_devices_of_api<A: HalApi>( &self, force_wait: bool, closures: &mut UserClosures, @@ -2161,10 +2158,13 @@ impl Global { } else { wgt::Maintain::Poll }; - let fence = device.fence.read(); - let fence = fence.as_ref().unwrap(); - let (cbs, queue_empty) = device.maintain(fence, maintain)?; - all_queue_empty = all_queue_empty && queue_empty; + + let DevicePoll { + closures: cbs, + queue_empty, + } = Self::poll_single_device(device, maintain)?; + + all_queue_empty &= queue_empty; closures.extend(cbs); } @@ -2186,23 +2186,23 @@ impl Global { #[cfg(vulkan)] { - all_queue_empty = - self.poll_device::<hal::api::Vulkan>(force_wait, &mut closures)? && all_queue_empty; + all_queue_empty &= + self.poll_all_devices_of_api::<hal::api::Vulkan>(force_wait, &mut closures)?; } #[cfg(metal)] { - all_queue_empty = - self.poll_device::<hal::api::Metal>(force_wait, &mut closures)? && all_queue_empty; + all_queue_empty &= + self.poll_all_devices_of_api::<hal::api::Metal>(force_wait, &mut closures)?; } #[cfg(dx12)] { - all_queue_empty = - self.poll_device::<hal::api::Dx12>(force_wait, &mut closures)? && all_queue_empty; + all_queue_empty &= + self.poll_all_devices_of_api::<hal::api::Dx12>(force_wait, &mut closures)?; } #[cfg(gles)] { - all_queue_empty = - self.poll_device::<hal::api::Gles>(force_wait, &mut closures)? && all_queue_empty; + all_queue_empty &= + self.poll_all_devices_of_api::<hal::api::Gles>(force_wait, &mut closures)?; } closures.fire(); @@ -2336,15 +2336,18 @@ impl Global { pub fn buffer_map_async<A: HalApi>( &self, buffer_id: id::BufferId, - range: Range<BufferAddress>, + offset: BufferAddress, + size: Option<BufferAddress>, op: BufferMapOperation, ) -> BufferAccessResult { - api_log!("Buffer::map_async {buffer_id:?} range {range:?} op: {op:?}"); + api_log!("Buffer::map_async {buffer_id:?} offset {offset:?} size {size:?} op: {op:?}"); // User callbacks must not be called while holding buffer_map_async_inner's locks, so we // defer the error callback if it needs to be called immediately (typically when running // into errors). - if let Err((mut operation, err)) = self.buffer_map_async_inner::<A>(buffer_id, range, op) { + if let Err((mut operation, err)) = + self.buffer_map_async_inner::<A>(buffer_id, offset, size, op) + { if let Some(callback) = operation.callback.take() { callback.call(Err(err.clone())); } @@ -2360,7 +2363,8 @@ impl Global { fn buffer_map_async_inner<A: HalApi>( &self, buffer_id: id::BufferId, - range: Range<BufferAddress>, + offset: BufferAddress, + size: Option<BufferAddress>, op: BufferMapOperation, ) -> Result<(), (BufferMapOperation, BufferAccessError)> { profiling::scope!("Buffer::map_async"); @@ -2372,29 +2376,50 @@ impl Global { HostMap::Write => (wgt::BufferUsages::MAP_WRITE, hal::BufferUses::MAP_WRITE), }; - if range.start % wgt::MAP_ALIGNMENT != 0 || range.end % wgt::COPY_BUFFER_ALIGNMENT != 0 { - return Err((op, BufferAccessError::UnalignedRange)); - } - let buffer = { - let buffer = hub - .buffers - .get(buffer_id) - .map_err(|_| BufferAccessError::Invalid); + let buffer = hub.buffers.get(buffer_id); let buffer = match buffer { Ok(b) => b, - Err(e) => { - return Err((op, e)); + Err(_) => { + return Err((op, BufferAccessError::Invalid)); } }; + { + let snatch_guard = buffer.device.snatchable_lock.read(); + if buffer.is_destroyed(&snatch_guard) { + return Err((op, BufferAccessError::Destroyed)); + } + } + + let range_size = if let Some(size) = size { + size + } else if offset > buffer.size { + 0 + } else { + buffer.size - offset + }; + + if offset % wgt::MAP_ALIGNMENT != 0 { + return Err((op, BufferAccessError::UnalignedOffset { offset })); + } + if range_size % wgt::COPY_BUFFER_ALIGNMENT != 0 { + return Err((op, BufferAccessError::UnalignedRangeSize { range_size })); + } + + let range = offset..(offset + range_size); + + if range.start % wgt::MAP_ALIGNMENT != 0 || range.end % wgt::COPY_BUFFER_ALIGNMENT != 0 + { + return Err((op, BufferAccessError::UnalignedRange)); + } let device = &buffer.device; if !device.is_valid() { return Err((op, DeviceError::Lost.into())); } - if let Err(e) = check_buffer_usage(buffer.usage, pub_usage) { + if let Err(e) = check_buffer_usage(buffer.info.id(), buffer.usage, pub_usage) { return Err((op, e.into())); } @@ -2417,11 +2442,6 @@ impl Global { )); } - let snatch_guard = device.snatchable_lock.read(); - if buffer.is_destroyed(&snatch_guard) { - return Err((op, BufferAccessError::Destroyed)); - } - { let map_state = &mut *buffer.map_state.lock(); *map_state = match *map_state { @@ -2442,6 +2462,8 @@ impl Global { }; } + let snatch_guard = buffer.device.snatchable_lock.read(); + { let mut trackers = buffer.device.as_ref().trackers.lock(); trackers.buffers.set_single(&buffer, internal_use); @@ -2557,3 +2579,8 @@ impl Global { buffer.unmap() } } + +struct DevicePoll { + closures: UserClosures, + queue_empty: bool, +} diff --git a/third_party/rust/wgpu-core/src/device/life.rs b/third_party/rust/wgpu-core/src/device/life.rs index 86c5d027c7..7b06a4a30b 100644 --- a/third_party/rust/wgpu-core/src/device/life.rs +++ b/third_party/rust/wgpu-core/src/device/life.rs @@ -6,17 +6,13 @@ use crate::{ DeviceError, DeviceLostClosure, }, hal_api::HalApi, - id::{ - self, BindGroupId, BindGroupLayoutId, BufferId, ComputePipelineId, Id, PipelineLayoutId, - QuerySetId, RenderBundleId, RenderPipelineId, SamplerId, StagingBufferId, TextureId, - TextureViewId, - }, + id, pipeline::{ComputePipeline, RenderPipeline}, resource::{ self, Buffer, DestroyedBuffer, DestroyedTexture, QuerySet, Resource, Sampler, StagingBuffer, Texture, TextureView, }, - track::{ResourceTracker, Tracker}, + track::{ResourceTracker, Tracker, TrackerIndex}, FastHashMap, SubmissionIndex, }; use smallvec::SmallVec; @@ -28,20 +24,20 @@ use thiserror::Error; /// A struct that keeps lists of resources that are no longer needed by the user. #[derive(Default)] pub(crate) struct ResourceMaps<A: HalApi> { - pub buffers: FastHashMap<BufferId, Arc<Buffer<A>>>, - pub staging_buffers: FastHashMap<StagingBufferId, Arc<StagingBuffer<A>>>, - pub textures: FastHashMap<TextureId, Arc<Texture<A>>>, - pub texture_views: FastHashMap<TextureViewId, Arc<TextureView<A>>>, - pub samplers: FastHashMap<SamplerId, Arc<Sampler<A>>>, - pub bind_groups: FastHashMap<BindGroupId, Arc<BindGroup<A>>>, - pub bind_group_layouts: FastHashMap<BindGroupLayoutId, Arc<BindGroupLayout<A>>>, - pub render_pipelines: FastHashMap<RenderPipelineId, Arc<RenderPipeline<A>>>, - pub compute_pipelines: FastHashMap<ComputePipelineId, Arc<ComputePipeline<A>>>, - pub pipeline_layouts: FastHashMap<PipelineLayoutId, Arc<PipelineLayout<A>>>, - pub render_bundles: FastHashMap<RenderBundleId, Arc<RenderBundle<A>>>, - pub query_sets: FastHashMap<QuerySetId, Arc<QuerySet<A>>>, - pub destroyed_buffers: FastHashMap<BufferId, Arc<DestroyedBuffer<A>>>, - pub destroyed_textures: FastHashMap<TextureId, Arc<DestroyedTexture<A>>>, + pub buffers: FastHashMap<TrackerIndex, Arc<Buffer<A>>>, + pub staging_buffers: FastHashMap<TrackerIndex, Arc<StagingBuffer<A>>>, + pub textures: FastHashMap<TrackerIndex, Arc<Texture<A>>>, + pub texture_views: FastHashMap<TrackerIndex, Arc<TextureView<A>>>, + pub samplers: FastHashMap<TrackerIndex, Arc<Sampler<A>>>, + pub bind_groups: FastHashMap<TrackerIndex, Arc<BindGroup<A>>>, + pub bind_group_layouts: FastHashMap<TrackerIndex, Arc<BindGroupLayout<A>>>, + pub render_pipelines: FastHashMap<TrackerIndex, Arc<RenderPipeline<A>>>, + pub compute_pipelines: FastHashMap<TrackerIndex, Arc<ComputePipeline<A>>>, + pub pipeline_layouts: FastHashMap<TrackerIndex, Arc<PipelineLayout<A>>>, + pub render_bundles: FastHashMap<TrackerIndex, Arc<RenderBundle<A>>>, + pub query_sets: FastHashMap<TrackerIndex, Arc<QuerySet<A>>>, + pub destroyed_buffers: FastHashMap<TrackerIndex, Arc<DestroyedBuffer<A>>>, + pub destroyed_textures: FastHashMap<TrackerIndex, Arc<DestroyedTexture<A>>>, } impl<A: HalApi> ResourceMaps<A> { @@ -276,25 +272,29 @@ impl<A: HalApi> LifetimeTracker<A> { for res in temp_resources { match res { TempResource::Buffer(raw) => { - last_resources.buffers.insert(raw.as_info().id(), raw); + last_resources + .buffers + .insert(raw.as_info().tracker_index(), raw); } TempResource::StagingBuffer(raw) => { last_resources .staging_buffers - .insert(raw.as_info().id(), raw); + .insert(raw.as_info().tracker_index(), raw); } TempResource::DestroyedBuffer(destroyed) => { last_resources .destroyed_buffers - .insert(destroyed.id, destroyed); + .insert(destroyed.tracker_index, destroyed); } TempResource::Texture(raw) => { - last_resources.textures.insert(raw.as_info().id(), raw); + last_resources + .textures + .insert(raw.as_info().tracker_index(), raw); } TempResource::DestroyedTexture(destroyed) => { last_resources .destroyed_textures - .insert(destroyed.id, destroyed); + .insert(destroyed.tracker_index, destroyed); } } } @@ -310,12 +310,14 @@ impl<A: HalApi> LifetimeTracker<A> { pub fn post_submit(&mut self) { for v in self.future_suspected_buffers.drain(..).take(1) { - self.suspected_resources.buffers.insert(v.as_info().id(), v); + self.suspected_resources + .buffers + .insert(v.as_info().tracker_index(), v); } for v in self.future_suspected_textures.drain(..).take(1) { self.suspected_resources .textures - .insert(v.as_info().id(), v); + .insert(v.as_info().tracker_index(), v); } } @@ -386,19 +388,27 @@ impl<A: HalApi> LifetimeTracker<A> { if let Some(resources) = resources { match temp_resource { TempResource::Buffer(raw) => { - resources.buffers.insert(raw.as_info().id(), raw); + resources.buffers.insert(raw.as_info().tracker_index(), raw); } TempResource::StagingBuffer(raw) => { - resources.staging_buffers.insert(raw.as_info().id(), raw); + resources + .staging_buffers + .insert(raw.as_info().tracker_index(), raw); } TempResource::DestroyedBuffer(destroyed) => { - resources.destroyed_buffers.insert(destroyed.id, destroyed); + resources + .destroyed_buffers + .insert(destroyed.tracker_index, destroyed); } TempResource::Texture(raw) => { - resources.textures.insert(raw.as_info().id(), raw); + resources + .textures + .insert(raw.as_info().tracker_index(), raw); } TempResource::DestroyedTexture(destroyed) => { - resources.destroyed_textures.insert(destroyed.id, destroyed); + resources + .destroyed_textures + .insert(destroyed.tracker_index, destroyed); } } } @@ -420,27 +430,27 @@ impl<A: HalApi> LifetimeTracker<A> { impl<A: HalApi> LifetimeTracker<A> { fn triage_resources<R>( - resources_map: &mut FastHashMap<Id<R::Marker>, Arc<R>>, + resources_map: &mut FastHashMap<TrackerIndex, Arc<R>>, active: &mut [ActiveSubmission<A>], - trackers: &mut impl ResourceTracker<R>, - get_resource_map: impl Fn(&mut ResourceMaps<A>) -> &mut FastHashMap<Id<R::Marker>, Arc<R>>, + trackers: &mut impl ResourceTracker, + get_resource_map: impl Fn(&mut ResourceMaps<A>) -> &mut FastHashMap<TrackerIndex, Arc<R>>, ) -> Vec<Arc<R>> where R: Resource, { let mut removed_resources = Vec::new(); - resources_map.retain(|&id, resource| { + resources_map.retain(|&index, resource| { let submit_index = resource.as_info().submission_index(); let non_referenced_resources = active .iter_mut() .find(|a| a.index == submit_index) .map(|a| &mut a.last_resources); - let is_removed = trackers.remove_abandoned(id); + let is_removed = trackers.remove_abandoned(index); if is_removed { removed_resources.push(resource.clone()); if let Some(resources) = non_referenced_resources { - get_resource_map(resources).insert(id, resource.clone()); + get_resource_map(resources).insert(index, resource.clone()); } } !is_removed @@ -459,27 +469,29 @@ impl<A: HalApi> LifetimeTracker<A> { ); removed_resources.drain(..).for_each(|bundle| { for v in bundle.used.buffers.write().drain_resources() { - self.suspected_resources.buffers.insert(v.as_info().id(), v); + self.suspected_resources + .buffers + .insert(v.as_info().tracker_index(), v); } for v in bundle.used.textures.write().drain_resources() { self.suspected_resources .textures - .insert(v.as_info().id(), v); + .insert(v.as_info().tracker_index(), v); } for v in bundle.used.bind_groups.write().drain_resources() { self.suspected_resources .bind_groups - .insert(v.as_info().id(), v); + .insert(v.as_info().tracker_index(), v); } for v in bundle.used.render_pipelines.write().drain_resources() { self.suspected_resources .render_pipelines - .insert(v.as_info().id(), v); + .insert(v.as_info().tracker_index(), v); } for v in bundle.used.query_sets.write().drain_resources() { self.suspected_resources .query_sets - .insert(v.as_info().id(), v); + .insert(v.as_info().tracker_index(), v); } }); self @@ -496,27 +508,30 @@ impl<A: HalApi> LifetimeTracker<A> { ); removed_resource.drain(..).for_each(|bind_group| { for v in bind_group.used.buffers.drain_resources() { - self.suspected_resources.buffers.insert(v.as_info().id(), v); + self.suspected_resources + .buffers + .insert(v.as_info().tracker_index(), v); } for v in bind_group.used.textures.drain_resources() { self.suspected_resources .textures - .insert(v.as_info().id(), v); + .insert(v.as_info().tracker_index(), v); } for v in bind_group.used.views.drain_resources() { self.suspected_resources .texture_views - .insert(v.as_info().id(), v); + .insert(v.as_info().tracker_index(), v); } for v in bind_group.used.samplers.drain_resources() { self.suspected_resources .samplers - .insert(v.as_info().id(), v); + .insert(v.as_info().tracker_index(), v); } - self.suspected_resources - .bind_group_layouts - .insert(bind_group.layout.as_info().id(), bind_group.layout.clone()); + self.suspected_resources.bind_group_layouts.insert( + bind_group.layout.as_info().tracker_index(), + bind_group.layout.clone(), + ); }); self } @@ -605,7 +620,7 @@ impl<A: HalApi> LifetimeTracker<A> { ); removed_resources.drain(..).for_each(|compute_pipeline| { self.suspected_resources.pipeline_layouts.insert( - compute_pipeline.layout.as_info().id(), + compute_pipeline.layout.as_info().tracker_index(), compute_pipeline.layout.clone(), ); }); @@ -623,7 +638,7 @@ impl<A: HalApi> LifetimeTracker<A> { ); removed_resources.drain(..).for_each(|render_pipeline| { self.suspected_resources.pipeline_layouts.insert( - render_pipeline.layout.as_info().id(), + render_pipeline.layout.as_info().tracker_index(), render_pipeline.layout.clone(), ); }); @@ -642,7 +657,7 @@ impl<A: HalApi> LifetimeTracker<A> { for bgl in &pipeline_layout.bind_group_layouts { self.suspected_resources .bind_group_layouts - .insert(bgl.as_info().id(), bgl.clone()); + .insert(bgl.as_info().tracker_index(), bgl.clone()); } }); self @@ -773,14 +788,14 @@ impl<A: HalApi> LifetimeTracker<A> { Vec::with_capacity(self.ready_to_map.len()); for buffer in self.ready_to_map.drain(..) { - let buffer_id = buffer.info.id(); + let tracker_index = buffer.info.tracker_index(); let is_removed = { let mut trackers = trackers.lock(); - trackers.buffers.remove_abandoned(buffer_id) + trackers.buffers.remove_abandoned(tracker_index) }; if is_removed { *buffer.map_state.lock() = resource::BufferMapState::Idle; - log::trace!("Buffer ready to map {:?} is not tracked anymore", buffer_id); + log::trace!("Buffer ready to map {tracker_index:?} is not tracked anymore"); } else { let mapping = match std::mem::replace( &mut *buffer.map_state.lock(), @@ -798,7 +813,7 @@ impl<A: HalApi> LifetimeTracker<A> { _ => panic!("No pending mapping."), }; let status = if mapping.range.start != mapping.range.end { - log::debug!("Buffer {:?} map state -> Active", buffer_id); + log::debug!("Buffer {tracker_index:?} map state -> Active"); let host = mapping.op.host; let size = mapping.range.end - mapping.range.start; match super::map_buffer(raw, &buffer, mapping.range.start, size, host) { diff --git a/third_party/rust/wgpu-core/src/device/queue.rs b/third_party/rust/wgpu-core/src/device/queue.rs index 08c5b767b6..6ebb9eb09b 100644 --- a/third_party/rust/wgpu-core/src/device/queue.rs +++ b/third_party/rust/wgpu-core/src/device/queue.rs @@ -12,7 +12,7 @@ use crate::{ global::Global, hal_api::HalApi, hal_label, - id::{self, QueueId}, + id::{self, DeviceId, QueueId}, init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange}, resource::{ Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, Resource, @@ -188,10 +188,17 @@ impl<A: HalApi> EncoderInFlight<A> { #[derive(Debug)] pub(crate) struct PendingWrites<A: HalApi> { pub command_encoder: A::CommandEncoder, - pub is_active: bool, + + /// True if `command_encoder` is in the "recording" state, as + /// described in the docs for the [`wgpu_hal::CommandEncoder`] + /// trait. + pub is_recording: bool, + pub temp_resources: Vec<TempResource<A>>, pub dst_buffers: FastHashMap<id::BufferId, Arc<Buffer<A>>>, pub dst_textures: FastHashMap<id::TextureId, Arc<Texture<A>>>, + + /// All command buffers allocated from `command_encoder`. pub executing_command_buffers: Vec<A::CommandBuffer>, } @@ -199,7 +206,7 @@ impl<A: HalApi> PendingWrites<A> { pub fn new(command_encoder: A::CommandEncoder) -> Self { Self { command_encoder, - is_active: false, + is_recording: false, temp_resources: Vec::new(), dst_buffers: FastHashMap::default(), dst_textures: FastHashMap::default(), @@ -209,7 +216,7 @@ impl<A: HalApi> PendingWrites<A> { pub fn dispose(mut self, device: &A::Device) { unsafe { - if self.is_active { + if self.is_recording { self.command_encoder.discard_encoding(); } self.command_encoder @@ -232,9 +239,9 @@ impl<A: HalApi> PendingWrites<A> { fn pre_submit(&mut self) -> Result<Option<&A::CommandBuffer>, DeviceError> { self.dst_buffers.clear(); self.dst_textures.clear(); - if self.is_active { + if self.is_recording { let cmd_buf = unsafe { self.command_encoder.end_encoding()? }; - self.is_active = false; + self.is_recording = false; self.executing_command_buffers.push(cmd_buf); return Ok(self.executing_command_buffers.last()); @@ -262,23 +269,23 @@ impl<A: HalApi> PendingWrites<A> { } pub fn activate(&mut self) -> &mut A::CommandEncoder { - if !self.is_active { + if !self.is_recording { unsafe { self.command_encoder .begin_encoding(Some("(wgpu internal) PendingWrites")) .unwrap(); } - self.is_active = true; + self.is_recording = true; } &mut self.command_encoder } pub fn deactivate(&mut self) { - if self.is_active { + if self.is_recording { unsafe { self.command_encoder.discard_encoding(); } - self.is_active = false; + self.is_recording = false; } } } @@ -303,7 +310,10 @@ fn prepare_staging_buffer<A: HalApi>( raw: Mutex::new(Some(buffer)), device: device.clone(), size, - info: ResourceInfo::new("<StagingBuffer>"), + info: ResourceInfo::new( + "<StagingBuffer>", + Some(device.tracker_indices.staging_buffers.clone()), + ), is_coherent: mapping.is_coherent, }; @@ -332,6 +342,15 @@ pub struct InvalidQueue; #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum QueueWriteError { + #[error( + "Device of queue ({:?}) does not match device of write recipient ({:?})", + queue_device_id, + target_device_id + )] + DeviceMismatch { + queue_device_id: DeviceId, + target_device_id: DeviceId, + }, #[error(transparent)] Queue(#[from] DeviceError), #[error(transparent)] @@ -376,6 +395,14 @@ impl Global { let hub = A::hub(self); + let buffer_device_id = hub + .buffers + .get(buffer_id) + .map_err(|_| TransferError::InvalidBuffer(buffer_id))? + .device + .as_info() + .id(); + let queue = hub .queues .get(queue_id) @@ -383,6 +410,16 @@ impl Global { let device = queue.device.as_ref().unwrap(); + { + let queue_device_id = device.as_info().id(); + if buffer_device_id != queue_device_id { + return Err(QueueWriteError::DeviceMismatch { + queue_device_id, + target_device_id: buffer_device_id, + }); + } + } + let data_size = data.len() as wgt::BufferAddress; #[cfg(feature = "trace")] @@ -1143,7 +1180,7 @@ impl Global { for &cmb_id in command_buffer_ids { // we reset the used surface textures every time we use // it, so make sure to set_size on it. - used_surface_textures.set_size(hub.textures.read().len()); + used_surface_textures.set_size(device.tracker_indices.textures.size()); #[allow(unused_mut)] let mut cmdbuf = match command_buffer_guard.replace_with_error(cmb_id) { @@ -1188,11 +1225,13 @@ impl Global { // update submission IDs for buffer in cmd_buf_trackers.buffers.used_resources() { - let id = buffer.info.id(); + let tracker_index = buffer.info.tracker_index(); let raw_buf = match buffer.raw.get(&snatch_guard) { Some(raw) => raw, None => { - return Err(QueueSubmitError::DestroyedBuffer(id)); + return Err(QueueSubmitError::DestroyedBuffer( + buffer.info.id(), + )); } }; buffer.info.use_at(submit_index); @@ -1207,28 +1246,28 @@ impl Global { .as_mut() .unwrap() .buffers - .insert(id, buffer.clone()); + .insert(tracker_index, buffer.clone()); } else { match *buffer.map_state.lock() { BufferMapState::Idle => (), - _ => return Err(QueueSubmitError::BufferStillMapped(id)), + _ => { + return Err(QueueSubmitError::BufferStillMapped( + buffer.info.id(), + )) + } } } } for texture in cmd_buf_trackers.textures.used_resources() { - let id = texture.info.id(); + let tracker_index = texture.info.tracker_index(); let should_extend = match texture.inner.get(&snatch_guard) { None => { - return Err(QueueSubmitError::DestroyedTexture(id)); + return Err(QueueSubmitError::DestroyedTexture( + texture.info.id(), + )); } Some(TextureInner::Native { .. }) => false, - Some(TextureInner::Surface { - ref has_work, - ref raw, - .. - }) => { - has_work.store(true, Ordering::Relaxed); - + Some(TextureInner::Surface { ref raw, .. }) => { if raw.is_some() { submit_surface_textures_owned.push(texture.clone()); } @@ -1242,7 +1281,7 @@ impl Global { .as_mut() .unwrap() .textures - .insert(id, texture.clone()); + .insert(tracker_index, texture.clone()); } if should_extend { unsafe { @@ -1255,11 +1294,10 @@ impl Global { for texture_view in cmd_buf_trackers.views.used_resources() { texture_view.info.use_at(submit_index); if texture_view.is_unique() { - temp_suspected - .as_mut() - .unwrap() - .texture_views - .insert(texture_view.as_info().id(), texture_view.clone()); + temp_suspected.as_mut().unwrap().texture_views.insert( + texture_view.as_info().tracker_index(), + texture_view.clone(), + ); } } { @@ -1279,7 +1317,7 @@ impl Global { .as_mut() .unwrap() .bind_groups - .insert(bg.as_info().id(), bg.clone()); + .insert(bg.as_info().tracker_index(), bg.clone()); } } } @@ -1290,7 +1328,7 @@ impl Global { compute_pipeline.info.use_at(submit_index); if compute_pipeline.is_unique() { temp_suspected.as_mut().unwrap().compute_pipelines.insert( - compute_pipeline.as_info().id(), + compute_pipeline.as_info().tracker_index(), compute_pipeline.clone(), ); } @@ -1301,7 +1339,7 @@ impl Global { render_pipeline.info.use_at(submit_index); if render_pipeline.is_unique() { temp_suspected.as_mut().unwrap().render_pipelines.insert( - render_pipeline.as_info().id(), + render_pipeline.as_info().tracker_index(), render_pipeline.clone(), ); } @@ -1309,11 +1347,10 @@ impl Global { for query_set in cmd_buf_trackers.query_sets.used_resources() { query_set.info.use_at(submit_index); if query_set.is_unique() { - temp_suspected - .as_mut() - .unwrap() - .query_sets - .insert(query_set.as_info().id(), query_set.clone()); + temp_suspected.as_mut().unwrap().query_sets.insert( + query_set.as_info().tracker_index(), + query_set.clone(), + ); } } for bundle in cmd_buf_trackers.bundles.used_resources() { @@ -1334,7 +1371,7 @@ impl Global { .as_mut() .unwrap() .render_bundles - .insert(bundle.as_info().id(), bundle.clone()); + .insert(bundle.as_info().tracker_index(), bundle.clone()); } } } @@ -1423,13 +1460,7 @@ impl Global { return Err(QueueSubmitError::DestroyedTexture(id)); } Some(TextureInner::Native { .. }) => {} - Some(TextureInner::Surface { - ref has_work, - ref raw, - .. - }) => { - has_work.store(true, Ordering::Relaxed); - + Some(TextureInner::Surface { ref raw, .. }) => { if raw.is_some() { submit_surface_textures_owned.push(texture.clone()); } diff --git a/third_party/rust/wgpu-core/src/device/resource.rs b/third_party/rust/wgpu-core/src/device/resource.rs index b2c85a056a..28ba0eafb1 100644 --- a/third_party/rust/wgpu-core/src/device/resource.rs +++ b/third_party/rust/wgpu-core/src/device/resource.rs @@ -13,7 +13,6 @@ use crate::{ hal_api::HalApi, hal_label, hub::Hub, - id::QueueId, init_tracker::{ BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange, TextureInitTracker, TextureInitTrackerAction, @@ -29,13 +28,16 @@ use crate::{ resource_log, snatch::{SnatchGuard, SnatchLock, Snatchable}, storage::Storage, - track::{BindGroupStates, TextureSelector, Tracker}, - validation::{self, check_buffer_usage, check_texture_usage}, + track::{BindGroupStates, TextureSelector, Tracker, TrackerIndexAllocators}, + validation::{ + self, check_buffer_usage, check_texture_usage, validate_color_attachment_bytes_per_sample, + }, FastHashMap, LabelHelpers as _, SubmissionIndex, }; use arrayvec::ArrayVec; use hal::{CommandEncoder as _, Device as _}; +use once_cell::sync::OnceCell; use parking_lot::{Mutex, MutexGuard, RwLock}; use smallvec::SmallVec; @@ -54,7 +56,7 @@ use std::{ use super::{ life::{self, ResourceMaps}, - queue::{self}, + queue::{self, Queue}, DeviceDescriptor, DeviceError, ImplicitPipelineContext, UserClosures, ENTRYPOINT_FAILURE_ERROR, IMPLICIT_BIND_GROUP_LAYOUT_ERROR_LABEL, ZERO_BUFFER_SIZE, }; @@ -87,8 +89,8 @@ use super::{ pub struct Device<A: HalApi> { raw: Option<A::Device>, pub(crate) adapter: Arc<Adapter<A>>, - pub(crate) queue_id: RwLock<Option<QueueId>>, - queue_to_drop: RwLock<Option<A::Queue>>, + pub(crate) queue: OnceCell<Weak<Queue<A>>>, + queue_to_drop: OnceCell<A::Queue>, pub(crate) zero_buffer: Option<A::Buffer>, pub(crate) info: ResourceInfo<Device<A>>, @@ -116,6 +118,7 @@ pub struct Device<A: HalApi> { /// Has to be locked temporarily only (locked last) /// and never before pending_writes pub(crate) trackers: Mutex<Tracker<A>>, + pub(crate) tracker_indices: TrackerIndexAllocators, // Life tracker should be locked right after the device and before anything else. life_tracker: Mutex<LifetimeTracker<A>>, /// Temporary storage for resource management functions. Cleared at the end @@ -160,7 +163,7 @@ impl<A: HalApi> Drop for Device<A> { unsafe { raw.destroy_buffer(self.zero_buffer.take().unwrap()); raw.destroy_fence(self.fence.write().take().unwrap()); - let queue = self.queue_to_drop.write().take().unwrap(); + let queue = self.queue_to_drop.take().unwrap(); raw.exit(queue); } } @@ -258,16 +261,17 @@ impl<A: HalApi> Device<A> { Ok(Self { raw: Some(raw_device), adapter: adapter.clone(), - queue_id: RwLock::new(None), - queue_to_drop: RwLock::new(None), + queue: OnceCell::new(), + queue_to_drop: OnceCell::new(), zero_buffer: Some(zero_buffer), - info: ResourceInfo::new("<device>"), + info: ResourceInfo::new("<device>", None), command_allocator: Mutex::new(Some(com_alloc)), active_submission_index: AtomicU64::new(0), fence: RwLock::new(Some(fence)), snatchable_lock: unsafe { SnatchLock::new() }, valid: AtomicBool::new(true), trackers: Mutex::new(Tracker::new()), + tracker_indices: TrackerIndexAllocators::new(), life_tracker: Mutex::new(life::LifetimeTracker::new()), temp_suspected: Mutex::new(Some(life::ResourceMaps::new())), bgl_pool: ResourcePool::new(), @@ -300,7 +304,7 @@ impl<A: HalApi> Device<A> { } pub(crate) fn release_queue(&self, queue: A::Queue) { - self.queue_to_drop.write().replace(queue); + assert!(self.queue_to_drop.set(queue).is_ok()); } pub(crate) fn lock_life<'a>(&'a self) -> MutexGuard<'a, LifetimeTracker<A>> { @@ -339,7 +343,8 @@ impl<A: HalApi> Device<A> { let Some(bind_group) = bind_group.upgrade() else { continue; }; - let Some(raw_bind_group) = bind_group.raw.snatch(self.snatchable_lock.write()) else { + let Some(raw_bind_group) = bind_group.raw.snatch(self.snatchable_lock.write()) + else { continue; }; @@ -357,6 +362,14 @@ impl<A: HalApi> Device<A> { } } + pub fn get_queue(&self) -> Option<Arc<Queue<A>>> { + self.queue.get().as_ref()?.upgrade() + } + + pub fn set_queue(&self, queue: Arc<Queue<A>>) { + assert!(self.queue.set(Arc::downgrade(&queue)).is_ok()); + } + /// Check this device for completed commands. /// /// The `maintain` argument tells how the maintence function should behave, either @@ -483,56 +496,56 @@ impl<A: HalApi> Device<A> { if resource.is_unique() { temp_suspected .buffers - .insert(resource.as_info().id(), resource.clone()); + .insert(resource.as_info().tracker_index(), resource.clone()); } } for resource in trackers.textures.used_resources() { if resource.is_unique() { temp_suspected .textures - .insert(resource.as_info().id(), resource.clone()); + .insert(resource.as_info().tracker_index(), resource.clone()); } } for resource in trackers.views.used_resources() { if resource.is_unique() { temp_suspected .texture_views - .insert(resource.as_info().id(), resource.clone()); + .insert(resource.as_info().tracker_index(), resource.clone()); } } for resource in trackers.bind_groups.used_resources() { if resource.is_unique() { temp_suspected .bind_groups - .insert(resource.as_info().id(), resource.clone()); + .insert(resource.as_info().tracker_index(), resource.clone()); } } for resource in trackers.samplers.used_resources() { if resource.is_unique() { temp_suspected .samplers - .insert(resource.as_info().id(), resource.clone()); + .insert(resource.as_info().tracker_index(), resource.clone()); } } for resource in trackers.compute_pipelines.used_resources() { if resource.is_unique() { temp_suspected .compute_pipelines - .insert(resource.as_info().id(), resource.clone()); + .insert(resource.as_info().tracker_index(), resource.clone()); } } for resource in trackers.render_pipelines.used_resources() { if resource.is_unique() { temp_suspected .render_pipelines - .insert(resource.as_info().id(), resource.clone()); + .insert(resource.as_info().tracker_index(), resource.clone()); } } for resource in trackers.query_sets.used_resources() { if resource.is_unique() { temp_suspected .query_sets - .insert(resource.as_info().id(), resource.clone()); + .insert(resource.as_info().tracker_index(), resource.clone()); } } } @@ -633,7 +646,10 @@ impl<A: HalApi> Device<A> { initialization_status: RwLock::new(BufferInitTracker::new(aligned_size)), sync_mapped_writes: Mutex::new(None), map_state: Mutex::new(resource::BufferMapState::Idle), - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.buffers.clone()), + ), bind_groups: Mutex::new(Vec::new()), }) } @@ -662,7 +678,10 @@ impl<A: HalApi> Device<A> { mips: 0..desc.mip_level_count, layers: 0..desc.array_layer_count(), }, - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.textures.clone()), + ), clear_mode: RwLock::new(clear_mode), views: Mutex::new(Vec::new()), bind_groups: Mutex::new(Vec::new()), @@ -684,7 +703,10 @@ impl<A: HalApi> Device<A> { initialization_status: RwLock::new(BufferInitTracker::new(0)), sync_mapped_writes: Mutex::new(None), map_state: Mutex::new(resource::BufferMapState::Idle), - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.buffers.clone()), + ), bind_groups: Mutex::new(Vec::new()), } } @@ -1262,7 +1284,10 @@ impl<A: HalApi> Device<A> { render_extent, samples: texture.desc.sample_count, selector, - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.texture_views.clone()), + ), }) } @@ -1366,7 +1391,10 @@ impl<A: HalApi> Device<A> { Ok(Sampler { raw: Some(raw), device: self.clone(), - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.samplers.clone()), + ), comparison: desc.compare.is_some(), filtering: desc.min_filter == wgt::FilterMode::Linear || desc.mag_filter == wgt::FilterMode::Linear, @@ -1484,6 +1512,10 @@ impl<A: HalApi> Device<A> { .contains(wgt::Features::SHADER_EARLY_DEPTH_TEST), ); caps.set( + Caps::SHADER_INT64, + self.features.contains(wgt::Features::SHADER_INT64), + ); + caps.set( Caps::MULTISAMPLED_SHADING, self.downlevel .flags @@ -1559,7 +1591,7 @@ impl<A: HalApi> Device<A> { raw: Some(raw), device: self.clone(), interface: Some(interface), - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new(desc.label.borrow_or_default(), None), label: desc.label.borrow_or_default().to_string(), }) } @@ -1600,7 +1632,7 @@ impl<A: HalApi> Device<A> { raw: Some(raw), device: self.clone(), interface: None, - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new(desc.label.borrow_or_default(), None), label: desc.label.borrow_or_default().to_string(), }) } @@ -1704,10 +1736,23 @@ impl<A: HalApi> Device<A> { BindGroupLayoutEntryError::SampleTypeFloatFilterableBindingMultisampled, }); } - Bt::Texture { .. } => ( - Some(wgt::Features::TEXTURE_BINDING_ARRAY), - WritableStorage::No, - ), + Bt::Texture { + multisampled, + view_dimension, + .. + } => { + if multisampled && view_dimension != TextureViewDimension::D2 { + return Err(binding_model::CreateBindGroupLayoutError::Entry { + binding: entry.binding, + error: BindGroupLayoutEntryError::Non2DMultisampled(view_dimension), + }); + } + + ( + Some(wgt::Features::TEXTURE_BINDING_ARRAY), + WritableStorage::No, + ) + } Bt::StorageTexture { access, view_dimension, @@ -1840,7 +1885,10 @@ impl<A: HalApi> Device<A> { entries: entry_map, origin, binding_count_validator: count_validator, - info: ResourceInfo::new(label.unwrap_or("<BindGroupLayout>")), + info: ResourceInfo::new( + label.unwrap_or("<BindGroupLayout>"), + Some(self.tracker_indices.bind_group_layouts.clone()), + ), label: label.unwrap_or_default().to_string(), }) } @@ -1905,7 +1953,7 @@ impl<A: HalApi> Device<A> { .add_single(storage, bb.buffer_id, internal_use) .ok_or(Error::InvalidBuffer(bb.buffer_id))?; - check_buffer_usage(buffer.usage, pub_usage)?; + check_buffer_usage(bb.buffer_id, buffer.usage, pub_usage)?; let raw_buffer = buffer .raw .get(snatch_guard) @@ -2273,7 +2321,10 @@ impl<A: HalApi> Device<A> { raw: Snatchable::new(raw), device: self.clone(), layout: layout.clone(), - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.bind_groups.clone()), + ), used, used_buffer_ranges, used_texture_ranges, @@ -2555,7 +2606,10 @@ impl<A: HalApi> Device<A> { Ok(binding_model::PipelineLayout { raw: Some(raw), device: self.clone(), - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.pipeline_layouts.clone()), + ), bind_group_layouts, push_constant_ranges: desc.push_constant_ranges.iter().cloned().collect(), }) @@ -2656,14 +2710,21 @@ impl<A: HalApi> Device<A> { let mut shader_binding_sizes = FastHashMap::default(); let io = validation::StageIo::default(); + let final_entry_point_name; + { let stage = wgt::ShaderStages::COMPUTE; + final_entry_point_name = shader_module.finalize_entry_point_name( + stage, + desc.stage.entry_point.as_ref().map(|ep| ep.as_ref()), + )?; + if let Some(ref interface) = shader_module.interface { let _ = interface.check_stage( &mut binding_layout_source, &mut shader_binding_sizes, - &desc.stage.entry_point, + &final_entry_point_name, stage, io, None, @@ -2691,7 +2752,7 @@ impl<A: HalApi> Device<A> { label: desc.label.to_hal(self.instance_flags), layout: pipeline_layout.raw(), stage: hal::ProgrammableStage { - entry_point: desc.stage.entry_point.as_ref(), + entry_point: final_entry_point_name.as_ref(), module: shader_module.raw(), }, }; @@ -2720,7 +2781,10 @@ impl<A: HalApi> Device<A> { device: self.clone(), _shader_module: shader_module, late_sized_buffer_groups, - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.compute_pipelines.clone()), + ), }; Ok(pipeline) } @@ -2749,11 +2813,12 @@ impl<A: HalApi> Device<A> { let mut shader_binding_sizes = FastHashMap::default(); let num_attachments = desc.fragment.as_ref().map(|f| f.targets.len()).unwrap_or(0); - if num_attachments > hal::MAX_COLOR_ATTACHMENTS { + let max_attachments = self.limits.max_color_attachments as usize; + if num_attachments > max_attachments { return Err(pipeline::CreateRenderPipelineError::ColorAttachment( command::ColorAttachmentError::TooMany { given: num_attachments, - limit: hal::MAX_COLOR_ATTACHMENTS, + limit: max_attachments, }, )); } @@ -2959,6 +3024,7 @@ impl<A: HalApi> Device<A> { } } } + break None; }; if let Some(e) = error { @@ -2967,6 +3033,16 @@ impl<A: HalApi> Device<A> { } } + let limit = self.limits.max_color_attachment_bytes_per_sample; + let formats = color_targets + .iter() + .map(|cs| cs.as_ref().map(|cs| cs.format)); + if let Err(total) = validate_color_attachment_bytes_per_sample(formats, limit) { + return Err(pipeline::CreateRenderPipelineError::ColorAttachment( + command::ColorAttachmentError::TooManyBytesPerSample { total, limit }, + )); + } + if let Some(ds) = depth_stencil_state { let error = loop { let format_features = self.describe_format_features(adapter, ds.format)?; @@ -3051,6 +3127,7 @@ impl<A: HalApi> Device<A> { }; let vertex_shader_module; + let vertex_entry_point_name; let vertex_stage = { let stage_desc = &desc.vertex.stage; let stage = wgt::ShaderStages::VERTEX; @@ -3065,27 +3142,37 @@ impl<A: HalApi> Device<A> { return Err(DeviceError::WrongDevice.into()); } + let stage_err = |error| pipeline::CreateRenderPipelineError::Stage { stage, error }; + + vertex_entry_point_name = vertex_shader_module + .finalize_entry_point_name( + stage, + stage_desc.entry_point.as_ref().map(|ep| ep.as_ref()), + ) + .map_err(stage_err)?; + if let Some(ref interface) = vertex_shader_module.interface { io = interface .check_stage( &mut binding_layout_source, &mut shader_binding_sizes, - &stage_desc.entry_point, + &vertex_entry_point_name, stage, io, desc.depth_stencil.as_ref().map(|d| d.depth_compare), ) - .map_err(|error| pipeline::CreateRenderPipelineError::Stage { stage, error })?; + .map_err(stage_err)?; validated_stages |= stage; } hal::ProgrammableStage { module: vertex_shader_module.raw(), - entry_point: stage_desc.entry_point.as_ref(), + entry_point: &vertex_entry_point_name, } }; let mut fragment_shader_module = None; + let fragment_entry_point_name; let fragment_stage = match desc.fragment { Some(ref fragment_state) => { let stage = wgt::ShaderStages::FRAGMENT; @@ -3099,28 +3186,38 @@ impl<A: HalApi> Device<A> { })?, ); + let stage_err = |error| pipeline::CreateRenderPipelineError::Stage { stage, error }; + + fragment_entry_point_name = shader_module + .finalize_entry_point_name( + stage, + fragment_state + .stage + .entry_point + .as_ref() + .map(|ep| ep.as_ref()), + ) + .map_err(stage_err)?; + if validated_stages == wgt::ShaderStages::VERTEX { if let Some(ref interface) = shader_module.interface { io = interface .check_stage( &mut binding_layout_source, &mut shader_binding_sizes, - &fragment_state.stage.entry_point, + &fragment_entry_point_name, stage, io, desc.depth_stencil.as_ref().map(|d| d.depth_compare), ) - .map_err(|error| pipeline::CreateRenderPipelineError::Stage { - stage, - error, - })?; + .map_err(stage_err)?; validated_stages |= stage; } } if let Some(ref interface) = shader_module.interface { shader_expects_dual_source_blending = interface - .fragment_uses_dual_source_blending(&fragment_state.stage.entry_point) + .fragment_uses_dual_source_blending(&fragment_entry_point_name) .map_err(|error| pipeline::CreateRenderPipelineError::Stage { stage, error, @@ -3129,7 +3226,7 @@ impl<A: HalApi> Device<A> { Some(hal::ProgrammableStage { module: shader_module.raw(), - entry_point: fragment_state.stage.entry_point.as_ref(), + entry_point: &fragment_entry_point_name, }) } None => None, @@ -3302,7 +3399,10 @@ impl<A: HalApi> Device<A> { strip_index_format: desc.primitive.strip_index_format, vertex_steps, late_sized_buffer_groups, - info: ResourceInfo::new(desc.label.borrow_or_default()), + info: ResourceInfo::new( + desc.label.borrow_or_default(), + Some(self.tracker_indices.render_pipelines.clone()), + ), }; Ok(pipeline) } @@ -3415,7 +3515,7 @@ impl<A: HalApi> Device<A> { Ok(QuerySet { raw: Some(unsafe { self.raw().create_query_set(&hal_desc).unwrap() }), device: self.clone(), - info: ResourceInfo::new(""), + info: ResourceInfo::new("", Some(self.tracker_indices.query_sets.clone())), desc: desc.map_label(|_| ()), }) } |