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
9pub 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 const INPUT: [[Pixel; 2]; 1] = [[R, G]];
76 const INPUT_FLAT: [u8; 6] = flatten!(INPUT, 6);
77
78 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}