use crate::{Backend, BackendGraph, StreamId};
pub struct CapturedGraph<B: Backend, T, F> {
device: B::Device,
stream: StreamId,
output: T,
closure: F,
hardware: Option<BackendGraph>,
}
struct CaptureGuard<'a, B: Backend> {
device: &'a B::Device,
stream: StreamId,
active: bool,
}
impl<B: Backend> Drop for CaptureGuard<'_, B> {
fn drop(&mut self) {
if self.active { self.stream.executes(|| B::graph_abort_capture(self.device)); }
}
}
pub fn capture<B: Backend, T, F: FnMut() -> T>(device: &B::Device, mut closure: F) -> CapturedGraph<B, T, F> {
let stream = StreamId::current();
let prepared = stream.executes(|| B::graph_prepare(device)).is_ok();
let mut guard = CaptureGuard::<B> { device, stream, active: prepared };
for _ in 0..3 {
let output = stream.executes(&mut closure);
let _ = stream.executes(|| B::sync(device));
drop(output);
}
let (hardware, output) = if !prepared {
(None, stream.executes(&mut closure))
} else { match stream.executes(|| B::graph_start_capture(device)) {
Ok(()) => {
let output = stream.executes(&mut closure);
let hardware = stream.executes(|| B::graph_stop_capture(device)).ok();
if hardware.is_none() { stream.executes(|| B::graph_abort_capture(device)); }
guard.active = false;
(hardware, output)
}
Err(_) => {
stream.executes(|| B::graph_abort_capture(device));
guard.active = false;
(None, stream.executes(&mut closure))
}
} };
CapturedGraph { device: device.clone(), stream, output, closure, hardware }
}
impl<B: Backend, T, F: FnMut() -> T> CapturedGraph<B, T, F> {
pub unsafe fn replay(&mut self) -> &T {
self.stream.executes(|| match &self.hardware {
Some(graph) => unsafe { B::graph_replay(&self.device, graph) }.expect("Graph replay failed"),
None => self.output = (self.closure)(),
});
&self.output
}
pub fn output(&self) -> &T { &self.output }
pub fn is_hardware(&self) -> bool { self.hardware.is_some() }
}