use crate::DecodeError;
use windows::Win32::Graphics::Direct3D12::ID3D12Resource;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum SlotState {
Free,
Occupied,
}
struct Slot<M> {
state: SlotState,
handle_outstanding: bool,
is_reference: bool,
meta: Option<M>,
}
impl<M> Default for Slot<M> {
fn default() -> Self {
Self {
state: SlotState::Free,
handle_outstanding: false,
is_reference: false,
meta: None,
}
}
}
pub(super) struct SlotTable<M> {
slots: Vec<Slot<M>>,
}
impl<M: Copy> SlotTable<M> {
pub(super) fn new(num_slots: u32) -> Self {
let mut slots = Vec::with_capacity(num_slots as usize);
slots.resize_with(num_slots as usize, Slot::default);
Self { slots }
}
pub(super) fn num_slots(&self) -> u32 {
u32::try_from(self.slots.len()).unwrap_or(0)
}
pub(super) fn acquire_free_slot(&mut self) -> Result<u32, DecodeError> {
let index = self
.slots
.iter()
.position(|s| s.state == SlotState::Free)
.ok_or(DecodeError::Backend)?;
self.slots[index].state = SlotState::Occupied;
Ok(u32::try_from(index).unwrap_or(0))
}
pub(super) fn evict(&mut self, index: u32) -> Result<(), DecodeError> {
let slot = self
.slots
.get_mut(index as usize)
.ok_or(DecodeError::Backend)?;
if slot.handle_outstanding {
return Err(DecodeError::Backend);
}
slot.state = SlotState::Free;
slot.is_reference = false;
slot.meta = None;
Ok(())
}
pub(super) fn mark_reference(&mut self, index: u32, meta: M) {
if let Some(slot) = self.slots.get_mut(index as usize) {
slot.is_reference = true;
slot.meta = Some(meta);
}
}
pub(super) fn release_if_unused(&mut self, index: u32) {
if let Some(slot) = self.slots.get_mut(index as usize) {
if !slot.is_reference && !slot.handle_outstanding {
slot.state = SlotState::Free;
}
}
}
pub(super) fn mark_handle_outstanding(&mut self, index: u32) {
if let Some(slot) = self.slots.get_mut(index as usize) {
slot.handle_outstanding = true;
}
}
pub(super) fn release_handle(&mut self, index: u32) {
if let Some(slot) = self.slots.get_mut(index as usize) {
slot.handle_outstanding = false;
if !slot.is_reference {
slot.state = SlotState::Free;
}
}
}
pub(super) fn is_free(&self, index: u32) -> bool {
self.slots
.get(index as usize)
.is_some_and(|s| s.state == SlotState::Free)
}
pub(super) fn references(&self) -> Vec<(u32, M)> {
self.slots
.iter()
.enumerate()
.filter_map(|(i, s)| {
if s.is_reference {
s.meta.map(|m| (u32::try_from(i).unwrap_or(0), m))
} else {
None
}
})
.collect()
}
}
pub(super) struct DpbPool<M> {
texture: ID3D12Resource,
table: SlotTable<M>,
}
impl<M: Copy> DpbPool<M> {
pub(super) fn new(texture: ID3D12Resource, num_slots: u32) -> Self {
Self {
texture,
table: SlotTable::new(num_slots),
}
}
pub(super) const fn texture(&self) -> &ID3D12Resource {
&self.texture
}
pub(super) const fn table(&self) -> &SlotTable<M> {
&self.table
}
pub(super) const fn table_mut(&mut self) -> &mut SlotTable<M> {
&mut self.table
}
}
#[cfg(test)]
#[path = "dpb_tests.rs"]
mod tests;