use std::collections::BTreeMap;
use crate::{ImageLoad, ImageQuery, ImageSample, Load, Sample, Sampler};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BufferExtent {
pub stride: u32,
pub elements: u32,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct BufferRead {
pub slot: u32,
pub element: u32,
pub offset: u32,
}
#[derive(Debug)]
pub struct AnsweredBuffers<S, F> {
pub images: S,
pub answer: F,
extents: BTreeMap<u32, BufferExtent>,
pub reads: Vec<(BufferRead, u32)>,
pub queries: Vec<(u32, Option<u32>)>,
}
impl<S, F> AnsweredBuffers<S, F> {
pub fn new(images: S, extents: BTreeMap<u32, BufferExtent>, answer: F) -> Result<Self, String> {
for (&slot, extent) in &extents {
if extent.stride == 0 || !extent.stride.is_multiple_of(4) {
return Err(format!(
"t{slot}: structured stride {} is not a positive word multiple",
extent.stride
));
}
if u64::from(extent.stride / 4).saturating_mul(u64::from(extent.elements)) > u64::from(u32::MAX) {
return Err(format!(
"t{slot}: structured extent exceeds the executor's word address range"
));
}
}
Ok(Self {
images,
answer,
extents,
reads: Vec::new(),
queries: Vec::new(),
})
}
}
impl<S: Sampler, F: FnMut(BufferRead) -> Result<u32, String>> Sampler for AnsweredBuffers<S, F> {
fn sample(&mut self, request: Sample) -> Result<[f32; 4], String> {
self.images.sample(request)
}
fn load(&mut self, request: Load) -> Result<[u32; 4], String> {
self.images.load(request)
}
fn sample_image(&mut self, request: ImageSample<u32>) -> Result<[f32; 4], String> {
self.images.sample_image(request)
}
fn load_image(&mut self, request: ImageLoad<u32>) -> Result<[u32; 4], String> {
self.images.load_image(request)
}
fn query_image(&mut self, request: ImageQuery<u32>) -> Result<[u32; 4], String> {
self.images.query_image(request)
}
fn structured(&mut self, slot: u32, element: u32, offset: u32) -> Result<u32, String> {
let extent = self
.extents
.get(&slot)
.ok_or_else(|| format!("t{slot}: no structured extent stated"))?;
if !offset.is_multiple_of(4) || u64::from(offset) + 4 > u64::from(extent.stride) {
return Err(format!(
"t{slot}: structured byte offset {offset} outside word-aligned stride {}",
extent.stride
));
}
let request = BufferRead {
slot,
element,
offset,
};
let value = if element >= extent.elements {
0
} else {
(self.answer)(request)
.map_err(|why| format!("t{slot}: element {element} byte {offset}: {why}"))?
};
self.reads.push((request, value));
Ok(value)
}
fn buffer_elements(&mut self, slot: u32) -> Option<u32> {
let elements = self.extents.get(&slot).map(|e| e.elements);
self.queries.push((slot, elements));
elements
}
}
#[cfg(test)]
#[path = "buffers_tests.rs"]
mod tests;