mod types;
use crate::program::Program;
use crate::raw::*;
use crate::util::sealed::OclInfoInternal;
use crate::Result;
use std::ffi::{c_void, CStr};
use std::fmt::{self, Debug, Formatter};
use std::pin::Pin;
pub use types::*;
#[derive(PartialEq, Eq, Hash)]
pub struct UnboundKernel(cl_kernel);
unsafe impl Send for UnboundKernel {}
#[derive(PartialEq, Eq, Hash)]
pub struct Kernel<T: KernelArgList> {
kernel: UnboundKernel,
args: T::Bound,
}
unsafe impl<T: KernelArgList> Send for Kernel<T> {}
impl Drop for UnboundKernel {
fn drop(&mut self) {
unsafe {
if let Err(e) = wrap_result!("clReleaseKernel" => clReleaseKernel(self.0)) {
log::warn!("Error releasing OpenCL kernel: {:?}: {:?}", self, e);
}
}
}
}
impl Debug for UnboundKernel {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.info_fmt(f)
}
}
impl<T: KernelArgList> Debug for Kernel<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
self.info_fmt(f)
}
}
impl OclInfoInternal for UnboundKernel {
type Param = cl_kernel_info;
const DEBUG_CONTEXT: &'static str = "clGetKernelInfo";
unsafe fn raw_info_internal(
&self,
param_name: Self::Param,
param_value_size: usize,
param_value: *mut c_void,
param_value_size_ret: *mut usize,
) -> i32 {
clGetKernelInfo(
self.0,
param_name,
param_value_size,
param_value,
param_value_size_ret,
)
}
}
impl<T: KernelArgList> OclInfoInternal for Kernel<T> {
type Param = <UnboundKernel as OclInfoInternal>::Param;
const DEBUG_CONTEXT: &'static str = UnboundKernel::DEBUG_CONTEXT;
unsafe fn raw_info_internal(
&self,
param_name: Self::Param,
param_value_size: usize,
param_value: *mut c_void,
param_value_size_ret: *mut usize,
) -> i32 {
self.kernel.raw_info_internal(
param_name,
param_value_size,
param_value,
param_value_size_ret,
)
}
}
impl KernelInfo for UnboundKernel {
fn as_unbound(&self) -> &UnboundKernel {
&self
}
}
impl<T: KernelArgList> KernelInfo for Kernel<T> {
fn as_unbound(&self) -> &UnboundKernel {
&self.kernel
}
}
impl UnboundKernel {
pub fn bind_arguments<T: KernelArgList>(self, arguments: T) -> Result<Kernel<T>> {
let required = self.num_args()? as usize;
let supplied = T::NUM_ARGS;
assert_eq!(
required, supplied,
"kernel arity mismatch - kernel requires {} arguments, but {} were specified",
required, supplied
);
arguments.bind(self, true)
}
pub fn bind_arguments_unchecked<T: KernelArgList>(self, arguments: T) -> Result<Kernel<T>> {
arguments.bind(self, false)
}
pub fn raw(&self) -> cl_kernel {
self.0
}
}
impl<T: KernelArgList> Kernel<T> {
pub fn arguments<'a>(&'a mut self) -> <T::Bound as BindProject<'a>>::Projected
where
T::Bound: BindProject<'a>,
{
unsafe {
use sealed::BindProjectInternal;
let bound: Pin<&'a mut T::Bound> = Pin::new_unchecked(&mut self.args);
BindProjectInternal::project(bound)
}
}
}
impl Program {
pub fn create_kernel(&self, name: &CStr) -> Result<UnboundKernel> {
unsafe {
let mut err = CL_SUCCESS;
let kernel = clCreateKernel(self.raw(), name.as_ptr(), &mut err as _);
wrap_result!("clCreateKernel" => err)?;
Ok(UnboundKernel(kernel))
}
}
}