phaneron/format/
rgba8.rs

1/*
2 * Phaneron media compositing software.
3 * Copyright (C) 2023 SuperFlyTV AB
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18
19use phaneron_plugin::InterlaceMode;
20
21use crate::{
22    compute::AsKernalParamU32,
23    io::{Packer, Unpacker},
24};
25
26const PIXELS_PER_WORK_ITEM: usize = 64;
27
28fn get_pitch(width: usize) -> usize {
29    width
30}
31
32fn get_pitch_bytes(width: usize) -> usize {
33    get_pitch(width) * 4
34}
35
36pub struct RGBA8Reader {
37    width: usize,
38    height: usize,
39    num_bytes: Vec<usize>,
40    work_items_per_group: usize,
41    global_work_items: usize,
42}
43
44impl RGBA8Reader {
45    pub fn new(width: usize, height: usize) -> Self {
46        let num_bytes = vec![get_pitch_bytes(width) * height];
47        let work_items_per_group = get_pitch(width) / PIXELS_PER_WORK_ITEM;
48        let global_work_items = work_items_per_group * height;
49
50        Self {
51            width,
52            height,
53            num_bytes,
54            work_items_per_group,
55            global_work_items,
56        }
57    }
58}
59
60impl Packer for RGBA8Reader {
61    fn get_name(&self) -> &str {
62        "RGBA8 Reader"
63    }
64
65    fn get_kernel(&self) -> &str {
66        include_str!("../../shaders/video_process/load/rgba8.cl")
67    }
68
69    fn get_width(&self) -> usize {
70        self.width
71    }
72
73    fn get_height(&self) -> usize {
74        self.height
75    }
76
77    fn get_num_bits(&self) -> usize {
78        8
79    }
80
81    fn get_luma_black(&self) -> f32 {
82        64.0
83    }
84
85    fn get_luma_white(&self) -> f32 {
86        940.0
87    }
88
89    fn get_chroma_range(&self) -> f32 {
90        896.0
91    }
92
93    fn get_num_bytes(&self) -> Vec<usize> {
94        self.num_bytes.clone()
95    }
96
97    fn get_num_bytes_rgba(&self) -> usize {
98        self.width * self.height * 4 * 4
99    }
100
101    fn get_is_rgb(&self) -> bool {
102        true
103    }
104
105    fn get_total_bytes(&self) -> usize {
106        self.num_bytes.iter().sum()
107    }
108
109    fn get_work_items_per_group(&self) -> usize {
110        self.work_items_per_group
111    }
112
113    fn get_global_work_items(&self) -> usize {
114        self.global_work_items
115    }
116
117    fn get_kernel_params(
118        &self,
119        kernel: &mut opencl3::kernel::ExecuteKernel,
120        inputs: &[&opencl3::memory::Buffer<opencl3::types::cl_uchar>],
121        output: &mut opencl3::memory::Buffer<opencl3::types::cl_uchar>,
122    ) {
123        if inputs.len() != 1 {
124            panic!(
125                "Reader for {} requires exactly 1 input, received {}",
126                self.get_name(),
127                inputs.len()
128            );
129        }
130
131        let width = self.width as u32;
132
133        unsafe { kernel.set_arg(inputs[0]).set_arg(output).set_arg(&width) };
134    }
135}
136
137pub struct RGBA8Writer {
138    width: usize,
139    height: usize,
140    interlace: InterlaceMode,
141    num_bytes: Vec<usize>,
142    work_items_per_group: usize,
143    global_work_items: usize,
144}
145
146impl RGBA8Writer {
147    pub fn new(width: usize, height: usize, interlace: InterlaceMode) -> Self {
148        let num_bytes = vec![get_pitch_bytes(width) * height];
149        let work_items_per_group = get_pitch(width) / PIXELS_PER_WORK_ITEM;
150        let global_work_items = (work_items_per_group * height)
151            / (match interlace {
152                InterlaceMode::Progressive => 1,
153                _ => 2,
154            });
155
156        Self {
157            width,
158            height,
159            interlace,
160            num_bytes,
161            work_items_per_group,
162            global_work_items,
163        }
164    }
165}
166
167impl Unpacker for RGBA8Writer {
168    fn get_name(&self) -> &str {
169        "RGBA8 Writer"
170    }
171
172    fn get_kernel(&self) -> &str {
173        include_str!("../../shaders/video_process/consume/rgba8.cl")
174    }
175
176    fn get_width(&self) -> usize {
177        self.width
178    }
179
180    fn get_height(&self) -> usize {
181        self.height
182    }
183
184    fn get_num_bits(&self) -> usize {
185        8
186    }
187
188    fn get_luma_black(&self) -> f32 {
189        64.0
190    }
191
192    fn get_luma_white(&self) -> f32 {
193        940.0
194    }
195
196    fn get_chroma_range(&self) -> f32 {
197        896.0
198    }
199
200    fn get_num_bytes(&self) -> Vec<usize> {
201        self.num_bytes.clone()
202    }
203
204    fn get_num_bytes_rgba(&self) -> usize {
205        self.width * self.height * 4 * 4
206    }
207
208    fn get_is_rgb(&self) -> bool {
209        true
210    }
211
212    fn get_total_bytes(&self) -> usize {
213        self.num_bytes.iter().sum()
214    }
215
216    fn get_work_items_per_group(&self) -> usize {
217        self.work_items_per_group
218    }
219
220    fn get_global_work_items(&self) -> usize {
221        self.global_work_items
222    }
223
224    fn get_kernel_params(
225        &self,
226        kernel: &mut opencl3::kernel::ExecuteKernel,
227        input: &opencl3::memory::Buffer<opencl3::types::cl_uchar>,
228        outputs: &mut Vec<opencl3::memory::Buffer<opencl3::types::cl_uchar>>,
229    ) {
230        if outputs.len() != 1 {
231            panic!(
232                "Writer for {} requires exactly 1 output, received {}",
233                self.get_name(),
234                outputs.len()
235            );
236        }
237
238        let width = self.width as u32;
239
240        unsafe {
241            kernel
242                .set_arg(input)
243                .set_arg(&outputs[0])
244                .set_arg(&width)
245                .set_arg(&self.interlace.as_kernel_param())
246        };
247    }
248}