wgpu-core: Move storage code to new storage module.

This commit is contained in:
Jim Blandy 2023-05-22 18:50:46 -07:00
parent 17d5361879
commit 4d1fbeb753
20 changed files with 308 additions and 284 deletions

View File

@ -2,9 +2,9 @@ use crate::{
binding_model::{BindGroup, LateMinBufferBindingSizeMismatch, PipelineLayout}, binding_model::{BindGroup, LateMinBufferBindingSizeMismatch, PipelineLayout},
device::SHADER_STAGE_COUNT, device::SHADER_STAGE_COUNT,
hal_api::HalApi, hal_api::HalApi,
hub::Storage,
id::{BindGroupId, BindGroupLayoutId, PipelineLayoutId, Valid}, id::{BindGroupId, BindGroupLayoutId, PipelineLayoutId, Valid},
pipeline::LateSizedBufferGroup, pipeline::LateSizedBufferGroup,
storage::Storage,
Stored, Stored,
}; };

View File

@ -91,12 +91,13 @@ use crate::{
}, },
error::{ErrorFormatter, PrettyError}, error::{ErrorFormatter, PrettyError},
hal_api::HalApi, hal_api::HalApi,
hub::{Hub, Resource, Storage, Token}, hub::{Hub, Resource, Token},
id, id,
identity::GlobalIdentityHandlerFactory, identity::GlobalIdentityHandlerFactory,
init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction},
pipeline::{self, PipelineFlags}, pipeline::{self, PipelineFlags},
resource, resource,
storage::Storage,
track::RenderBundleScope, track::RenderBundleScope,
validation::check_buffer_usage, validation::check_buffer_usage,
Label, LabelHelpers, LifeGuard, Stored, Label, LabelHelpers, LifeGuard, Stored,

View File

@ -7,11 +7,12 @@ use crate::{
get_lowest_common_denom, get_lowest_common_denom,
global::Global, global::Global,
hal_api::HalApi, hal_api::HalApi,
hub::{self, Token}, hub::Token,
id::{BufferId, CommandEncoderId, DeviceId, TextureId, Valid}, id::{BufferId, CommandEncoderId, DeviceId, TextureId, Valid},
identity::GlobalIdentityHandlerFactory, identity::GlobalIdentityHandlerFactory,
init_tracker::{MemoryInitKind, TextureInitRange}, init_tracker::{MemoryInitKind, TextureInitRange},
resource::{Texture, TextureClearMode}, resource::{Texture, TextureClearMode},
storage,
track::{TextureSelector, TextureTracker}, track::{TextureSelector, TextureTracker},
}; };
@ -235,7 +236,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
} }
pub(crate) fn clear_texture<A: HalApi>( pub(crate) fn clear_texture<A: HalApi>(
storage: &hub::Storage<Texture<A>, TextureId>, storage: &storage::Storage<Texture<A>, TextureId>,
dst_texture_id: Valid<TextureId>, dst_texture_id: Valid<TextureId>,
range: TextureInitRange, range: TextureInitRange,
encoder: &mut A::CommandEncoder, encoder: &mut A::CommandEncoder,

View File

@ -13,12 +13,13 @@ use crate::{
error::{ErrorFormatter, PrettyError}, error::{ErrorFormatter, PrettyError},
global::Global, global::Global,
hal_api::HalApi, hal_api::HalApi,
hub::{Storage, Token}, hub::Token,
id, id,
identity::GlobalIdentityHandlerFactory, identity::GlobalIdentityHandlerFactory,
init_tracker::MemoryInitKind, init_tracker::MemoryInitKind,
pipeline, pipeline,
resource::{self, Buffer, Texture}, resource::{self, Buffer, Texture},
storage::Storage,
track::{Tracker, UsageConflict, UsageScope}, track::{Tracker, UsageConflict, UsageScope},
validation::{check_buffer_usage, MissingBufferUsageError}, validation::{check_buffer_usage, MissingBufferUsageError},
Label, Label,

View File

@ -5,10 +5,10 @@ use hal::CommandEncoder;
use crate::{ use crate::{
device::Device, device::Device,
hal_api::HalApi, hal_api::HalApi,
hub::Storage,
id::{self, TextureId}, id::{self, TextureId},
init_tracker::*, init_tracker::*,
resource::{Buffer, Texture}, resource::{Buffer, Texture},
storage::Storage,
track::{TextureTracker, Tracker}, track::{TextureTracker, Tracker},
FastHashMap, FastHashMap,
}; };

View File

@ -23,10 +23,11 @@ use crate::track::{Tracker, UsageScope};
use crate::{ use crate::{
global::Global, global::Global,
hal_api::HalApi, hal_api::HalApi,
hub::{Storage, Token}, hub::Token,
id, id,
identity::GlobalIdentityHandlerFactory, identity::GlobalIdentityHandlerFactory,
resource::{Buffer, Texture}, resource::{Buffer, Texture},
storage::Storage,
Label, Stored, Label, Stored,
}; };

View File

@ -6,11 +6,12 @@ use crate::{
command::{CommandBuffer, CommandEncoderError}, command::{CommandBuffer, CommandEncoderError},
global::Global, global::Global,
hal_api::HalApi, hal_api::HalApi,
hub::{Storage, Token}, hub::Token,
id::{self, Id, TypedId}, id::{self, Id, TypedId},
identity::GlobalIdentityHandlerFactory, identity::GlobalIdentityHandlerFactory,
init_tracker::MemoryInitKind, init_tracker::MemoryInitKind,
resource::QuerySet, resource::QuerySet,
storage::Storage,
Epoch, FastHashMap, Index, Epoch, FastHashMap, Index,
}; };
use std::{iter, marker::PhantomData}; use std::{iter, marker::PhantomData};

View File

@ -16,12 +16,13 @@ use crate::{
error::{ErrorFormatter, PrettyError}, error::{ErrorFormatter, PrettyError},
global::Global, global::Global,
hal_api::HalApi, hal_api::HalApi,
hub::{Storage, Token}, hub::Token,
id, id,
identity::GlobalIdentityHandlerFactory, identity::GlobalIdentityHandlerFactory,
init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction}, init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction},
pipeline::{self, PipelineFlags}, pipeline::{self, PipelineFlags},
resource::{self, Buffer, Texture, TextureView, TextureViewNotRenderableReason}, resource::{self, Buffer, Texture, TextureView, TextureViewNotRenderableReason},
storage::Storage,
track::{TextureSelector, UsageConflict, UsageScope}, track::{TextureSelector, UsageConflict, UsageScope},
validation::{ validation::{
check_buffer_usage, check_texture_usage, MissingBufferUsageError, MissingTextureUsageError, check_buffer_usage, check_texture_usage, MissingBufferUsageError, MissingTextureUsageError,

View File

@ -7,7 +7,7 @@ use crate::{
error::{ErrorFormatter, PrettyError}, error::{ErrorFormatter, PrettyError},
global::Global, global::Global,
hal_api::HalApi, hal_api::HalApi,
hub::{Storage, Token}, hub::Token,
id::{BufferId, CommandEncoderId, TextureId, Valid}, id::{BufferId, CommandEncoderId, TextureId, Valid},
identity::GlobalIdentityHandlerFactory, identity::GlobalIdentityHandlerFactory,
init_tracker::{ init_tracker::{
@ -15,6 +15,7 @@ use crate::{
TextureInitTrackerAction, TextureInitTrackerAction,
}, },
resource::{Texture, TextureErrorDimension}, resource::{Texture, TextureErrorDimension},
storage::Storage,
track::TextureSelector, track::TextureSelector,
}; };

View File

@ -3,7 +3,7 @@ use crate::{
device::life::WaitIdleError, device::life::WaitIdleError,
global::Global, global::Global,
hal_api::HalApi, hal_api::HalApi,
hub::{Hub, InvalidId, Storage, Token}, hub::{Hub, Token},
id, id,
identity::{GlobalIdentityHandlerFactory, Input}, identity::{GlobalIdentityHandlerFactory, Input},
init_tracker::{ init_tracker::{
@ -14,6 +14,7 @@ use crate::{
pipeline, present, pipeline, present,
resource::{self, BufferAccessResult, BufferMapState, TextureViewNotRenderableReason}, resource::{self, BufferAccessResult, BufferMapState, TextureViewNotRenderableReason},
resource::{BufferAccessError, BufferMapOperation}, resource::{BufferAccessError, BufferMapOperation},
storage::{InvalidId, Storage},
track::{BindGroupStates, TextureSelector, Tracker}, track::{BindGroupStates, TextureSelector, Tracker},
validation::{self, check_buffer_usage, check_texture_usage}, validation::{self, check_buffer_usage, check_texture_usage},
FastHashMap, Label, LabelHelpers as _, LifeGuard, MultiRefCount, RefCount, Stored, FastHashMap, Label, LabelHelpers as _, LifeGuard, MultiRefCount, RefCount, Stored,

View File

@ -1,11 +1,11 @@
use crate::{ use crate::{
hal_api::HalApi, hal_api::HalApi,
hub::{Element, StorageReport},
hub::{HubReport, Hubs}, hub::{HubReport, Hubs},
id, id,
identity::GlobalIdentityHandlerFactory, identity::GlobalIdentityHandlerFactory,
instance::{Instance, Surface}, instance::{Instance, Surface},
registry::Registry, registry::Registry,
storage::{Element, StorageReport},
}; };
#[derive(Debug)] #[derive(Debug)]

View File

@ -140,6 +140,7 @@ creation fails, the id supplied for that resource is marked to indicate
as much, allowing subsequent operations using that id to be properly as much, allowing subsequent operations using that id to be properly
flagged as errors as well. flagged as errors as well.
[`Backend`]: wgt::Backend
[`Global`]: crate::global::Global [`Global`]: crate::global::Global
[`Global::new`]: crate::global::Global::new [`Global::new`]: crate::global::Global::new
[`gfx_select`]: crate::gfx_select [`gfx_select`]: crate::gfx_select
@ -165,243 +166,12 @@ use crate::{
pipeline::{ComputePipeline, RenderPipeline, ShaderModule}, pipeline::{ComputePipeline, RenderPipeline, ShaderModule},
registry::Registry, registry::Registry,
resource::{Buffer, QuerySet, Sampler, StagingBuffer, Texture, TextureClearMode, TextureView}, resource::{Buffer, QuerySet, Sampler, StagingBuffer, Texture, TextureClearMode, TextureView},
Epoch, Index, storage::{Element, Storage, StorageReport},
}; };
use wgt::Backend;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
use std::cell::Cell; use std::cell::Cell;
use std::{fmt::Debug, marker::PhantomData, mem, ops}; use std::{fmt::Debug, marker::PhantomData};
/// An entry in a `Storage::map` table.
#[derive(Debug)]
pub(crate) enum Element<T> {
/// There are no live ids with this index.
Vacant,
/// There is one live id with this index, allocated at the given
/// epoch.
Occupied(T, Epoch),
/// Like `Occupied`, but an error occurred when creating the
/// resource.
///
/// The given `String` is the resource's descriptor label.
Error(Epoch, String),
}
#[derive(Clone, Debug, Default)]
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;
/// A table of `T` values indexed by the id type `I`.
///
/// The table is represented as a vector indexed by the ids' index
/// values, so you should use an id allocator like `IdentityManager`
/// that keeps the index values dense and close to zero.
#[derive(Debug)]
pub struct Storage<T, I: id::TypedId> {
pub(crate) map: Vec<Element<T>>,
pub(crate) kind: &'static str,
pub(crate) _phantom: PhantomData<I>,
}
impl<T, I: id::TypedId> ops::Index<id::Valid<I>> for Storage<T, I> {
type Output = T;
fn index(&self, id: id::Valid<I>) -> &T {
self.get(id.0).unwrap()
}
}
impl<T, I: id::TypedId> ops::IndexMut<id::Valid<I>> for Storage<T, I> {
fn index_mut(&mut self, id: id::Valid<I>) -> &mut T {
self.get_mut(id.0).unwrap()
}
}
impl<T, I: id::TypedId> Storage<T, I> {
pub(crate) fn contains(&self, id: I) -> bool {
let (index, epoch, _) = id.unzip();
match self.map.get(index as usize) {
Some(&Element::Vacant) => false,
Some(&Element::Occupied(_, storage_epoch) | &Element::Error(storage_epoch, _)) => {
storage_epoch == epoch
}
None => false,
}
}
/// Attempts to get a reference to an item behind a potentially invalid ID.
///
/// Returns [`None`] if there is an epoch mismatch, or the entry is empty.
///
/// This function is primarily intended for the `as_hal` family of functions
/// where you may need to fallibly get a object backed by an id that could
/// be in a different hub.
pub(crate) fn try_get(&self, id: I) -> Result<Option<&T>, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch),
Some(&Element::Vacant) => return Ok(None),
Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
None => return Err(InvalidId),
};
assert_eq!(
epoch, storage_epoch,
"{}[{}] is no longer alive",
self.kind, index
);
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<&T, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch),
Some(&Element::Vacant) => panic!("{}[{}] does not exist", self.kind, index),
Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
None => return Err(InvalidId),
};
assert_eq!(
epoch, storage_epoch,
"{}[{}] is no longer alive",
self.kind, index
);
result
}
/// Get a mutable 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_mut(&mut self, id: I) -> Result<&mut T, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get_mut(index as usize) {
Some(&mut Element::Occupied(ref mut v, epoch)) => (Ok(v), epoch),
Some(&mut Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index),
Some(&mut Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
};
assert_eq!(
epoch, storage_epoch,
"{}[{}] is no longer alive",
self.kind, index
);
result
}
pub(crate) unsafe fn get_unchecked(&self, id: u32) -> &T {
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) {
Some(&Element::Error(_, ref label)) => label,
_ => "",
}
}
fn insert_impl(&mut self, index: usize, element: Element<T>) {
if index >= self.map.len() {
self.map.resize_with(index + 1, || Element::Vacant);
}
match std::mem::replace(&mut self.map[index], element) {
Element::Vacant => {}
_ => panic!("Index {index:?} is already occupied"),
}
}
pub(crate) fn insert(&mut self, id: I, value: T) {
let (index, epoch, _) = id.unzip();
self.insert_impl(index as usize, Element::Occupied(value, epoch))
}
pub(crate) fn insert_error(&mut self, id: I, label: &str) {
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, value: T) {
let (index, epoch, _) = id.unzip();
self.map[index as usize] = Element::Occupied(value, epoch);
}
pub(crate) fn remove(&mut self, id: I) -> Option<T> {
let (index, epoch, _) = id.unzip();
match std::mem::replace(&mut self.map[index as usize], Element::Vacant) {
Element::Occupied(value, storage_epoch) => {
assert_eq!(epoch, storage_epoch);
Some(value)
}
Element::Error(..) => None,
Element::Vacant => panic!("Cannot remove a vacant resource"),
}
}
// Prevents panic on out of range access, allows Vacant elements.
pub(crate) fn _try_remove(&mut self, id: I) -> Option<T> {
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<Item = (I, &T)> {
self.map
.iter()
.enumerate()
.filter_map(move |(index, x)| match *x {
Element::Occupied(ref value, storage_epoch) => {
Some((I::zip(index as Index, storage_epoch, backend), value))
}
_ => None,
})
}
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::<T>(),
..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
}
}
/// Type system for enforcing the lock order on [`Hub`] fields. /// Type system for enforcing the lock order on [`Hub`] fields.
/// ///

View File

@ -45,7 +45,7 @@ type Dummy = hal::api::Empty;
/// [`Global`]: crate::global::Global /// [`Global`]: crate::global::Global
/// [`Hub`]: crate::hub::Hub /// [`Hub`]: crate::hub::Hub
/// [`Hub<A>`]: crate::hub::Hub /// [`Hub<A>`]: crate::hub::Hub
/// [`Storage`]: crate::hub::Storage /// [`Storage`]: crate::storage::Storage
/// [`Texture<A>`]: crate::resource::Texture /// [`Texture<A>`]: crate::resource::Texture
/// [`Index`]: std::ops::Index /// [`Index`]: std::ops::Index
/// [`IndexMut`]: std::ops::IndexMut /// [`IndexMut`]: std::ops::IndexMut

View File

@ -53,6 +53,7 @@ pub mod pipeline;
pub mod present; pub mod present;
pub mod registry; pub mod registry;
pub mod resource; pub mod resource;
pub mod storage;
mod track; mod track;
mod validation; mod validation;

View File

@ -4,9 +4,10 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use wgt::Backend; use wgt::Backend;
use crate::{ use crate::{
hub::{Access, Resource, Storage, Token}, hub::{Access, Resource, Token},
id, id,
identity::{IdentityHandler, IdentityHandlerFactory}, identity::{IdentityHandler, IdentityHandlerFactory},
storage::Storage,
}; };
#[derive(Debug)] #[derive(Debug)]

234
wgpu-core/src/storage.rs Normal file
View File

@ -0,0 +1,234 @@
use std::{marker::PhantomData, mem, ops};
use wgt::Backend;
use crate::{id, Epoch, Index};
/// An entry in a `Storage::map` table.
#[derive(Debug)]
pub(crate) enum Element<T> {
/// There are no live ids with this index.
Vacant,
/// There is one live id with this index, allocated at the given
/// epoch.
Occupied(T, Epoch),
/// Like `Occupied`, but an error occurred when creating the
/// resource.
///
/// The given `String` is the resource's descriptor label.
Error(Epoch, String),
}
#[derive(Clone, Debug, Default)]
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;
/// A table of `T` values indexed by the id type `I`.
///
/// The table is represented as a vector indexed by the ids' index
/// values, so you should use an id allocator like `IdentityManager`
/// that keeps the index values dense and close to zero.
#[derive(Debug)]
pub struct Storage<T, I: id::TypedId> {
pub(crate) map: Vec<Element<T>>,
pub(crate) kind: &'static str,
pub(crate) _phantom: PhantomData<I>,
}
impl<T, I: id::TypedId> ops::Index<id::Valid<I>> for Storage<T, I> {
type Output = T;
fn index(&self, id: id::Valid<I>) -> &T {
self.get(id.0).unwrap()
}
}
impl<T, I: id::TypedId> ops::IndexMut<id::Valid<I>> for Storage<T, I> {
fn index_mut(&mut self, id: id::Valid<I>) -> &mut T {
self.get_mut(id.0).unwrap()
}
}
impl<T, I: id::TypedId> Storage<T, I> {
pub(crate) fn contains(&self, id: I) -> bool {
let (index, epoch, _) = id.unzip();
match self.map.get(index as usize) {
Some(&Element::Vacant) => false,
Some(&Element::Occupied(_, storage_epoch) | &Element::Error(storage_epoch, _)) => {
storage_epoch == epoch
}
None => false,
}
}
/// Attempts to get a reference to an item behind a potentially invalid ID.
///
/// Returns [`None`] if there is an epoch mismatch, or the entry is empty.
///
/// This function is primarily intended for the `as_hal` family of functions
/// where you may need to fallibly get a object backed by an id that could
/// be in a different hub.
pub(crate) fn try_get(&self, id: I) -> Result<Option<&T>, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch),
Some(&Element::Vacant) => return Ok(None),
Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
None => return Err(InvalidId),
};
assert_eq!(
epoch, storage_epoch,
"{}[{}] is no longer alive",
self.kind, index
);
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<&T, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch),
Some(&Element::Vacant) => panic!("{}[{}] does not exist", self.kind, index),
Some(&Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
None => return Err(InvalidId),
};
assert_eq!(
epoch, storage_epoch,
"{}[{}] is no longer alive",
self.kind, index
);
result
}
/// Get a mutable 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_mut(&mut self, id: I) -> Result<&mut T, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get_mut(index as usize) {
Some(&mut Element::Occupied(ref mut v, epoch)) => (Ok(v), epoch),
Some(&mut Element::Vacant) | None => panic!("{}[{}] does not exist", self.kind, index),
Some(&mut Element::Error(epoch, ..)) => (Err(InvalidId), epoch),
};
assert_eq!(
epoch, storage_epoch,
"{}[{}] is no longer alive",
self.kind, index
);
result
}
pub(crate) unsafe fn get_unchecked(&self, id: u32) -> &T {
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) {
Some(&Element::Error(_, ref label)) => label,
_ => "",
}
}
fn insert_impl(&mut self, index: usize, element: Element<T>) {
if index >= self.map.len() {
self.map.resize_with(index + 1, || Element::Vacant);
}
match std::mem::replace(&mut self.map[index], element) {
Element::Vacant => {}
_ => panic!("Index {index:?} is already occupied"),
}
}
pub(crate) fn insert(&mut self, id: I, value: T) {
let (index, epoch, _) = id.unzip();
self.insert_impl(index as usize, Element::Occupied(value, epoch))
}
pub(crate) fn insert_error(&mut self, id: I, label: &str) {
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, value: T) {
let (index, epoch, _) = id.unzip();
self.map[index as usize] = Element::Occupied(value, epoch);
}
pub(crate) fn remove(&mut self, id: I) -> Option<T> {
let (index, epoch, _) = id.unzip();
match std::mem::replace(&mut self.map[index as usize], Element::Vacant) {
Element::Occupied(value, storage_epoch) => {
assert_eq!(epoch, storage_epoch);
Some(value)
}
Element::Error(..) => None,
Element::Vacant => panic!("Cannot remove a vacant resource"),
}
}
// Prevents panic on out of range access, allows Vacant elements.
pub(crate) fn _try_remove(&mut self, id: I) -> Option<T> {
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<Item = (I, &T)> {
self.map
.iter()
.enumerate()
.filter_map(move |(index, x)| match *x {
Element::Occupied(ref value, storage_epoch) => {
Some((I::zip(index as Index, storage_epoch, backend), value))
}
_ => None,
})
}
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::<T>(),
..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
}
}

View File

@ -10,9 +10,9 @@ use std::{borrow::Cow, marker::PhantomData, vec::Drain};
use super::PendingTransition; use super::PendingTransition;
use crate::{ use crate::{
hal_api::HalApi, hal_api::HalApi,
hub,
id::{BufferId, TypedId, Valid}, id::{BufferId, TypedId, Valid},
resource::Buffer, resource::Buffer,
storage,
track::{ track::{
invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider, invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider,
ResourceUses, UsageConflict, ResourceUses, UsageConflict,
@ -73,7 +73,7 @@ impl<A: HalApi> BufferBindGroupState<A> {
/// Adds the given resource with the given state. /// Adds the given resource with the given state.
pub fn add_single<'a>( pub fn add_single<'a>(
&mut self, &mut self,
storage: &'a hub::Storage<Buffer<A>, BufferId>, storage: &'a storage::Storage<Buffer<A>, BufferId>,
id: BufferId, id: BufferId,
state: BufferUses, state: BufferUses,
) -> Option<&'a Buffer<A>> { ) -> Option<&'a Buffer<A>> {
@ -216,7 +216,7 @@ impl<A: HalApi> BufferUsageScope<A> {
/// the vectors will be extended. A call to set_size is not needed. /// the vectors will be extended. A call to set_size is not needed.
pub fn merge_single<'a>( pub fn merge_single<'a>(
&mut self, &mut self,
storage: &'a hub::Storage<Buffer<A>, BufferId>, storage: &'a storage::Storage<Buffer<A>, BufferId>,
id: BufferId, id: BufferId,
new_state: BufferUses, new_state: BufferUses,
) -> Result<&'a Buffer<A>, UsageConflict> { ) -> Result<&'a Buffer<A>, UsageConflict> {
@ -349,7 +349,7 @@ impl<A: HalApi> BufferTracker<A> {
/// the vectors will be extended. A call to set_size is not needed. /// the vectors will be extended. A call to set_size is not needed.
pub fn set_single<'a>( pub fn set_single<'a>(
&mut self, &mut self,
storage: &'a hub::Storage<Buffer<A>, BufferId>, storage: &'a storage::Storage<Buffer<A>, BufferId>,
id: BufferId, id: BufferId,
state: BufferUses, state: BufferUses,
) -> Option<(&'a Buffer<A>, Option<PendingTransition<BufferUses>>)> { ) -> Option<(&'a Buffer<A>, Option<PendingTransition<BufferUses>>)> {

View File

@ -102,9 +102,8 @@ mod texture;
use crate::{ use crate::{
binding_model, command, conv, binding_model, command, conv,
hal_api::HalApi, hal_api::HalApi,
hub,
id::{self, TypedId}, id::{self, TypedId},
pipeline, resource, pipeline, resource, storage,
}; };
use std::{fmt, ops}; use std::{fmt, ops};
@ -358,11 +357,11 @@ pub(crate) struct RenderBundleScope<A: HalApi> {
impl<A: HalApi> RenderBundleScope<A> { impl<A: HalApi> RenderBundleScope<A> {
/// Create the render bundle scope and pull the maximum IDs from the hubs. /// Create the render bundle scope and pull the maximum IDs from the hubs.
pub fn new( pub fn new(
buffers: &hub::Storage<resource::Buffer<A>, id::BufferId>, buffers: &storage::Storage<resource::Buffer<A>, id::BufferId>,
textures: &hub::Storage<resource::Texture<A>, id::TextureId>, textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
bind_groups: &hub::Storage<binding_model::BindGroup<A>, id::BindGroupId>, bind_groups: &storage::Storage<binding_model::BindGroup<A>, id::BindGroupId>,
render_pipelines: &hub::Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>, render_pipelines: &storage::Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>,
query_sets: &hub::Storage<resource::QuerySet<A>, id::QuerySetId>, query_sets: &storage::Storage<resource::QuerySet<A>, id::QuerySetId>,
) -> Self { ) -> Self {
let mut value = Self { let mut value = Self {
buffers: BufferUsageScope::new(), buffers: BufferUsageScope::new(),
@ -392,7 +391,7 @@ impl<A: HalApi> RenderBundleScope<A> {
/// length of the storage given at the call to `new`. /// length of the storage given at the call to `new`.
pub unsafe fn merge_bind_group( pub unsafe fn merge_bind_group(
&mut self, &mut self,
textures: &hub::Storage<resource::Texture<A>, id::TextureId>, textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
bind_group: &BindGroupStates<A>, bind_group: &BindGroupStates<A>,
) -> Result<(), UsageConflict> { ) -> Result<(), UsageConflict> {
unsafe { self.buffers.merge_bind_group(&bind_group.buffers)? }; unsafe { self.buffers.merge_bind_group(&bind_group.buffers)? };
@ -416,8 +415,8 @@ pub(crate) struct UsageScope<A: HalApi> {
impl<A: HalApi> UsageScope<A> { impl<A: HalApi> UsageScope<A> {
/// Create the render bundle scope and pull the maximum IDs from the hubs. /// Create the render bundle scope and pull the maximum IDs from the hubs.
pub fn new( pub fn new(
buffers: &hub::Storage<resource::Buffer<A>, id::BufferId>, buffers: &storage::Storage<resource::Buffer<A>, id::BufferId>,
textures: &hub::Storage<resource::Texture<A>, id::TextureId>, textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
) -> Self { ) -> Self {
let mut value = Self { let mut value = Self {
buffers: BufferUsageScope::new(), buffers: BufferUsageScope::new(),
@ -441,7 +440,7 @@ impl<A: HalApi> UsageScope<A> {
/// length of the storage given at the call to `new`. /// length of the storage given at the call to `new`.
pub unsafe fn merge_bind_group( pub unsafe fn merge_bind_group(
&mut self, &mut self,
textures: &hub::Storage<resource::Texture<A>, id::TextureId>, textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
bind_group: &BindGroupStates<A>, bind_group: &BindGroupStates<A>,
) -> Result<(), UsageConflict> { ) -> Result<(), UsageConflict> {
unsafe { unsafe {
@ -464,7 +463,7 @@ impl<A: HalApi> UsageScope<A> {
/// length of the storage given at the call to `new`. /// length of the storage given at the call to `new`.
pub unsafe fn merge_render_bundle( pub unsafe fn merge_render_bundle(
&mut self, &mut self,
textures: &hub::Storage<resource::Texture<A>, id::TextureId>, textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
render_bundle: &RenderBundleScope<A>, render_bundle: &RenderBundleScope<A>,
) -> Result<(), UsageConflict> { ) -> Result<(), UsageConflict> {
self.buffers.merge_usage_scope(&render_bundle.buffers)?; self.buffers.merge_usage_scope(&render_bundle.buffers)?;
@ -506,17 +505,19 @@ impl<A: HalApi> Tracker<A> {
/// Pull the maximum IDs from the hubs. /// Pull the maximum IDs from the hubs.
pub fn set_size( pub fn set_size(
&mut self, &mut self,
buffers: Option<&hub::Storage<resource::Buffer<A>, id::BufferId>>, buffers: Option<&storage::Storage<resource::Buffer<A>, id::BufferId>>,
textures: Option<&hub::Storage<resource::Texture<A>, id::TextureId>>, textures: Option<&storage::Storage<resource::Texture<A>, id::TextureId>>,
views: Option<&hub::Storage<resource::TextureView<A>, id::TextureViewId>>, views: Option<&storage::Storage<resource::TextureView<A>, id::TextureViewId>>,
samplers: Option<&hub::Storage<resource::Sampler<A>, id::SamplerId>>, samplers: Option<&storage::Storage<resource::Sampler<A>, id::SamplerId>>,
bind_groups: Option<&hub::Storage<binding_model::BindGroup<A>, id::BindGroupId>>, bind_groups: Option<&storage::Storage<binding_model::BindGroup<A>, id::BindGroupId>>,
compute_pipelines: Option< compute_pipelines: Option<
&hub::Storage<pipeline::ComputePipeline<A>, id::ComputePipelineId>, &storage::Storage<pipeline::ComputePipeline<A>, id::ComputePipelineId>,
>, >,
render_pipelines: Option<&hub::Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>>, render_pipelines: Option<
bundles: Option<&hub::Storage<command::RenderBundle<A>, id::RenderBundleId>>, &storage::Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>,
query_sets: Option<&hub::Storage<resource::QuerySet<A>, id::QuerySetId>>, >,
bundles: Option<&storage::Storage<command::RenderBundle<A>, id::RenderBundleId>>,
query_sets: Option<&storage::Storage<resource::QuerySet<A>, id::QuerySetId>>,
) { ) {
if let Some(buffers) = buffers { if let Some(buffers) = buffers {
self.buffers.set_size(buffers.len()); self.buffers.set_size(buffers.len());
@ -571,7 +572,7 @@ impl<A: HalApi> Tracker<A> {
/// value given to `set_size` /// value given to `set_size`
pub unsafe fn set_and_remove_from_usage_scope_sparse( pub unsafe fn set_and_remove_from_usage_scope_sparse(
&mut self, &mut self,
textures: &hub::Storage<resource::Texture<A>, id::TextureId>, textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
scope: &mut UsageScope<A>, scope: &mut UsageScope<A>,
bind_group: &BindGroupStates<A>, bind_group: &BindGroupStates<A>,
) { ) {

View File

@ -10,6 +10,7 @@ use crate::{
hal_api::HalApi, hal_api::HalApi,
hub, hub,
id::{TypedId, Valid}, id::{TypedId, Valid},
storage,
track::ResourceMetadata, track::ResourceMetadata,
RefCount, RefCount,
}; };
@ -45,7 +46,11 @@ impl<T: hub::Resource, Id: TypedId> StatelessBindGroupSate<T, Id> {
} }
/// Adds the given resource. /// Adds the given resource.
pub fn add_single<'a>(&mut self, storage: &'a hub::Storage<T, Id>, id: Id) -> Option<&'a T> { pub fn add_single<'a>(
&mut self,
storage: &'a storage::Storage<T, Id>,
id: Id,
) -> Option<&'a T> {
let resource = storage.get(id).ok()?; let resource = storage.get(id).ok()?;
self.resources self.resources
@ -118,7 +123,11 @@ impl<A: HalApi, T: hub::Resource, Id: TypedId> StatelessTracker<A, T, Id> {
/// ///
/// If the ID is higher than the length of internal vectors, /// If the ID is higher than the length of internal vectors,
/// the vectors will be extended. A call to set_size is not needed. /// the vectors will be extended. A call to set_size is not needed.
pub fn add_single<'a>(&mut self, storage: &'a hub::Storage<T, Id>, id: Id) -> Option<&'a T> { pub fn add_single<'a>(
&mut self,
storage: &'a storage::Storage<T, Id>,
id: Id,
) -> Option<&'a T> {
let item = storage.get(id).ok()?; let item = storage.get(id).ok()?;
let (index32, epoch, _) = id.unzip(); let (index32, epoch, _) = id.unzip();

View File

@ -22,9 +22,9 @@
use super::{range::RangedStates, PendingTransition}; use super::{range::RangedStates, PendingTransition};
use crate::{ use crate::{
hal_api::HalApi, hal_api::HalApi,
hub,
id::{TextureId, TypedId, Valid}, id::{TextureId, TypedId, Valid},
resource::Texture, resource::Texture,
storage,
track::{ track::{
invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider, invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider,
ResourceUses, UsageConflict, ResourceUses, UsageConflict,
@ -185,7 +185,7 @@ impl<A: HalApi> TextureBindGroupState<A> {
/// Adds the given resource with the given state. /// Adds the given resource with the given state.
pub fn add_single<'a>( pub fn add_single<'a>(
&mut self, &mut self,
storage: &'a hub::Storage<Texture<A>, TextureId>, storage: &'a storage::Storage<Texture<A>, TextureId>,
id: TextureId, id: TextureId,
ref_count: RefCount, ref_count: RefCount,
selector: Option<TextureSelector>, selector: Option<TextureSelector>,
@ -279,7 +279,7 @@ impl<A: HalApi> TextureUsageScope<A> {
/// the vectors will be extended. A call to set_size is not needed. /// the vectors will be extended. A call to set_size is not needed.
pub fn merge_usage_scope( pub fn merge_usage_scope(
&mut self, &mut self,
storage: &hub::Storage<Texture<A>, TextureId>, storage: &storage::Storage<Texture<A>, TextureId>,
scope: &Self, scope: &Self,
) -> Result<(), UsageConflict> { ) -> Result<(), UsageConflict> {
let incoming_size = scope.set.simple.len(); let incoming_size = scope.set.simple.len();
@ -326,7 +326,7 @@ impl<A: HalApi> TextureUsageScope<A> {
/// method is called. /// method is called.
pub unsafe fn merge_bind_group( pub unsafe fn merge_bind_group(
&mut self, &mut self,
storage: &hub::Storage<Texture<A>, TextureId>, storage: &storage::Storage<Texture<A>, TextureId>,
bind_group: &TextureBindGroupState<A>, bind_group: &TextureBindGroupState<A>,
) -> Result<(), UsageConflict> { ) -> Result<(), UsageConflict> {
for &(id, ref selector, ref ref_count, state) in &bind_group.textures { for &(id, ref selector, ref ref_count, state) in &bind_group.textures {
@ -351,7 +351,7 @@ impl<A: HalApi> TextureUsageScope<A> {
/// method is called. /// method is called.
pub unsafe fn merge_single( pub unsafe fn merge_single(
&mut self, &mut self,
storage: &hub::Storage<Texture<A>, TextureId>, storage: &storage::Storage<Texture<A>, TextureId>,
id: Valid<TextureId>, id: Valid<TextureId>,
selector: Option<TextureSelector>, selector: Option<TextureSelector>,
ref_count: &RefCount, ref_count: &RefCount,
@ -564,7 +564,7 @@ impl<A: HalApi> TextureTracker<A> {
/// the vectors will be extended. A call to set_size is not needed. /// the vectors will be extended. A call to set_size is not needed.
pub fn set_from_tracker( pub fn set_from_tracker(
&mut self, &mut self,
storage: &hub::Storage<Texture<A>, TextureId>, storage: &storage::Storage<Texture<A>, TextureId>,
tracker: &Self, tracker: &Self,
) { ) {
let incoming_size = tracker.start_set.simple.len(); let incoming_size = tracker.start_set.simple.len();
@ -610,7 +610,7 @@ impl<A: HalApi> TextureTracker<A> {
/// the vectors will be extended. A call to set_size is not needed. /// the vectors will be extended. A call to set_size is not needed.
pub fn set_from_usage_scope( pub fn set_from_usage_scope(
&mut self, &mut self,
storage: &hub::Storage<Texture<A>, TextureId>, storage: &storage::Storage<Texture<A>, TextureId>,
scope: &TextureUsageScope<A>, scope: &TextureUsageScope<A>,
) { ) {
let incoming_size = scope.set.simple.len(); let incoming_size = scope.set.simple.len();
@ -662,7 +662,7 @@ impl<A: HalApi> TextureTracker<A> {
/// method is called. /// method is called.
pub unsafe fn set_and_remove_from_usage_scope_sparse( pub unsafe fn set_and_remove_from_usage_scope_sparse(
&mut self, &mut self,
storage: &hub::Storage<Texture<A>, TextureId>, storage: &storage::Storage<Texture<A>, TextureId>,
scope: &mut TextureUsageScope<A>, scope: &mut TextureUsageScope<A>,
bind_group_state: &TextureBindGroupState<A>, bind_group_state: &TextureBindGroupState<A>,
) { ) {
@ -877,7 +877,7 @@ impl<'a> TextureStateProvider<'a> {
/// out of the texture storage. /// out of the texture storage.
#[inline(always)] #[inline(always)]
unsafe fn texture_data_from_texture<A: HalApi>( unsafe fn texture_data_from_texture<A: HalApi>(
storage: &hub::Storage<Texture<A>, TextureId>, storage: &storage::Storage<Texture<A>, TextureId>,
index32: u32, index32: u32,
) -> (&LifeGuard, &TextureSelector) { ) -> (&LifeGuard, &TextureSelector) {
let texture = unsafe { storage.get_unchecked(index32) }; let texture = unsafe { storage.get_unchecked(index32) };