use glam::Vec3;
use super::{GpuAccumulate, GpuBackend, GpuBatchItem};
use crate::renderer::gpu::frame::BatchEvent;
pub(super) struct BatchOutput<'b, 'a> {
pub(super) items: &'b mut [GpuBatchItem<'a>],
pub(super) scratches: Vec<Vec<Vec3>>,
pub(super) on_done: &'b mut dyn FnMut(usize, GpuAccumulate),
pub(super) reported: usize,
}
impl BatchOutput<'_, '_> {
pub(super) fn report(&mut self, backend: &GpuBackend, index: usize, outcome: GpuAccumulate) {
debug_assert_eq!(
index, self.reported,
"batch outcomes must be reported in input order"
);
let scratch = std::mem::take(&mut self.scratches[index]);
if outcome == GpuAccumulate::Done {
for (total, traced) in self.items[index].out.iter_mut().zip(&scratch) {
*total += *traced;
}
}
backend.return_scratch(scratch);
self.reported = index + 1;
(self.on_done)(index, outcome);
}
pub(super) fn deliver(&mut self, backend: &GpuBackend, event: BatchEvent) {
match event {
BatchEvent::Done(index) => self.report(backend, index, GpuAccumulate::Done),
BatchEvent::Declined(index) => self.report(backend, index, GpuAccumulate::Declined),
BatchEvent::Cancelled(first) => {
for index in first..self.items.len() {
self.report(backend, index, GpuAccumulate::Cancelled);
}
}
}
}
pub(super) fn finish_rest(&mut self, backend: &GpuBackend, outcome: GpuAccumulate) {
for index in self.reported..self.items.len() {
self.report(backend, index, outcome);
}
}
}