mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-26 00:33:51 +00:00
wgpu-core: Move storage code to new storage
module.
This commit is contained in:
parent
17d5361879
commit
4d1fbeb753
@ -2,9 +2,9 @@ use crate::{
|
||||
binding_model::{BindGroup, LateMinBufferBindingSizeMismatch, PipelineLayout},
|
||||
device::SHADER_STAGE_COUNT,
|
||||
hal_api::HalApi,
|
||||
hub::Storage,
|
||||
id::{BindGroupId, BindGroupLayoutId, PipelineLayoutId, Valid},
|
||||
pipeline::LateSizedBufferGroup,
|
||||
storage::Storage,
|
||||
Stored,
|
||||
};
|
||||
|
||||
|
@ -91,12 +91,13 @@ use crate::{
|
||||
},
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
hal_api::HalApi,
|
||||
hub::{Hub, Resource, Storage, Token},
|
||||
hub::{Hub, Resource, Token},
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction},
|
||||
pipeline::{self, PipelineFlags},
|
||||
resource,
|
||||
storage::Storage,
|
||||
track::RenderBundleScope,
|
||||
validation::check_buffer_usage,
|
||||
Label, LabelHelpers, LifeGuard, Stored,
|
||||
|
@ -7,11 +7,12 @@ use crate::{
|
||||
get_lowest_common_denom,
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{self, Token},
|
||||
hub::Token,
|
||||
id::{BufferId, CommandEncoderId, DeviceId, TextureId, Valid},
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{MemoryInitKind, TextureInitRange},
|
||||
resource::{Texture, TextureClearMode},
|
||||
storage,
|
||||
track::{TextureSelector, TextureTracker},
|
||||
};
|
||||
|
||||
@ -235,7 +236,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
|
||||
pub(crate) fn clear_texture<A: HalApi>(
|
||||
storage: &hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &storage::Storage<Texture<A>, TextureId>,
|
||||
dst_texture_id: Valid<TextureId>,
|
||||
range: TextureInitRange,
|
||||
encoder: &mut A::CommandEncoder,
|
||||
|
@ -13,12 +13,13 @@ use crate::{
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{Storage, Token},
|
||||
hub::Token,
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::MemoryInitKind,
|
||||
pipeline,
|
||||
resource::{self, Buffer, Texture},
|
||||
storage::Storage,
|
||||
track::{Tracker, UsageConflict, UsageScope},
|
||||
validation::{check_buffer_usage, MissingBufferUsageError},
|
||||
Label,
|
||||
|
@ -5,10 +5,10 @@ use hal::CommandEncoder;
|
||||
use crate::{
|
||||
device::Device,
|
||||
hal_api::HalApi,
|
||||
hub::Storage,
|
||||
id::{self, TextureId},
|
||||
init_tracker::*,
|
||||
resource::{Buffer, Texture},
|
||||
storage::Storage,
|
||||
track::{TextureTracker, Tracker},
|
||||
FastHashMap,
|
||||
};
|
||||
|
@ -23,10 +23,11 @@ use crate::track::{Tracker, UsageScope};
|
||||
use crate::{
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{Storage, Token},
|
||||
hub::Token,
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
resource::{Buffer, Texture},
|
||||
storage::Storage,
|
||||
Label, Stored,
|
||||
};
|
||||
|
||||
|
@ -6,11 +6,12 @@ use crate::{
|
||||
command::{CommandBuffer, CommandEncoderError},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{Storage, Token},
|
||||
hub::Token,
|
||||
id::{self, Id, TypedId},
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::MemoryInitKind,
|
||||
resource::QuerySet,
|
||||
storage::Storage,
|
||||
Epoch, FastHashMap, Index,
|
||||
};
|
||||
use std::{iter, marker::PhantomData};
|
||||
|
@ -16,12 +16,13 @@ use crate::{
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{Storage, Token},
|
||||
hub::Token,
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction},
|
||||
pipeline::{self, PipelineFlags},
|
||||
resource::{self, Buffer, Texture, TextureView, TextureViewNotRenderableReason},
|
||||
storage::Storage,
|
||||
track::{TextureSelector, UsageConflict, UsageScope},
|
||||
validation::{
|
||||
check_buffer_usage, check_texture_usage, MissingBufferUsageError, MissingTextureUsageError,
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
error::{ErrorFormatter, PrettyError},
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{Storage, Token},
|
||||
hub::Token,
|
||||
id::{BufferId, CommandEncoderId, TextureId, Valid},
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
init_tracker::{
|
||||
@ -15,6 +15,7 @@ use crate::{
|
||||
TextureInitTrackerAction,
|
||||
},
|
||||
resource::{Texture, TextureErrorDimension},
|
||||
storage::Storage,
|
||||
track::TextureSelector,
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
device::life::WaitIdleError,
|
||||
global::Global,
|
||||
hal_api::HalApi,
|
||||
hub::{Hub, InvalidId, Storage, Token},
|
||||
hub::{Hub, Token},
|
||||
id,
|
||||
identity::{GlobalIdentityHandlerFactory, Input},
|
||||
init_tracker::{
|
||||
@ -14,6 +14,7 @@ use crate::{
|
||||
pipeline, present,
|
||||
resource::{self, BufferAccessResult, BufferMapState, TextureViewNotRenderableReason},
|
||||
resource::{BufferAccessError, BufferMapOperation},
|
||||
storage::{InvalidId, Storage},
|
||||
track::{BindGroupStates, TextureSelector, Tracker},
|
||||
validation::{self, check_buffer_usage, check_texture_usage},
|
||||
FastHashMap, Label, LabelHelpers as _, LifeGuard, MultiRefCount, RefCount, Stored,
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::{
|
||||
hal_api::HalApi,
|
||||
hub::{Element, StorageReport},
|
||||
hub::{HubReport, Hubs},
|
||||
id,
|
||||
identity::GlobalIdentityHandlerFactory,
|
||||
instance::{Instance, Surface},
|
||||
registry::Registry,
|
||||
storage::{Element, StorageReport},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -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
|
||||
flagged as errors as well.
|
||||
|
||||
[`Backend`]: wgt::Backend
|
||||
[`Global`]: crate::global::Global
|
||||
[`Global::new`]: crate::global::Global::new
|
||||
[`gfx_select`]: crate::gfx_select
|
||||
@ -165,243 +166,12 @@ use crate::{
|
||||
pipeline::{ComputePipeline, RenderPipeline, ShaderModule},
|
||||
registry::Registry,
|
||||
resource::{Buffer, QuerySet, Sampler, StagingBuffer, Texture, TextureClearMode, TextureView},
|
||||
Epoch, Index,
|
||||
storage::{Element, Storage, StorageReport},
|
||||
};
|
||||
|
||||
use wgt::Backend;
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
use std::cell::Cell;
|
||||
use std::{fmt::Debug, marker::PhantomData, mem, ops};
|
||||
|
||||
/// 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
|
||||
}
|
||||
}
|
||||
use std::{fmt::Debug, marker::PhantomData};
|
||||
|
||||
/// Type system for enforcing the lock order on [`Hub`] fields.
|
||||
///
|
||||
|
@ -45,7 +45,7 @@ type Dummy = hal::api::Empty;
|
||||
/// [`Global`]: crate::global::Global
|
||||
/// [`Hub`]: crate::hub::Hub
|
||||
/// [`Hub<A>`]: crate::hub::Hub
|
||||
/// [`Storage`]: crate::hub::Storage
|
||||
/// [`Storage`]: crate::storage::Storage
|
||||
/// [`Texture<A>`]: crate::resource::Texture
|
||||
/// [`Index`]: std::ops::Index
|
||||
/// [`IndexMut`]: std::ops::IndexMut
|
||||
|
@ -53,6 +53,7 @@ pub mod pipeline;
|
||||
pub mod present;
|
||||
pub mod registry;
|
||||
pub mod resource;
|
||||
pub mod storage;
|
||||
mod track;
|
||||
mod validation;
|
||||
|
||||
|
@ -4,9 +4,10 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
|
||||
use wgt::Backend;
|
||||
|
||||
use crate::{
|
||||
hub::{Access, Resource, Storage, Token},
|
||||
hub::{Access, Resource, Token},
|
||||
id,
|
||||
identity::{IdentityHandler, IdentityHandlerFactory},
|
||||
storage::Storage,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
|
234
wgpu-core/src/storage.rs
Normal file
234
wgpu-core/src/storage.rs
Normal 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
|
||||
}
|
||||
}
|
@ -10,9 +10,9 @@ use std::{borrow::Cow, marker::PhantomData, vec::Drain};
|
||||
use super::PendingTransition;
|
||||
use crate::{
|
||||
hal_api::HalApi,
|
||||
hub,
|
||||
id::{BufferId, TypedId, Valid},
|
||||
resource::Buffer,
|
||||
storage,
|
||||
track::{
|
||||
invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider,
|
||||
ResourceUses, UsageConflict,
|
||||
@ -73,7 +73,7 @@ impl<A: HalApi> BufferBindGroupState<A> {
|
||||
/// Adds the given resource with the given state.
|
||||
pub fn add_single<'a>(
|
||||
&mut self,
|
||||
storage: &'a hub::Storage<Buffer<A>, BufferId>,
|
||||
storage: &'a storage::Storage<Buffer<A>, BufferId>,
|
||||
id: BufferId,
|
||||
state: BufferUses,
|
||||
) -> 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.
|
||||
pub fn merge_single<'a>(
|
||||
&mut self,
|
||||
storage: &'a hub::Storage<Buffer<A>, BufferId>,
|
||||
storage: &'a storage::Storage<Buffer<A>, BufferId>,
|
||||
id: BufferId,
|
||||
new_state: BufferUses,
|
||||
) -> 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.
|
||||
pub fn set_single<'a>(
|
||||
&mut self,
|
||||
storage: &'a hub::Storage<Buffer<A>, BufferId>,
|
||||
storage: &'a storage::Storage<Buffer<A>, BufferId>,
|
||||
id: BufferId,
|
||||
state: BufferUses,
|
||||
) -> Option<(&'a Buffer<A>, Option<PendingTransition<BufferUses>>)> {
|
||||
|
@ -102,9 +102,8 @@ mod texture;
|
||||
use crate::{
|
||||
binding_model, command, conv,
|
||||
hal_api::HalApi,
|
||||
hub,
|
||||
id::{self, TypedId},
|
||||
pipeline, resource,
|
||||
pipeline, resource, storage,
|
||||
};
|
||||
|
||||
use std::{fmt, ops};
|
||||
@ -358,11 +357,11 @@ pub(crate) struct RenderBundleScope<A: HalApi> {
|
||||
impl<A: HalApi> RenderBundleScope<A> {
|
||||
/// Create the render bundle scope and pull the maximum IDs from the hubs.
|
||||
pub fn new(
|
||||
buffers: &hub::Storage<resource::Buffer<A>, id::BufferId>,
|
||||
textures: &hub::Storage<resource::Texture<A>, id::TextureId>,
|
||||
bind_groups: &hub::Storage<binding_model::BindGroup<A>, id::BindGroupId>,
|
||||
render_pipelines: &hub::Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>,
|
||||
query_sets: &hub::Storage<resource::QuerySet<A>, id::QuerySetId>,
|
||||
buffers: &storage::Storage<resource::Buffer<A>, id::BufferId>,
|
||||
textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
|
||||
bind_groups: &storage::Storage<binding_model::BindGroup<A>, id::BindGroupId>,
|
||||
render_pipelines: &storage::Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>,
|
||||
query_sets: &storage::Storage<resource::QuerySet<A>, id::QuerySetId>,
|
||||
) -> Self {
|
||||
let mut value = Self {
|
||||
buffers: BufferUsageScope::new(),
|
||||
@ -392,7 +391,7 @@ impl<A: HalApi> RenderBundleScope<A> {
|
||||
/// length of the storage given at the call to `new`.
|
||||
pub unsafe fn merge_bind_group(
|
||||
&mut self,
|
||||
textures: &hub::Storage<resource::Texture<A>, id::TextureId>,
|
||||
textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
|
||||
bind_group: &BindGroupStates<A>,
|
||||
) -> Result<(), UsageConflict> {
|
||||
unsafe { self.buffers.merge_bind_group(&bind_group.buffers)? };
|
||||
@ -416,8 +415,8 @@ pub(crate) struct UsageScope<A: HalApi> {
|
||||
impl<A: HalApi> UsageScope<A> {
|
||||
/// Create the render bundle scope and pull the maximum IDs from the hubs.
|
||||
pub fn new(
|
||||
buffers: &hub::Storage<resource::Buffer<A>, id::BufferId>,
|
||||
textures: &hub::Storage<resource::Texture<A>, id::TextureId>,
|
||||
buffers: &storage::Storage<resource::Buffer<A>, id::BufferId>,
|
||||
textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
|
||||
) -> Self {
|
||||
let mut value = Self {
|
||||
buffers: BufferUsageScope::new(),
|
||||
@ -441,7 +440,7 @@ impl<A: HalApi> UsageScope<A> {
|
||||
/// length of the storage given at the call to `new`.
|
||||
pub unsafe fn merge_bind_group(
|
||||
&mut self,
|
||||
textures: &hub::Storage<resource::Texture<A>, id::TextureId>,
|
||||
textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
|
||||
bind_group: &BindGroupStates<A>,
|
||||
) -> Result<(), UsageConflict> {
|
||||
unsafe {
|
||||
@ -464,7 +463,7 @@ impl<A: HalApi> UsageScope<A> {
|
||||
/// length of the storage given at the call to `new`.
|
||||
pub unsafe fn merge_render_bundle(
|
||||
&mut self,
|
||||
textures: &hub::Storage<resource::Texture<A>, id::TextureId>,
|
||||
textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
|
||||
render_bundle: &RenderBundleScope<A>,
|
||||
) -> Result<(), UsageConflict> {
|
||||
self.buffers.merge_usage_scope(&render_bundle.buffers)?;
|
||||
@ -506,17 +505,19 @@ impl<A: HalApi> Tracker<A> {
|
||||
/// Pull the maximum IDs from the hubs.
|
||||
pub fn set_size(
|
||||
&mut self,
|
||||
buffers: Option<&hub::Storage<resource::Buffer<A>, id::BufferId>>,
|
||||
textures: Option<&hub::Storage<resource::Texture<A>, id::TextureId>>,
|
||||
views: Option<&hub::Storage<resource::TextureView<A>, id::TextureViewId>>,
|
||||
samplers: Option<&hub::Storage<resource::Sampler<A>, id::SamplerId>>,
|
||||
bind_groups: Option<&hub::Storage<binding_model::BindGroup<A>, id::BindGroupId>>,
|
||||
buffers: Option<&storage::Storage<resource::Buffer<A>, id::BufferId>>,
|
||||
textures: Option<&storage::Storage<resource::Texture<A>, id::TextureId>>,
|
||||
views: Option<&storage::Storage<resource::TextureView<A>, id::TextureViewId>>,
|
||||
samplers: Option<&storage::Storage<resource::Sampler<A>, id::SamplerId>>,
|
||||
bind_groups: Option<&storage::Storage<binding_model::BindGroup<A>, id::BindGroupId>>,
|
||||
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>>,
|
||||
bundles: Option<&hub::Storage<command::RenderBundle<A>, id::RenderBundleId>>,
|
||||
query_sets: Option<&hub::Storage<resource::QuerySet<A>, id::QuerySetId>>,
|
||||
render_pipelines: Option<
|
||||
&storage::Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>,
|
||||
>,
|
||||
bundles: Option<&storage::Storage<command::RenderBundle<A>, id::RenderBundleId>>,
|
||||
query_sets: Option<&storage::Storage<resource::QuerySet<A>, id::QuerySetId>>,
|
||||
) {
|
||||
if let Some(buffers) = buffers {
|
||||
self.buffers.set_size(buffers.len());
|
||||
@ -571,7 +572,7 @@ impl<A: HalApi> Tracker<A> {
|
||||
/// value given to `set_size`
|
||||
pub unsafe fn set_and_remove_from_usage_scope_sparse(
|
||||
&mut self,
|
||||
textures: &hub::Storage<resource::Texture<A>, id::TextureId>,
|
||||
textures: &storage::Storage<resource::Texture<A>, id::TextureId>,
|
||||
scope: &mut UsageScope<A>,
|
||||
bind_group: &BindGroupStates<A>,
|
||||
) {
|
||||
|
@ -10,6 +10,7 @@ use crate::{
|
||||
hal_api::HalApi,
|
||||
hub,
|
||||
id::{TypedId, Valid},
|
||||
storage,
|
||||
track::ResourceMetadata,
|
||||
RefCount,
|
||||
};
|
||||
@ -45,7 +46,11 @@ impl<T: hub::Resource, Id: TypedId> StatelessBindGroupSate<T, Id> {
|
||||
}
|
||||
|
||||
/// 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()?;
|
||||
|
||||
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,
|
||||
/// 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 (index32, epoch, _) = id.unzip();
|
||||
|
@ -22,9 +22,9 @@
|
||||
use super::{range::RangedStates, PendingTransition};
|
||||
use crate::{
|
||||
hal_api::HalApi,
|
||||
hub,
|
||||
id::{TextureId, TypedId, Valid},
|
||||
resource::Texture,
|
||||
storage,
|
||||
track::{
|
||||
invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider,
|
||||
ResourceUses, UsageConflict,
|
||||
@ -185,7 +185,7 @@ impl<A: HalApi> TextureBindGroupState<A> {
|
||||
/// Adds the given resource with the given state.
|
||||
pub fn add_single<'a>(
|
||||
&mut self,
|
||||
storage: &'a hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &'a storage::Storage<Texture<A>, TextureId>,
|
||||
id: TextureId,
|
||||
ref_count: RefCount,
|
||||
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.
|
||||
pub fn merge_usage_scope(
|
||||
&mut self,
|
||||
storage: &hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &storage::Storage<Texture<A>, TextureId>,
|
||||
scope: &Self,
|
||||
) -> Result<(), UsageConflict> {
|
||||
let incoming_size = scope.set.simple.len();
|
||||
@ -326,7 +326,7 @@ impl<A: HalApi> TextureUsageScope<A> {
|
||||
/// method is called.
|
||||
pub unsafe fn merge_bind_group(
|
||||
&mut self,
|
||||
storage: &hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &storage::Storage<Texture<A>, TextureId>,
|
||||
bind_group: &TextureBindGroupState<A>,
|
||||
) -> Result<(), UsageConflict> {
|
||||
for &(id, ref selector, ref ref_count, state) in &bind_group.textures {
|
||||
@ -351,7 +351,7 @@ impl<A: HalApi> TextureUsageScope<A> {
|
||||
/// method is called.
|
||||
pub unsafe fn merge_single(
|
||||
&mut self,
|
||||
storage: &hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &storage::Storage<Texture<A>, TextureId>,
|
||||
id: Valid<TextureId>,
|
||||
selector: Option<TextureSelector>,
|
||||
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.
|
||||
pub fn set_from_tracker(
|
||||
&mut self,
|
||||
storage: &hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &storage::Storage<Texture<A>, TextureId>,
|
||||
tracker: &Self,
|
||||
) {
|
||||
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.
|
||||
pub fn set_from_usage_scope(
|
||||
&mut self,
|
||||
storage: &hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &storage::Storage<Texture<A>, TextureId>,
|
||||
scope: &TextureUsageScope<A>,
|
||||
) {
|
||||
let incoming_size = scope.set.simple.len();
|
||||
@ -662,7 +662,7 @@ impl<A: HalApi> TextureTracker<A> {
|
||||
/// method is called.
|
||||
pub unsafe fn set_and_remove_from_usage_scope_sparse(
|
||||
&mut self,
|
||||
storage: &hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &storage::Storage<Texture<A>, TextureId>,
|
||||
scope: &mut TextureUsageScope<A>,
|
||||
bind_group_state: &TextureBindGroupState<A>,
|
||||
) {
|
||||
@ -877,7 +877,7 @@ impl<'a> TextureStateProvider<'a> {
|
||||
/// out of the texture storage.
|
||||
#[inline(always)]
|
||||
unsafe fn texture_data_from_texture<A: HalApi>(
|
||||
storage: &hub::Storage<Texture<A>, TextureId>,
|
||||
storage: &storage::Storage<Texture<A>, TextureId>,
|
||||
index32: u32,
|
||||
) -> (&LifeGuard, &TextureSelector) {
|
||||
let texture = unsafe { storage.get_unchecked(index32) };
|
||||
|
Loading…
Reference in New Issue
Block a user