1use async_cuda_core::runtime::Future;
2use async_cuda_core::DeviceBuffer2D;
3
4use crate::ffi;
5use crate::region::Region;
6use crate::stream::Stream;
7
8type Result<T> = std::result::Result<T, crate::error::Error>;
9
10pub async fn resize(
31 input: &DeviceBuffer2D<u8>,
32 input_region: Region,
33 output: &mut DeviceBuffer2D<u8>,
34 output_region: Region,
35 stream: &Stream,
36) -> Result<()> {
37 assert_eq!(input.num_channels(), 3, "input image must be in RGB format");
38 assert_eq!(
39 output.num_channels(),
40 3,
41 "output image must be in RGB format"
42 );
43
44 let context = stream.to_context();
45 Future::new(move || {
46 ffi::resize::resize(
47 input.inner(),
48 input_region,
49 output.inner_mut(),
50 output_region,
51 &context,
52 )
53 })
54 .await
55}
56
57#[cfg(test)]
58mod tests {
59 use super::*;
60
61 use crate::stream::Stream;
62 use crate::tests::image::*;
63 use crate::tests::memory::*;
64
65 use async_cuda_core::DeviceBuffer2D;
66
67 #[tokio::test]
68 async fn test_resize() {
69 const OUTPUT: Image2x2 = [[R, R], [R, B]];
72 const OUTPUT_FLAT: [u8; 2 * 2 * 3] = flatten!(OUTPUT, 2 * 2 * 3);
73
74 let stream = Stream::new().await.unwrap();
75
76 let image = to_device_2d!(&RGB_FLAG, 4, 4, 3, &stream);
77 let mut output = DeviceBuffer2D::<u8>::new(2, 2, 3).await;
78 resize(&image, Region::Full, &mut output, Region::Full, &stream)
79 .await
80 .unwrap();
81
82 let output = to_host_2d!(output, &stream);
83 assert_eq!(&output, &OUTPUT_FLAT);
84 }
85
86 #[tokio::test]
87 async fn test_resize_with_input_region() {
88 #[rustfmt::skip]
91 #[allow(clippy::zero_prefixed_literal)]
92 const OUTPUT: [u8; 4 * 4 * 3] = [
93 000, 255, 000, 000, 255, 000, 000, 255, 000, 064, 191, 000,
94 000, 191, 064, 000, 191, 064, 000, 191, 064, 064, 143, 048,
95 000, 064, 191, 000, 064, 191, 000, 064, 191, 064, 048, 143,
96 064, 000, 191, 064, 000, 191, 064, 000, 191, 112, 000, 143,
97 ];
98
99 let stream = Stream::new().await.unwrap();
100
101 let image = to_device_2d!(&RGB_FLAG, 4, 4, 3, &stream);
102 let center = Region::Rectangle {
103 x: 1,
104 y: 1,
105 width: 2,
106 height: 2,
107 };
108 let mut output = DeviceBuffer2D::<u8>::new(4, 4, 3).await;
109 resize(&image, center, &mut output, Region::Full, &stream)
110 .await
111 .unwrap();
112
113 let output = to_host_2d!(output, &stream);
114 assert_eq!(&output, &OUTPUT);
115 }
116
117 #[tokio::test]
118 async fn test_resize_with_output_region() {
119 #[rustfmt::skip]
120 const INPUT: [u8; 2 * 2 * 3] = [
121 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
122 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
123 ];
124 #[rustfmt::skip]
125 const EXPECTED_OUTPUT: [u8; 2 * 2 * 3] = [
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
128 ];
129
130 let stream = Stream::new().await.unwrap();
131 let bottom_half = Region::Rectangle {
132 x: 0,
133 y: 1,
134 width: 2,
135 height: 1,
136 };
137
138 let image = to_device_2d!(&INPUT, 2, 2, 3, &stream);
139 let mut output = DeviceBuffer2D::<u8>::new(2, 2, 3).await;
140 output.fill_with_byte(0x00, &stream).await.unwrap();
141 resize(&image, Region::Full, &mut output, bottom_half, &stream)
142 .await
143 .unwrap();
144
145 let output = to_host_2d!(output, &stream);
146 assert_eq!(&output, &EXPECTED_OUTPUT);
147 }
148
149 #[tokio::test]
150 #[should_panic]
151 async fn test_it_panics_when_input_num_channels_incorrect() {
152 let input = DeviceBuffer2D::<u8>::new(100, 100, 2).await;
153 let mut output = DeviceBuffer2D::<u8>::new(200, 200, 3).await;
154 resize(
155 &input,
156 Region::Full,
157 &mut output,
158 Region::Full,
159 &Stream::null().await,
160 )
161 .await
162 .unwrap();
163 }
164
165 #[tokio::test]
166 #[should_panic]
167 async fn test_it_panics_when_output_num_channels_incorrect() {
168 let input = DeviceBuffer2D::<u8>::new(100, 100, 3).await;
169 let mut output = DeviceBuffer2D::<u8>::new(200, 200, 2).await;
170 resize(
171 &input,
172 Region::Full,
173 &mut output,
174 Region::Full,
175 &Stream::null().await,
176 )
177 .await
178 .unwrap();
179 }
180}