vdtfont/opencl/
image_view.rs1use 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}