1use std::{marker::PhantomData, ptr::NonNull};
2
3use singe_cuda::memory::DeviceMemory;
4use singe_npp_sys as sys;
5
6use crate::{
7 error::{Error, Result},
8 types::Size,
9 utility::{checked_len, checked_step, ensure_positive, to_usize},
10};
11
12pub trait ChannelLayout: Copy + 'static {
13 const CHANNELS: usize;
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17pub struct C1;
18
19impl ChannelLayout for C1 {
20 const CHANNELS: usize = 1;
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub struct C2;
25
26impl ChannelLayout for C2 {
27 const CHANNELS: usize = 2;
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub struct C3;
32
33impl ChannelLayout for C3 {
34 const CHANNELS: usize = 3;
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub struct C4;
39
40impl ChannelLayout for C4 {
41 const CHANNELS: usize = 4;
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45pub struct AC4;
46
47impl ChannelLayout for AC4 {
48 const CHANNELS: usize = 4;
49}
50
51pub type Gray = C1;
52pub type Channels2 = C2;
53pub type Rgb = C3;
54pub type Rgba = C4;
55pub type AlphaIgnoredRgba = AC4;
56
57pub type MaskView<'a> = ImageView<'a, u8, C1>;
58pub type MaskViewMut<'a> = ImageViewMut<'a, u8, C1>;
59
60#[derive(Debug, Clone, Copy)]
61pub struct ImageView<'a, T, L = C1> {
62 ptr: NonNull<T>,
63 size: Size,
64 step: i32,
65 _t: PhantomData<(&'a T, L)>,
66}
67
68impl<'a, T, L> ImageView<'a, T, L>
69where
70 L: ChannelLayout,
71{
72 pub fn from_memory(memory: &'a DeviceMemory<T>, size: Size) -> Result<Self> {
73 let len = checked_len(size, L::CHANNELS)?;
74 if len > memory.len() {
75 return Err(Error::LengthMismatch {
76 name: "image memory".into(),
77 expected: len,
78 actual: memory.len(),
79 });
80 }
81
82 Self::from_memory_with_step(
83 memory,
84 size,
85 checked_step(size.width, L::CHANNELS, size_of::<T>())?,
86 )
87 }
88
89 pub fn from_memory_with_step(
90 memory: &'a DeviceMemory<T>,
91 size: Size,
92 step: i32,
93 ) -> Result<Self> {
94 validate_image_shape::<T, L>(size, step)?;
95 validate_image_memory::<T, L>(memory.len(), size, step)?;
96
97 Ok(Self {
98 ptr: NonNull::new(memory.as_ptr().cast_mut()).ok_or(Error::NullHandle)?,
99 size,
100 step,
101 _t: PhantomData,
102 })
103 }
104
105 pub unsafe fn from_raw_parts(ptr: *const T, size: Size, step: i32) -> Result<Self> {
117 validate_image_shape::<T, L>(size, step)?;
118
119 Ok(Self {
120 ptr: NonNull::new(ptr.cast_mut()).ok_or(Error::NullHandle)?,
121 size,
122 step,
123 _t: PhantomData,
124 })
125 }
126
127 pub const fn size(&self) -> Size {
128 self.size
129 }
130
131 pub const fn step(&self) -> i32 {
132 self.step
133 }
134
135 pub fn byte_len(&self) -> Result<usize> {
136 image_byte_len::<T, L>(self.size, self.step)
137 }
138
139 pub(crate) const fn as_ptr(&self) -> *const T {
140 self.ptr.as_ptr()
141 }
142
143 pub(crate) fn descriptor(&self) -> sys::NppiImageDescriptor {
144 sys::NppiImageDescriptor {
145 pData: self.as_ptr().cast_mut().cast(),
146 nStep: self.step,
147 oSize: self.size.into(),
148 }
149 }
150}
151
152#[derive(Debug)]
153pub struct ImageViewMut<'a, T, L = C1> {
154 ptr: NonNull<T>,
155 size: Size,
156 step: i32,
157 _marker: PhantomData<(&'a mut T, L)>,
158}
159
160impl<'a, T, L> ImageViewMut<'a, T, L>
161where
162 L: ChannelLayout,
163{
164 pub fn from_memory(memory: &'a mut DeviceMemory<T>, size: Size) -> Result<Self> {
165 let len = checked_len(size, L::CHANNELS)?;
166 if len > memory.len() {
167 return Err(Error::LengthMismatch {
168 name: "image memory".into(),
169 expected: len,
170 actual: memory.len(),
171 });
172 }
173
174 Self::from_memory_with_step(
175 memory,
176 size,
177 checked_step(size.width, L::CHANNELS, size_of::<T>())?,
178 )
179 }
180
181 pub fn from_memory_with_step(
182 memory: &'a mut DeviceMemory<T>,
183 size: Size,
184 step: i32,
185 ) -> Result<Self> {
186 validate_image_shape::<T, L>(size, step)?;
187 validate_image_memory::<T, L>(memory.len(), size, step)?;
188
189 Ok(Self {
190 ptr: NonNull::new(memory.as_mut_ptr()).ok_or(Error::NullHandle)?,
191 size,
192 step,
193 _marker: PhantomData,
194 })
195 }
196
197 pub unsafe fn from_raw_parts(ptr: *mut T, size: Size, step: i32) -> Result<Self> {
210 validate_image_shape::<T, L>(size, step)?;
211
212 Ok(Self {
213 ptr: NonNull::new(ptr).ok_or(Error::NullHandle)?,
214 size,
215 step,
216 _marker: PhantomData,
217 })
218 }
219
220 pub const fn size(&self) -> Size {
221 self.size
222 }
223
224 pub const fn step(&self) -> i32 {
225 self.step
226 }
227
228 pub fn byte_len(&self) -> Result<usize> {
229 image_byte_len::<T, L>(self.size, self.step)
230 }
231
232 pub(crate) const fn as_mut_ptr(&mut self) -> *mut T {
233 self.ptr.as_ptr()
234 }
235
236 pub(crate) fn descriptor(&mut self) -> sys::NppiImageDescriptor {
237 sys::NppiImageDescriptor {
238 pData: self.as_mut_ptr().cast(),
239 nStep: self.step,
240 oSize: self.size.into(),
241 }
242 }
243}
244
245#[derive(Debug, Clone, Copy)]
246pub struct PlanarImageView<'a, T, const C: usize> {
247 planes: [ImageView<'a, T, C1>; C],
248}
249
250impl<'a, T, const C: usize> PlanarImageView<'a, T, C> {
251 pub fn create(planes: [ImageView<'a, T, C1>; C]) -> Result<Self> {
252 validate_plane_count(C)?;
253 validate_same_planes(&planes)?;
254 Ok(Self { planes })
255 }
256
257 pub const fn planes(&self) -> &[ImageView<'a, T, C1>; C] {
258 &self.planes
259 }
260}
261
262#[derive(Debug)]
263pub struct PlanarImageViewMut<'a, T, const C: usize> {
264 planes: [ImageViewMut<'a, T, C1>; C],
265}
266
267impl<'a, T, const C: usize> PlanarImageViewMut<'a, T, C> {
268 pub fn create(planes: [ImageViewMut<'a, T, C1>; C]) -> Result<Self> {
269 validate_plane_count(C)?;
270 validate_same_planes(&planes)?;
271 Ok(Self { planes })
272 }
273
274 pub const fn planes(&self) -> &[ImageViewMut<'a, T, C1>; C] {
275 &self.planes
276 }
277
278 pub fn planes_mut(&mut self) -> &mut [ImageViewMut<'a, T, C1>; C] {
279 &mut self.planes
280 }
281}
282
283fn validate_image_shape<T, L>(size: Size, step: i32) -> Result<()>
284where
285 L: ChannelLayout,
286{
287 size.validate()?;
288
289 let element_size = size_of::<T>();
290 if element_size == 0 {
291 return Err(Error::OutOfRange {
292 name: "element size".into(),
293 });
294 }
295
296 let minimum_step = checked_step(size.width, L::CHANNELS, element_size)?;
297 if step < minimum_step {
298 return Err(Error::OutOfRange {
299 name: "step".into(),
300 });
301 }
302
303 Ok(())
304}
305
306fn validate_image_memory<T, L>(memory_len: usize, size: Size, step: i32) -> Result<()>
307where
308 L: ChannelLayout,
309{
310 let element_size = size_of::<T>();
311 let required_bytes = image_byte_len::<T, L>(size, step)?;
312 let available_bytes = memory_len
313 .checked_mul(element_size)
314 .ok_or_else(|| Error::OutOfRange { name: "len".into() })?;
315
316 if required_bytes > available_bytes {
317 return Err(Error::LengthMismatch {
318 name: "image memory".into(),
319 expected: required_bytes,
320 actual: available_bytes,
321 });
322 }
323
324 Ok(())
325}
326
327fn image_byte_len<T, L>(size: Size, step: i32) -> Result<usize>
328where
329 L: ChannelLayout,
330{
331 size.validate()?;
332 ensure_positive(step, "step")?;
333
334 let row_bytes = (size.width as usize)
335 .checked_mul(L::CHANNELS)
336 .and_then(|value| value.checked_mul(size_of::<T>()))
337 .ok_or_else(|| Error::OutOfRange {
338 name: "byte_len".into(),
339 })?;
340 (size.height as usize - 1)
341 .checked_mul(step as usize)
342 .and_then(|value| value.checked_add(row_bytes))
343 .ok_or_else(|| Error::OutOfRange {
344 name: "byte_len".into(),
345 })
346}
347
348fn validate_plane_count(count: usize) -> Result<()> {
349 match count {
350 2..=4 => Ok(()),
351 _ => Err(Error::OutOfRange {
352 name: "plane count".into(),
353 }),
354 }
355}
356
357fn validate_same_planes<T, P, const C: usize>(planes: &[P; C]) -> Result<()>
358where
359 P: PlaneInfo<T>,
360{
361 let Some(first) = planes.first() else {
362 return Ok(());
363 };
364
365 for plane in planes.iter().skip(1) {
366 if plane.size() != first.size() {
367 let expected = (first.size().width as usize)
368 .checked_mul(first.size().height as usize)
369 .ok_or_else(|| Error::OutOfRange { name: "len".into() })?;
370 let actual = (plane.size().width as usize)
371 .checked_mul(plane.size().height as usize)
372 .ok_or_else(|| Error::OutOfRange { name: "len".into() })?;
373 return Err(Error::LengthMismatch {
374 name: "plane size".into(),
375 expected,
376 actual,
377 });
378 }
379
380 if plane.step() != first.step() {
381 return Err(Error::LengthMismatch {
382 name: "plane step".into(),
383 expected: to_usize(first.step(), "plane step")?,
384 actual: to_usize(plane.step(), "plane step")?,
385 });
386 }
387 }
388
389 Ok(())
390}
391
392trait PlaneInfo<T> {
393 fn size(&self) -> Size;
394 fn step(&self) -> i32;
395}
396
397impl<T> PlaneInfo<T> for ImageView<'_, T, C1> {
398 fn size(&self) -> Size {
399 self.size()
400 }
401
402 fn step(&self) -> i32 {
403 self.step()
404 }
405}
406
407impl<T> PlaneInfo<T> for ImageViewMut<'_, T, C1> {
408 fn size(&self) -> Size {
409 self.size()
410 }
411
412 fn step(&self) -> i32 {
413 self.step()
414 }
415}
416
417pub(crate) fn image_descriptors<T, L>(
418 images: &[ImageView<'_, T, L>],
419) -> Vec<sys::NppiImageDescriptor>
420where
421 L: ChannelLayout,
422{
423 images.iter().map(ImageView::descriptor).collect()
424}
425
426pub(crate) fn image_descriptors_mut<T, L>(
427 images: &mut [ImageViewMut<'_, T, L>],
428) -> Vec<sys::NppiImageDescriptor>
429where
430 L: ChannelLayout,
431{
432 images.iter_mut().map(ImageViewMut::descriptor).collect()
433}