iridia_exec/probe/
buffers.rs1use std::collections::BTreeMap;
3
4use crate::{ImageLoad, ImageQuery, ImageSample, Load, Sample, Sampler};
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub struct BufferExtent {
9 pub stride: u32,
11 pub elements: u32,
13}
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub struct BufferRead {
18 pub slot: u32,
20 pub element: u32,
22 pub offset: u32,
24}
25
26#[derive(Debug)]
38pub struct AnsweredBuffers<S, F> {
39 pub images: S,
41 pub answer: F,
43 extents: BTreeMap<u32, BufferExtent>,
44 pub reads: Vec<(BufferRead, u32)>,
46 pub queries: Vec<(u32, Option<u32>)>,
48}
49
50impl<S, F> AnsweredBuffers<S, F> {
51 pub fn new(images: S, extents: BTreeMap<u32, BufferExtent>, answer: F) -> Result<Self, String> {
54 for (&slot, extent) in &extents {
55 if extent.stride == 0 || !extent.stride.is_multiple_of(4) {
56 return Err(format!(
57 "t{slot}: structured stride {} is not a positive word multiple",
58 extent.stride
59 ));
60 }
61 if u64::from(extent.stride / 4).saturating_mul(u64::from(extent.elements)) > u64::from(u32::MAX) {
62 return Err(format!(
63 "t{slot}: structured extent exceeds the executor's word address range"
64 ));
65 }
66 }
67 Ok(Self {
68 images,
69 answer,
70 extents,
71 reads: Vec::new(),
72 queries: Vec::new(),
73 })
74 }
75}
76
77impl<S: Sampler, F: FnMut(BufferRead) -> Result<u32, String>> Sampler for AnsweredBuffers<S, F> {
78 fn sample(&mut self, request: Sample) -> Result<[f32; 4], String> {
79 self.images.sample(request)
80 }
81
82 fn load(&mut self, request: Load) -> Result<[u32; 4], String> {
83 self.images.load(request)
84 }
85
86 fn sample_image(&mut self, request: ImageSample<u32>) -> Result<[f32; 4], String> {
87 self.images.sample_image(request)
88 }
89
90 fn load_image(&mut self, request: ImageLoad<u32>) -> Result<[u32; 4], String> {
91 self.images.load_image(request)
92 }
93
94 fn query_image(&mut self, request: ImageQuery<u32>) -> Result<[u32; 4], String> {
95 self.images.query_image(request)
96 }
97
98 fn structured(&mut self, slot: u32, element: u32, offset: u32) -> Result<u32, String> {
99 let extent = self
100 .extents
101 .get(&slot)
102 .ok_or_else(|| format!("t{slot}: no structured extent stated"))?;
103 if !offset.is_multiple_of(4) || u64::from(offset) + 4 > u64::from(extent.stride) {
104 return Err(format!(
105 "t{slot}: structured byte offset {offset} outside word-aligned stride {}",
106 extent.stride
107 ));
108 }
109 let request = BufferRead {
110 slot,
111 element,
112 offset,
113 };
114 let value = if element >= extent.elements {
115 0
116 } else {
117 (self.answer)(request)
118 .map_err(|why| format!("t{slot}: element {element} byte {offset}: {why}"))?
119 };
120 self.reads.push((request, value));
121 Ok(value)
122 }
123
124 fn buffer_elements(&mut self, slot: u32) -> Option<u32> {
125 let elements = self.extents.get(&slot).map(|e| e.elements);
126 self.queries.push((slot, elements));
127 elements
128 }
129}
130
131#[cfg(test)]
132#[path = "buffers_tests.rs"]
133mod tests;