async_cuda_npp/ffi/
copy_constant_border.rs

1use cpp::cpp;
2
3use crate::constant_border::ConstantBorder;
4use crate::ffi::context::Context;
5use crate::ffi::result;
6
7type Result<T> = std::result::Result<T, crate::error::Error>;
8
9/// Synchroneous implementation of [`crate::copy_constant_border()`].
10///
11/// Refer to [`crate::copy_constant_border()`] for documentation.
12pub fn copy_constant_border(
13    input: &async_cuda_core::ffi::memory::DeviceBuffer2D<u8>,
14    output: &mut async_cuda_core::ffi::memory::DeviceBuffer2D<u8>,
15    border: &ConstantBorder,
16    context: &Context,
17) -> Result<()> {
18    assert_eq!(input.num_channels, 3, "input image must be in RGB format");
19    assert_eq!(output.num_channels, 3, "output image must be in RGB format");
20
21    let (src_pitch, src_width, src_height) = (input.pitch, input.width as i32, input.height as i32);
22    let (dst_pitch, dst_width, dst_height) =
23        (output.pitch, output.width as i32, output.height as i32);
24
25    let (border_left, border_top) = (border.left as i32, border.top as i32);
26    let border_color_ptr = border.color.as_ptr();
27
28    let src_ptr = input.as_internal().as_ptr();
29    let dst_ptr = output.as_mut_internal().as_mut_ptr();
30    let context_ptr = context.as_ptr();
31    let ret = cpp!(unsafe [
32        src_ptr as "const void*",
33        src_pitch as "std::size_t",
34        src_width as "std::int32_t",
35        src_height as "std::int32_t",
36        dst_ptr as "void*",
37        dst_pitch as "std::size_t",
38        dst_width as "std::int32_t",
39        dst_height as "std::int32_t",
40        border_left as "std::int32_t",
41        border_top as "std::int32_t",
42        border_color_ptr as "const std::uint8_t*",
43        context_ptr as "void*"
44    ] -> i32 as "std::int32_t" {
45        NppiSize src_size = { src_width, src_height };
46        NppiSize dst_size = { dst_width, dst_height };
47        return nppiCopyConstBorder_8u_C3R_Ctx(
48            (const Npp8u*) src_ptr,
49            src_pitch,
50            src_size,
51            (Npp8u*) dst_ptr,
52            dst_pitch,
53            dst_size,
54            border_top,
55            border_left,
56            border_color_ptr,
57            *((NppStreamContext*) context_ptr)
58        );
59    });
60    result!(ret)
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    use crate::tests::image::*;
68    use crate::tests::sync::memory::*;
69
70    use crate::ffi::context::Context;
71
72    #[test]
73    fn test_copy_constant_border() {
74        // Input image is 1x2 and just contains one red and one green pixel.
75        const INPUT: [[Pixel; 2]; 1] = [[R, G]];
76        const INPUT_FLAT: [u8; 6] = flatten!(INPUT, 6);
77
78        // Expected output of copy constant border with left border of 1 and top border of 2, if
79        // the border color is blue.
80        const OUTPUT: [[Pixel; 4]; 5] = [
81            [B, B, B, B],
82            [B, B, B, B],
83            [B, R, G, B],
84            [B, B, B, B],
85            [B, B, B, B],
86        ];
87        const OUTPUT_FLAT: [u8; 4 * 5 * 3] = flatten!(OUTPUT, 4 * 5 * 3);
88
89        let context = Context::from_null_stream();
90
91        let image = to_device_2d!(&INPUT_FLAT, 2, 1, 3, &context);
92        let mut output = async_cuda_core::ffi::memory::DeviceBuffer2D::<u8>::new(4, 5, 3);
93        copy_constant_border(&image, &mut output, &ConstantBorder::new(1, 2, B), &context).unwrap();
94
95        let output = to_host_2d!(output, &context);
96        assert_eq!(&output, &OUTPUT_FLAT);
97    }
98
99    #[test]
100    #[should_panic]
101    fn test_it_panics_when_input_num_channels_incorrect() {
102        let input = async_cuda_core::ffi::memory::DeviceBuffer2D::<u8>::new(100, 100, 2);
103        let mut output = async_cuda_core::ffi::memory::DeviceBuffer2D::<u8>::new(200, 200, 3);
104        copy_constant_border(
105            &input,
106            &mut output,
107            &ConstantBorder::black(10, 20),
108            &Context::from_null_stream(),
109        )
110        .unwrap();
111    }
112
113    #[test]
114    #[should_panic]
115    fn test_it_panics_when_output_num_channels_incorrect() {
116        let input = async_cuda_core::ffi::memory::DeviceBuffer2D::<u8>::new(100, 100, 3);
117        let mut output = async_cuda_core::ffi::memory::DeviceBuffer2D::<u8>::new(200, 200, 2);
118        copy_constant_border(
119            &input,
120            &mut output,
121            &ConstantBorder::black(10, 20),
122            &Context::from_null_stream(),
123        )
124        .unwrap();
125    }
126}