vdtfont/opencl/
image_view.rs

1use std::{convert, ops};
2
3use anyhow::Context;
4
5#[derive(Debug, Clone)]
6pub struct ImageView<T: ocl::OclPrm> {
7    ocl_image: ocl::Image<T>,
8
9    origin: Dims,
10    region: Dims,
11}
12
13impl<T: ocl::OclPrm> ImageView<T> {
14    pub fn new<D: convert::Into<Dims>>(
15        ocl_image: ocl::Image<T>,
16        origin: Option<D>,
17        region: Option<D>,
18    ) -> anyhow::Result<Self> {
19        let full_image_region: Dims = ocl_image.dims().into();
20
21        let origin: Dims = origin.map(D::into).unwrap_or([0; 3].into());
22        let region: Dims = region.map(D::into).unwrap_or(full_image_region);
23
24        if !is_region_suitable_for_image(&ocl_image, origin, region) {
25            anyhow::bail!(
26                "The given region {:?} which starts at the origin {:?}
27                exceeds the size of the full image {:?}",
28                region,
29                origin,
30                full_image_region
31            );
32        }
33
34        Ok(Self { ocl_image, origin, region })
35    }
36
37    pub fn ocl_image(&self) -> &ocl::Image<T> {
38        &self.ocl_image
39    }
40
41    pub fn origin(&self) -> Dims {
42        self.origin
43    }
44
45    pub fn region(&self) -> Dims {
46        self.region
47    }
48
49    pub fn set_origin<O: convert::Into<Dims>>(&mut self, origin: O) -> anyhow::Result<()> {
50        let origin: Dims = origin.into();
51
52        if !is_region_suitable_for_image(&self.ocl_image, origin, self.region) {
53            anyhow::bail!("The given origin {:?} isn't suitable for image", origin);
54        }
55
56        self.origin = origin;
57
58        Ok(())
59    }
60
61    pub fn set_region<R: convert::Into<Dims>>(&mut self, region: R) -> anyhow::Result<()> {
62        let region = region.into();
63
64        if !is_region_suitable_for_image(&self.ocl_image, self.origin, region) {
65            anyhow::bail!("The given region {:?} isn't suitable for image", region);
66        }
67
68        self.region = region;
69
70        Ok(())
71    }
72
73    pub fn read(&self, dst_data: &mut [T]) -> anyhow::Result<()> {
74        self.ocl_image
75            .cmd()
76            .origin(self.origin)
77            .region(self.region)
78            .read(dst_data)
79            .enq()?;
80
81        Ok(())
82    }
83
84    pub fn write(&self, src_data: &[T]) -> anyhow::Result<()> {
85        self.ocl_image
86            .cmd()
87            .origin(self.origin)
88            .region(self.region)
89            .write(src_data)
90            .enq()?;
91
92        Ok(())
93    }
94
95    pub fn deepcopy(&self) -> anyhow::Result<Self> {
96        let queue = self
97            .ocl_image
98            .default_queue()
99            .context("The original image is expected to have a default queue")?
100            .clone();
101
102        let copied_image = ocl::Image::builder()
103            .queue(queue)
104            .channel_data_type(ocl::enums::ImageChannelDataType::SignedInt32)
105            .channel_order(ocl::enums::ImageChannelOrder::Rgba)
106            .image_type(ocl::enums::MemObjectType::Image2d)
107            .dims(self.ocl_image.dims())
108            .build()?;
109        self.ocl_image.cmd().copy(&copied_image, [0; 3]).enq()?;
110
111        Ok(Self { ocl_image: copied_image, origin: self.origin, region: self.region })
112    }
113
114    pub fn to_vec(&self) -> anyhow::Result<Vec<T>> {
115        let mut data = vec![
116            T::default();
117            self.region[0]
118                * self.region[1]
119                * self.region[2]
120                * self.ocl_image.pixel_element_len()
121        ];
122        self.read(&mut data)?;
123
124        Ok(data)
125    }
126}
127
128fn is_region_suitable_for_image<T: ocl::OclPrm>(
129    ocl_image: &ocl::Image<T>,
130    origin: Dims,
131    region: Dims,
132) -> bool {
133    let full_image_region: Dims = ocl_image.dims().into();
134
135    const MAX_DIM_COUNT: usize = 3;
136    for i in 0..MAX_DIM_COUNT {
137        if origin[i] + region[i] > full_image_region[i] {
138            return false;
139        }
140    }
141
142    true
143}
144
145#[derive(Debug, Clone, Copy)]
146#[repr(transparent)]
147pub struct Dims([usize; 3]);
148
149impl Dims {
150    pub fn new(x: usize, y: usize, z: usize) -> Self {
151        Self([x, y, z])
152    }
153}
154
155impl convert::From<usize> for Dims {
156    fn from(x: usize) -> Self {
157        Self::new(x, 1, 1)
158    }
159}
160
161impl convert::From<(usize,)> for Dims {
162    fn from(dims: (usize,)) -> Self {
163        Self::new(dims.0, 1, 1)
164    }
165}
166
167impl convert::From<[usize; 1]> for Dims {
168    fn from(dims: [usize; 1]) -> Self {
169        Self::new(dims[0], 1, 1)
170    }
171}
172
173impl convert::From<(usize, usize)> for Dims {
174    fn from(dims: (usize, usize)) -> Self {
175        Self::new(dims.0, dims.1, 1)
176    }
177}
178
179impl convert::From<[usize; 2]> for Dims {
180    fn from(dims: [usize; 2]) -> Self {
181        Self::new(dims[0], dims[1], 1)
182    }
183}
184
185impl convert::From<(usize, usize, usize)> for Dims {
186    fn from(dims: (usize, usize, usize)) -> Self {
187        Self::new(dims.0, dims.1, dims.2)
188    }
189}
190
191impl convert::From<[usize; 3]> for Dims {
192    fn from(dims: [usize; 3]) -> Self {
193        Self::new(dims[0], dims[1], dims[2])
194    }
195}
196
197impl convert::From<ocl::SpatialDims> for Dims {
198    fn from(spatial_dims: ocl::SpatialDims) -> Self {
199        match spatial_dims.to_lens() {
200            Ok(dims) => dims.into(),
201            Err(_) => [1; 3].into(),
202        }
203    }
204}
205
206impl convert::From<&ocl::SpatialDims> for Dims {
207    fn from(spatial_dims: &ocl::SpatialDims) -> Self {
208        match spatial_dims.to_lens() {
209            Ok(dims) => dims.into(),
210            Err(_) => [1; 3].into(),
211        }
212    }
213}
214
215impl convert::From<Dims> for [usize; 3] {
216    fn from(dims: Dims) -> Self {
217        dims.0
218    }
219}
220
221impl convert::From<Dims> for ocl::SpatialDims {
222    fn from(dims: Dims) -> Self {
223        dims.0.into()
224    }
225}
226
227impl ops::Index<usize> for Dims {
228    type Output = usize;
229
230    fn index(&self, index: usize) -> &Self::Output {
231        &self.0[index]
232    }
233}
234
235impl ops::IndexMut<usize> for Dims {
236    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
237        &mut self.0[index]
238    }
239}