Skip to main content

iridia_exec/
stage.rs

1//! What the stages that run a function at a time (geometry, hull and domain programs) share: how a program's resources
2//! are found in the caller's bindings.
3
4use std::collections::BTreeMap;
5
6use super::pixel::SlotBackend;
7use super::{Bound, Executable};
8use crate::Sampler;
9use iridia::{BufferKind, D3dClass, Program, ResourceId, ResourceKind, StorageTarget};
10
11/// The rows of constant buffers, by (register, space).
12pub type Constants = BTreeMap<(u32, u32), Vec<[u32; 4]>>;
13
14/// Where the resources of a program are bound.
15#[derive(Debug)]
16pub(super) struct Bindings {
17    /// The constant buffers by resource, as (register, space).
18    constants: BTreeMap<ResourceId, (u32, u32)>,
19    slots: BTreeMap<ResourceId, u32>,
20    buffers: BTreeMap<ResourceId, BufferKind>,
21}
22
23impl Bindings {
24    pub(super) fn new(program: &Program) -> Result<Self, String> {
25        let mut constants = BTreeMap::new();
26        let mut slots = BTreeMap::new();
27        let mut buffers = BTreeMap::new();
28        for r in &program.interface.resources {
29            let Some(binding) = r.provenance.d3d else {
30                return Err(format!("resource {} has no D3D bind slot", r.provenance.name));
31            };
32            slots.insert(r.id, binding.register);
33            if matches!(r.kind, ResourceKind::ConstantBuffer { .. })
34                && binding.class == D3dClass::ConstantBuffer
35            {
36                constants.insert(r.id, (binding.register, binding.space));
37            }
38            if let ResourceKind::Buffer(kind)
39            | ResourceKind::Storage {
40                target: StorageTarget::Buffer(kind),
41                ..
42            } = &r.kind
43            {
44                buffers.insert(r.id, *kind);
45            }
46        }
47        Ok(Self {
48            constants,
49            slots,
50            buffers,
51        })
52    }
53
54    /// The buffers `executable` reads, from the caller's `constants`.
55    pub(super) fn bind<'a>(
56        &self,
57        executable: &Executable,
58        constants: &'a Constants,
59    ) -> Result<Bound<'a>, String> {
60        executable.bind(
61            |id| {
62                let key = self.constants.get(&id)?;
63                constants.get(key).map(Vec::as_slice)
64            },
65            |_| None,
66        )
67    }
68
69    /// The program's requests in the sampler's vocabulary: bind slots.
70    pub(super) fn backend<'a>(&'a self, sampler: &'a mut dyn Sampler) -> SlotBackend<'a> {
71        SlotBackend {
72            sampler,
73            slots: &self.slots,
74            buffers: &self.buffers,
75        }
76    }
77}