use std::marker::PhantomData;
use crate::{KernelSignature, LaunchConfig, Result, Stream, TypedKernel};
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub enum CaptureMode {
Global,
#[default]
ThreadLocal,
Relaxed,
}
impl CaptureMode {
const fn native(self) -> mircuda_sys::CaptureMode {
match self {
Self::Global => mircuda_sys::CaptureMode::Global,
Self::ThreadLocal => mircuda_sys::CaptureMode::ThreadLocal,
Self::Relaxed => mircuda_sys::CaptureMode::Relaxed,
}
}
}
#[derive(Debug)]
pub struct Graph<Resources> {
native: mircuda_sys::Graph,
resources: Resources,
}
#[derive(Debug)]
pub struct KernelNode<Signature: KernelSignature> {
native: mircuda_sys::KernelNode,
signature: PhantomData<Signature>,
}
impl<Signature: KernelSignature> Clone for KernelNode<Signature> {
fn clone(&self) -> Self {
*self
}
}
impl<Signature: KernelSignature> Copy for KernelNode<Signature> {}
impl<Signature: KernelSignature> KernelNode<Signature> {
pub(crate) const fn new(native: mircuda_sys::KernelNode) -> Self {
Self { native, signature: PhantomData }
}
}
impl Stream {
pub fn capture<Resources, CaptureError>(
&self,
resources: Resources,
operation: fn(&mut Resources) -> std::result::Result<(), CaptureError>,
) -> std::result::Result<Graph<Resources>, CaptureError>
where
CaptureError: From<crate::Error>,
{
self.capture_with(CaptureMode::ThreadLocal, resources, operation)
}
pub fn capture_with<Resources, CaptureError>(
&self,
mode: CaptureMode,
mut resources: Resources,
operation: fn(&mut Resources) -> std::result::Result<(), CaptureError>,
) -> std::result::Result<Graph<Resources>, CaptureError>
where
CaptureError: From<crate::Error>,
{
self.begin_capture(mode)?;
let operation_result = operation(&mut resources);
let graph_result = self.end_capture();
operation_result?;
Ok(Graph { native: graph_result?, resources })
}
fn begin_capture(&self, mode: CaptureMode) -> Result<()> {
Ok(self.native.begin_capture(mode.native())?)
}
fn end_capture(&self) -> Result<mircuda_sys::Graph> {
Ok(self.native.end_capture()?)
}
}
impl<Resources> Graph<Resources> {
pub fn launch(&mut self, stream: &Stream) -> Result<()> {
Ok(self.native.launch(&stream.native)?)
}
#[must_use]
pub const fn resources(&self) -> &Resources {
&self.resources
}
pub fn with_resources_mut<T>(&mut self, operation: impl FnOnce(&mut Resources) -> T) -> T {
operation(&mut self.resources)
}
#[must_use]
pub fn into_resources(self) -> Resources {
let Self { native: _native, resources } = self;
resources
}
pub fn kernel_nodes<Signature: KernelSignature>(
&self,
kernel: &TypedKernel<Signature>,
) -> Result<Vec<KernelNode<Signature>>> {
Ok(self
.native
.kernel_nodes(kernel.native())?
.into_iter()
.map(KernelNode::new)
.collect())
}
pub fn update_kernel<Signature, Arguments>(
&mut self,
node: &KernelNode<Signature>,
kernel: &TypedKernel<Signature>,
config: LaunchConfig,
arguments: Arguments,
) -> Result<()>
where
Signature: KernelSignature,
Arguments: for<'borrow> FnOnce(&'borrow mut Resources) -> Signature::Arguments<'borrow>,
{
let mut encoded = Signature::encode(arguments(&mut self.resources));
Ok(self.native.update_kernel(
node.native,
kernel.native(),
config.native(),
&mut encoded.native,
)?)
}
pub fn try_update_kernel<Signature, Arguments, UpdateError>(
&mut self,
node: &KernelNode<Signature>,
kernel: &TypedKernel<Signature>,
config: LaunchConfig,
arguments: Arguments,
) -> std::result::Result<(), UpdateError>
where
Signature: KernelSignature,
Arguments:
for<'borrow> FnOnce(
&'borrow mut Resources,
)
-> std::result::Result<Signature::Arguments<'borrow>, UpdateError>,
UpdateError: From<crate::Error>,
{
let mut encoded = Signature::encode(arguments(&mut self.resources)?);
let update: crate::Result<()> = (|| {
self.native.update_kernel(
node.native,
kernel.native(),
config.native(),
&mut encoded.native,
)?;
Ok(())
})();
update?;
Ok(())
}
}