use std::marker::PhantomData;
use crate::{
hub,
id::{TypedId, Valid},
track::ResourceMetadata,
RefCount,
};
pub(crate) struct StatelessBindGroupSate<T, Id: TypedId> {
resources: Vec<(Valid<Id>, RefCount)>,
_phantom: PhantomData<T>,
}
impl<T: hub::Resource, Id: TypedId> StatelessBindGroupSate<T, Id> {
pub fn new() -> Self {
Self {
resources: Vec::new(),
_phantom: PhantomData,
}
}
pub(crate) fn optimize(&mut self) {
self.resources
.sort_unstable_by_key(|&(id, _)| id.0.unzip().0);
}
pub fn used(&self) -> impl Iterator<Item = Valid<Id>> + '_ {
self.resources.iter().map(|&(id, _)| id)
}
pub fn add_single<'a>(&mut self, storage: &'a hub::Storage<T, Id>, id: Id) -> Option<&'a T> {
let resource = storage.get(id).ok()?;
self.resources
.push((Valid(id), resource.life_guard().add_ref()));
Some(resource)
}
}
pub(crate) struct StatelessTracker<A: hub::HalApi, T, Id: TypedId> {
metadata: ResourceMetadata<A>,
_phantom: PhantomData<(T, Id)>,
}
impl<A: hub::HalApi, T: hub::Resource, Id: TypedId> StatelessTracker<A, T, Id> {
pub fn new() -> Self {
Self {
metadata: ResourceMetadata::new(),
_phantom: PhantomData,
}
}
fn tracker_assert_in_bounds(&self, index: usize) {
self.metadata.tracker_assert_in_bounds(index);
}
pub fn set_size(&mut self, size: usize) {
self.metadata.set_size(size);
}
fn allow_index(&mut self, index: usize) {
if index >= self.metadata.size() {
self.set_size(index + 1);
}
}
pub fn used(&self) -> impl Iterator<Item = Valid<Id>> + '_ {
self.metadata.owned_ids()
}
pub fn insert_single(&mut self, id: Valid<Id>, ref_count: RefCount) {
let (index32, epoch, _) = id.0.unzip();
let index = index32 as usize;
self.allow_index(index);
self.tracker_assert_in_bounds(index);
unsafe {
self.metadata.insert(index, epoch, ref_count);
}
}
pub fn add_single<'a>(&mut self, storage: &'a hub::Storage<T, Id>, id: Id) -> Option<&'a T> {
let item = storage.get(id).ok()?;
let (index32, epoch, _) = id.unzip();
let index = index32 as usize;
self.allow_index(index);
self.tracker_assert_in_bounds(index);
unsafe {
self.metadata
.insert(index, epoch, item.life_guard().add_ref());
}
Some(item)
}
pub fn add_from_tracker(&mut self, other: &Self) {
let incoming_size = other.metadata.size();
if incoming_size > self.metadata.size() {
self.set_size(incoming_size);
}
for index in other.metadata.owned_indices() {
self.tracker_assert_in_bounds(index);
other.tracker_assert_in_bounds(index);
unsafe {
let previously_owned = self.metadata.contains_unchecked(index);
if !previously_owned {
let epoch = other.metadata.get_epoch_unchecked(index);
let other_ref_count = other.metadata.get_ref_count_unchecked(index);
self.metadata.insert(index, epoch, other_ref_count.clone());
}
}
}
}
pub fn remove_abandoned(&mut self, id: Valid<Id>) -> bool {
let (index32, epoch, _) = id.0.unzip();
let index = index32 as usize;
if index > self.metadata.size() {
return false;
}
self.tracker_assert_in_bounds(index);
unsafe {
if self.metadata.contains_unchecked(index) {
let existing_epoch = self.metadata.get_epoch_unchecked(index);
let existing_ref_count = self.metadata.get_ref_count_unchecked(index);
if existing_epoch == epoch && existing_ref_count.load() == 1 {
self.metadata.remove(index);
return true;
}
}
}
false
}
}