use std::collections::BTreeMap;
use super::pixel::SlotBackend;
use super::{Bound, Executable};
use crate::Sampler;
use iridia::{BufferKind, D3dClass, Program, ResourceId, ResourceKind, StorageTarget};
pub type Constants = BTreeMap<(u32, u32), Vec<[u32; 4]>>;
#[derive(Debug)]
pub(super) struct Bindings {
constants: BTreeMap<ResourceId, (u32, u32)>,
slots: BTreeMap<ResourceId, u32>,
buffers: BTreeMap<ResourceId, BufferKind>,
}
impl Bindings {
pub(super) fn new(program: &Program) -> Result<Self, String> {
let mut constants = BTreeMap::new();
let mut slots = BTreeMap::new();
let mut buffers = BTreeMap::new();
for r in &program.interface.resources {
let Some(binding) = r.provenance.d3d else {
return Err(format!("resource {} has no D3D bind slot", r.provenance.name));
};
slots.insert(r.id, binding.register);
if matches!(r.kind, ResourceKind::ConstantBuffer { .. })
&& binding.class == D3dClass::ConstantBuffer
{
constants.insert(r.id, (binding.register, binding.space));
}
if let ResourceKind::Buffer(kind)
| ResourceKind::Storage {
target: StorageTarget::Buffer(kind),
..
} = &r.kind
{
buffers.insert(r.id, *kind);
}
}
Ok(Self {
constants,
slots,
buffers,
})
}
pub(super) fn bind<'a>(
&self,
executable: &Executable,
constants: &'a Constants,
) -> Result<Bound<'a>, String> {
executable.bind(
|id| {
let key = self.constants.get(&id)?;
constants.get(key).map(Vec::as_slice)
},
|_| None,
)
}
pub(super) fn backend<'a>(&'a self, sampler: &'a mut dyn Sampler) -> SlotBackend<'a> {
SlotBackend {
sampler,
slots: &self.slots,
buffers: &self.buffers,
}
}
}