use std::sync::Arc;
use crate::{
id::Id,
lock::{rank, Mutex},
resource::Resource,
resource_log,
storage::Storage,
track::ResourceMetadata,
};
use super::{ResourceTracker, TrackerIndex};
type Pair<T> = (Id<<T as Resource>::Marker>, Arc<T>);
#[derive(Debug)]
pub(crate) struct StatelessBindGroupSate<T: Resource> {
resources: Mutex<Vec<Pair<T>>>,
}
impl<T: Resource> StatelessBindGroupSate<T> {
pub fn new() -> Self {
Self {
resources: Mutex::new(rank::STATELESS_BIND_GROUP_STATE_RESOURCES, Vec::new()),
}
}
pub(crate) fn optimize(&self) {
let mut resources = self.resources.lock();
resources.sort_unstable_by_key(|&(id, _)| id.unzip().0);
}
pub fn used_resources(&self) -> impl Iterator<Item = Arc<T>> + '_ {
let resources = self.resources.lock();
resources
.iter()
.map(|(_, resource)| resource.clone())
.collect::<Vec<_>>()
.into_iter()
}
pub fn drain_resources(&self) -> impl Iterator<Item = Arc<T>> + '_ {
let mut resources = self.resources.lock();
resources
.drain(..)
.map(|(_, r)| r)
.collect::<Vec<_>>()
.into_iter()
}
pub fn add_single<'a>(&self, storage: &'a Storage<T>, id: Id<T::Marker>) -> Option<&'a T> {
let resource = storage.get(id).ok()?;
let mut resources = self.resources.lock();
resources.push((id, resource.clone()));
Some(resource)
}
}
#[derive(Debug)]
pub(crate) struct StatelessTracker<T: Resource> {
metadata: ResourceMetadata<T>,
}
impl<T: Resource> ResourceTracker for StatelessTracker<T> {
fn remove_abandoned(&mut self, index: TrackerIndex) -> bool {
let index = index.as_usize();
if index >= self.metadata.size() {
return false;
}
resource_log!("StatelessTracker::remove_abandoned {index:?}");
self.tracker_assert_in_bounds(index);
unsafe {
if self.metadata.contains_unchecked(index) {
let existing_ref_count = self.metadata.get_ref_count_unchecked(index);
if existing_ref_count <= 2 {
self.metadata.remove(index);
return true;
}
return false;
}
}
true
}
}
impl<T: Resource> StatelessTracker<T> {
pub fn new() -> Self {
Self {
metadata: ResourceMetadata::new(),
}
}
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_resources(&self) -> impl Iterator<Item = Arc<T>> + '_ {
self.metadata.owned_resources()
}
pub fn drain_resources(&mut self) -> impl Iterator<Item = Arc<T>> + '_ {
let resources = self.metadata.drain_resources();
resources.into_iter()
}
pub fn insert_single(&mut self, resource: Arc<T>) -> &Arc<T> {
let index = resource.as_info().tracker_index().as_usize();
self.allow_index(index);
self.tracker_assert_in_bounds(index);
unsafe { self.metadata.insert(index, resource) }
}
pub fn add_single<'a>(
&mut self,
storage: &'a Storage<T>,
id: Id<T::Marker>,
) -> Option<&'a Arc<T>> {
let resource = storage.get(id).ok()?;
let index = resource.as_info().tracker_index().as_usize();
self.allow_index(index);
self.tracker_assert_in_bounds(index);
unsafe {
self.metadata.insert(index, resource.clone());
}
Some(resource)
}
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 other_resource = other.metadata.get_resource_unchecked(index);
self.metadata.insert(index, other_resource.clone());
}
}
}
}
}