open_cl_low_level/
work.rs

1// use std::marker::PhantomData;
2use crate::{Dims, Error, Output};
3
4#[derive(Debug, Fail, Clone, Eq, PartialEq)]
5pub enum WorkError {
6    #[fail(display = "Work does not allow a zero value for any of its specified dimenions")]
7    DimLengthCannotBeZero,
8
9    #[fail(display = "Work dimensions must be 1, 2, or 3.")]
10    InvalidDimsCount,
11
12    #[fail(display = "Work size dimensions cannot have any zero values")]
13    InvalidWorkSize,
14}
15
16const INVALID_WORK_SIZE: Error = Error::WorkError(WorkError::InvalidWorkSize);
17
18/// WorkSize is the general, non-zero sized 3D array.
19#[derive(Debug, PartialEq, Eq, Clone)]
20pub struct NonZeroVolume3DArray([usize; 3]);
21
22impl NonZeroVolume3DArray {
23    fn as_ptr(&self) -> *const usize {
24        self.0.as_ptr()
25    }
26}
27
28impl NonZeroVolume3DArray {
29    fn from_dims(d: &Dims) -> Output<NonZeroVolume3DArray> {
30        let work_size: [usize; 3] = match d {
31            Dims::One(x) => [*x, 1, 1],
32            Dims::Two(x, y) => [*x, *y, 1],
33            Dims::Three(x, y, z) => [*x, *y, *z],
34        };
35        match work_size {
36            [0, _, _] | [_, 0, _] | [_, _, 0] => Err(INVALID_WORK_SIZE),
37            w => Ok(NonZeroVolume3DArray(w)),
38        }
39    }
40}
41
42#[derive(Debug, PartialEq, Eq, Clone)]
43pub struct GlobalWorkSize(NonZeroVolume3DArray);
44
45impl GlobalWorkSize {
46    pub fn from_dims(dims: &Dims) -> Output<GlobalWorkSize> {
47        let arr = NonZeroVolume3DArray::from_dims(dims)?;
48        Ok(GlobalWorkSize(arr))
49    }
50
51    pub fn as_ptr(&self) -> *const usize {
52        self.0.as_ptr()
53    }
54}
55
56#[derive(Debug, PartialEq, Eq, Clone)]
57pub enum LocalWorkSize {
58    WorkSize(NonZeroVolume3DArray),
59    Null,
60}
61
62impl LocalWorkSize {
63    pub fn from_dims(dims: &Dims) -> Output<LocalWorkSize> {
64        let arr = NonZeroVolume3DArray::from_dims(dims)?;
65        Ok(LocalWorkSize::WorkSize(arr))
66    }
67
68    pub fn as_ptr(&self) -> *const usize {
69        match self {
70            LocalWorkSize::WorkSize(arr) => arr.as_ptr(),
71            LocalWorkSize::Null => std::ptr::null::<usize>(),
72        }
73    }
74}
75
76#[derive(Debug, PartialEq, Eq, Clone)]
77pub enum GlobalWorkOffset {
78    Offset([usize; 3]),
79    Null,
80}
81
82impl GlobalWorkOffset {
83    pub fn from_dims(d: &Dims) -> GlobalWorkOffset {
84        let work_offset: [usize; 3] = match d {
85            Dims::One(x) => [*x, 0, 0],
86            Dims::Two(x, y) => [*x, *y, 0],
87            Dims::Three(x, y, z) => [*x, *y, *z],
88        };
89        GlobalWorkOffset::Offset(work_offset)
90    }
91
92    pub fn as_ptr(&self) -> *const usize {
93        match self {
94            GlobalWorkOffset::Offset(arr) => arr.as_ptr(),
95            GlobalWorkOffset::Null => std::ptr::null::<usize>(),
96        }
97    }
98}
99
100/// Work is a representation of 1, 2, or 3 dimensions.
101///
102/// For global_size none of the specified dimensions can be 0.
103///
104/// For global_offset any specficied dimension can be any usize.
105///
106/// For local_size none of the specified dimensions can be 0.
107#[derive(Debug, Clone, Eq, PartialEq)]
108pub struct Work {
109    pub global_size: Dims,
110    pub global_offset: Option<Dims>,
111    pub local_size: Option<Dims>,
112}
113
114impl Work {
115    pub fn new<D: Into<Dims>>(global_size: D) -> Work {
116        Work {
117            global_size: global_size.into(),
118            global_offset: None,
119            local_size: None,
120        }
121    }
122
123    pub fn with_global_offset<D: Into<Dims>>(mut self, offset: D) -> Work {
124        self.global_offset = Some(offset.into());
125        self
126    }
127
128    pub fn with_local_size<D: Into<Dims>>(mut self, local_size: D) -> Work {
129        self.local_size = Some(local_size.into());
130        self
131    }
132
133    pub fn work_dims(&self) -> u32 {
134        self.global_size.n_dimensions() as u32
135    }
136
137    /// A 3D array that describes the Volume of the Work.
138    /// A Work's global_work_size must describe a non-zero Volume.
139    /// For example, `[4, 3, 2]` is a 4 by 3 by 2 Volume that does not
140    /// result in an empty volume (4 * 3 * 2 != 0); to drive this point
141    /// home the Volume `[3, 3, 0]` is not a valid global_work_size because
142    /// the product of its elements equal 0.
143    pub fn global_work_size(&self) -> Output<GlobalWorkSize> {
144        GlobalWorkSize::from_dims(&self.global_size)
145    }
146
147    /// A 3D array that describes the 3 dimensional offset of the Work.
148    /// The `global_work_size` can be `None` or can be specified as a `Dims`.
149    /// Because the `global_work_offset` describes an of a 3 dimensional
150    /// collection/buffer the dimensionality of the data can be zero.
151    /// `Some([0, 0, 0])` is a valid `global_work_offset`.
152    pub fn global_work_offset(&self) -> GlobalWorkOffset {
153        match &self.global_offset {
154            Some(dims) => GlobalWorkOffset::from_dims(dims),
155            None => GlobalWorkOffset::Null,
156        }
157    }
158
159    pub fn local_work_size(&self) -> Output<LocalWorkSize> {
160        match &self.local_size {
161            Some(dims) => LocalWorkSize::from_dims(dims),
162            None => Ok(LocalWorkSize::Null),
163        }
164    }
165
166    pub fn n_items(&self) -> usize {
167        self.global_size.n_items()
168    }
169}