async_cuda_npp/
copy_constant_border.rs

1use async_cuda_core::runtime::Future;
2use async_cuda_core::DeviceBuffer2D;
3
4use crate::constant_border::ConstantBorder;
5use crate::ffi;
6use crate::stream::Stream;
7
8type Result<T> = std::result::Result<T, crate::error::Error>;
9
10/// Copy an image with a constant border. This function expects a reference to a device image for
11/// input, and a mutable reference to a device image to place the output in.
12///
13/// This function assumes the following about the input and output images:
14/// * Images are in RGB format.
15/// * Images are in standard memory order, i.e. HWC.
16///
17/// # Stream ordered semantics
18///
19/// This function uses stream ordered semantics. It can only be guaranteed to complete sequentially
20/// relative to operations scheduled on the same stream or the default stream.
21///
22/// # Arguments
23///
24/// * `input` - The on-device input image.
25/// * `output` - The on-device output image.
26/// * `constant_border` - The constant border parameters to apply.
27/// * `stream` - Stream to use.
28pub async fn copy_constant_border(
29    input: &DeviceBuffer2D<u8>,
30    output: &mut DeviceBuffer2D<u8>,
31    constant_border: &ConstantBorder,
32    stream: &Stream,
33) -> Result<()> {
34    assert_eq!(input.num_channels(), 3, "input image must be in RGB format");
35    assert_eq!(
36        output.num_channels(),
37        3,
38        "output image must be in RGB format"
39    );
40
41    let context = stream.to_context();
42    Future::new(move || {
43        ffi::copy_constant_border::copy_constant_border(
44            input.inner(),
45            output.inner_mut(),
46            constant_border,
47            &context,
48        )
49    })
50    .await
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    use crate::stream::Stream;
58    use crate::tests::image::*;
59    use crate::tests::memory::*;
60
61    use async_cuda_core::DeviceBuffer2D;
62
63    #[tokio::test]
64    async fn test_copy_constant_border() {
65        // Input image is 1x2 and just contains one red and one green pixel.
66        const INPUT: [[Pixel; 2]; 1] = [[R, G]];
67        const INPUT_FLAT: [u8; 6] = flatten!(INPUT, 6);
68
69        // Expected output of copy constant border with left border of 1 and top border of 2, if
70        // the border color is blue.
71        const OUTPUT: [[Pixel; 4]; 5] = [
72            [B, B, B, B],
73            [B, B, B, B],
74            [B, R, G, B],
75            [B, B, B, B],
76            [B, B, B, B],
77        ];
78        const OUTPUT_FLAT: [u8; 4 * 5 * 3] = flatten!(OUTPUT, 4 * 5 * 3);
79
80        let stream = Stream::new().await.unwrap();
81
82        let image = to_device_2d!(&INPUT_FLAT, 2, 1, 3, &stream);
83        let mut output = DeviceBuffer2D::<u8>::new(4, 5, 3).await;
84        copy_constant_border(&image, &mut output, &ConstantBorder::new(1, 2, B), &stream)
85            .await
86            .unwrap();
87
88        let output = to_host_2d!(output, &stream);
89        assert_eq!(&output, &OUTPUT_FLAT);
90    }
91
92    #[tokio::test]
93    #[should_panic]
94    async fn test_it_panics_when_input_num_channels_incorrect() {
95        let input = DeviceBuffer2D::<u8>::new(100, 100, 2).await;
96        let mut output = DeviceBuffer2D::<u8>::new(200, 200, 3).await;
97        copy_constant_border(
98            &input,
99            &mut output,
100            &ConstantBorder::black(10, 20),
101            &Stream::null().await,
102        )
103        .await
104        .unwrap();
105    }
106
107    #[tokio::test]
108    #[should_panic]
109    async fn test_it_panics_when_output_num_channels_incorrect() {
110        let input = DeviceBuffer2D::<u8>::new(100, 100, 3).await;
111        let mut output = DeviceBuffer2D::<u8>::new(200, 200, 2).await;
112        copy_constant_border(
113            &input,
114            &mut output,
115            &ConstantBorder::black(10, 20),
116            &Stream::null().await,
117        )
118        .await
119        .unwrap();
120    }
121}