oximedia_gpu/kernels/
resize.rs1use crate::{GpuDevice, Result};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum ResizeFilter {
8 Nearest,
10 Bilinear,
12 Bicubic,
14 Lanczos,
16 Area,
18}
19
20impl ResizeFilter {
21 #[must_use]
23 pub fn to_id(self) -> u32 {
24 match self {
25 Self::Nearest => 0,
26 Self::Bilinear => 1,
27 Self::Bicubic => 2,
28 Self::Lanczos => 3,
29 Self::Area => 4,
30 }
31 }
32
33 #[must_use]
35 pub fn name(self) -> &'static str {
36 match self {
37 Self::Nearest => "Nearest",
38 Self::Bilinear => "Bilinear",
39 Self::Bicubic => "Bicubic",
40 Self::Lanczos => "Lanczos",
41 Self::Area => "Area",
42 }
43 }
44
45 #[must_use]
47 pub fn kernel_radius(self) -> u32 {
48 match self {
49 Self::Nearest => 0,
50 Self::Bilinear => 1,
51 Self::Bicubic => 2,
52 Self::Lanczos => 3,
53 Self::Area => 1,
54 }
55 }
56}
57
58pub struct ResizeKernel {
60 filter: ResizeFilter,
61}
62
63impl ResizeKernel {
64 #[must_use]
66 pub fn new(filter: ResizeFilter) -> Self {
67 Self { filter }
68 }
69
70 #[allow(clippy::too_many_arguments)]
86 pub fn execute(
87 &self,
88 device: &GpuDevice,
89 input: &[u8],
90 _src_width: u32,
91 _src_height: u32,
92 output: &mut [u8],
93 dst_width: u32,
94 dst_height: u32,
95 ) -> Result<()> {
96 crate::ops::ScaleOperation::scale(
98 device,
99 input,
100 _src_width,
101 _src_height,
102 output,
103 dst_width,
104 dst_height,
105 self.filter.into(),
106 )
107 }
108
109 #[must_use]
111 pub fn filter(&self) -> ResizeFilter {
112 self.filter
113 }
114
115 #[must_use]
117 pub fn output_size(dst_width: u32, dst_height: u32, channels: u32) -> usize {
118 (dst_width * dst_height * channels) as usize
119 }
120
121 #[must_use]
123 pub fn estimate_flops(
124 _src_width: u32,
125 _src_height: u32,
126 dst_width: u32,
127 dst_height: u32,
128 filter: ResizeFilter,
129 ) -> u64 {
130 let output_pixels = u64::from(dst_width) * u64::from(dst_height);
131 let kernel_size = u64::from(filter.kernel_radius());
132 let samples_per_pixel = (kernel_size * 2 + 1) * (kernel_size * 2 + 1);
133
134 output_pixels * samples_per_pixel * 6
136 }
137}
138
139impl From<ResizeFilter> for crate::ops::ScaleFilter {
140 fn from(filter: ResizeFilter) -> Self {
141 match filter {
142 ResizeFilter::Nearest => Self::Nearest,
143 ResizeFilter::Bilinear => Self::Bilinear,
144 ResizeFilter::Bicubic => Self::Bicubic,
145 ResizeFilter::Area => Self::Area,
146 ResizeFilter::Lanczos => Self::Bicubic, }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn test_resize_filter_properties() {
157 assert_eq!(ResizeFilter::Nearest.to_id(), 0);
158 assert_eq!(ResizeFilter::Bilinear.to_id(), 1);
159 assert_eq!(ResizeFilter::Bicubic.to_id(), 2);
160
161 assert_eq!(ResizeFilter::Nearest.kernel_radius(), 0);
162 assert_eq!(ResizeFilter::Bilinear.kernel_radius(), 1);
163 assert_eq!(ResizeFilter::Bicubic.kernel_radius(), 2);
164 assert_eq!(ResizeFilter::Lanczos.kernel_radius(), 3);
165 }
166
167 #[test]
168 fn test_output_size_calculation() {
169 assert_eq!(ResizeKernel::output_size(1920, 1080, 4), 1920 * 1080 * 4);
170 assert_eq!(ResizeKernel::output_size(640, 480, 3), 640 * 480 * 3);
171 }
172
173 #[test]
174 fn test_flops_estimation() {
175 let flops = ResizeKernel::estimate_flops(1920, 1080, 960, 540, ResizeFilter::Bilinear);
176 assert!(flops > 0);
177
178 let flops_bicubic =
179 ResizeKernel::estimate_flops(1920, 1080, 960, 540, ResizeFilter::Bicubic);
180 assert!(flops_bicubic > flops); }
182}