blob: 1f0796519b815c32df1a4b1e1865014df3eb7f22 [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
Michele Di Giorgiod9eaf612020-07-08 11:12:57 +01002 * Copyright (c) 2016-2018 Arm Limited.
Anthony Barbier6ff3b192017-09-04 18:44:23 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#include "arm_compute/core/NEON/kernels/NEColorConvertKernel.h"
25
26#include "arm_compute/core/Error.h"
27#include "arm_compute/core/Helpers.h"
28#include "arm_compute/core/IAccessWindow.h"
29#include "arm_compute/core/IMultiImage.h"
30#include "arm_compute/core/ITensor.h"
31#include "arm_compute/core/MultiImageInfo.h"
32#include "arm_compute/core/NEON/NEColorConvertHelper.inl"
33#include "arm_compute/core/TensorInfo.h"
34#include "arm_compute/core/Types.h"
35#include "arm_compute/core/Validate.h"
36#include "arm_compute/core/Window.h"
37
38using namespace arm_compute;
39
40NEColorConvertKernel::NEColorConvertKernel()
41 : _input(nullptr), _output(nullptr), _func(nullptr)
42{
43}
44
45void NEColorConvertKernel::configure(const ITensor *input, ITensor *output)
46{
47 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
48
49 set_shape_if_empty(*output->info(), input->info()->tensor_shape());
50
51 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output);
52
53 unsigned int num_elems_processed_per_iteration = 0;
54
55 switch(input->info()->format())
56 {
57 case Format::RGBA8888:
58 {
59 switch(output->info()->format())
60 {
61 case Format::RGB888:
62 _func = colorconvert_rgbx_to_rgb;
63 num_elems_processed_per_iteration = 16;
64 break;
65 default:
66 ARM_COMPUTE_ERROR("Not supported");
67 break;
68 }
69 break;
70 }
71 case Format::UYVY422:
72 {
73 switch(output->info()->format())
74 {
75 case Format::RGB888:
76 _func = colorconvert_yuyv_to_rgb<false, false>;
77 num_elems_processed_per_iteration = 32;
78 break;
79 case Format::RGBA8888:
80 _func = colorconvert_yuyv_to_rgb<false, true>;
81 num_elems_processed_per_iteration = 32;
82 break;
83 default:
84 ARM_COMPUTE_ERROR("Not supported");
85 break;
86 }
87 break;
88 }
89 case Format::YUYV422:
90 {
91 switch(output->info()->format())
92 {
93 case Format::RGB888:
94 _func = colorconvert_yuyv_to_rgb<true, false>;
95 num_elems_processed_per_iteration = 32;
96 break;
97 case Format::RGBA8888:
98 _func = colorconvert_yuyv_to_rgb<true, true>;
99 num_elems_processed_per_iteration = 32;
100 break;
101 default:
102 ARM_COMPUTE_ERROR("Not supported");
103 break;
104 }
105 break;
106 }
107 case Format::RGB888:
108 {
109 switch(output->info()->format())
110 {
111 case Format::RGBA8888:
112 _func = colorconvert_rgb_to_rgbx;
113 num_elems_processed_per_iteration = 16;
114 break;
Manuel Bottini4284bfa2018-09-26 15:33:15 +0100115 case Format::U8:
116 _func = colorconvert_rgb_to_u8;
117 num_elems_processed_per_iteration = 16;
118 break;
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100119 default:
120 ARM_COMPUTE_ERROR("Not supported");
121 break;
122 }
123 break;
124 }
125 default:
126 ARM_COMPUTE_ERROR("Not supported");
127 break;
128 }
129
130 _input = input;
131 _output = output;
132
133 // Configure kernel window
134 Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
135 AccessWindowHorizontal input_access(input->info(), 0, num_elems_processed_per_iteration);
136 AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
137
138 update_window_and_padding(win, input_access, output_access);
139
140 output_access.set_valid_region(win, input->info()->valid_region());
141
142 INEKernel::configure(win);
143}
144
145void NEColorConvertKernel::configure(const IMultiImage *input, IImage *output)
146{
147 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
148 ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(output);
149
150 set_shape_if_empty(*output->info(), input->plane(0)->info()->tensor_shape());
151
152 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output);
153
154 unsigned int num_elems_processed_per_iteration = 0;
155
156 switch(input->info()->format())
157 {
158 case Format::NV12:
159 {
160 switch(output->info()->format())
161 {
162 case Format::RGB888:
163 _func = colorconvert_nv12_to_rgb<true, false>;
164 num_elems_processed_per_iteration = 32;
165 break;
166 case Format::RGBA8888:
167 _func = colorconvert_nv12_to_rgb<true, true>;
168 num_elems_processed_per_iteration = 32;
169 break;
170 default:
171 ARM_COMPUTE_ERROR("Not supported");
172 break;
173 }
174 break;
175 }
176 case Format::NV21:
177 {
178 switch(output->info()->format())
179 {
180 case Format::RGB888:
181 _func = colorconvert_nv12_to_rgb<false, false>;
182 num_elems_processed_per_iteration = 32;
183 break;
184 case Format::RGBA8888:
185 _func = colorconvert_nv12_to_rgb<false, true>;
186 num_elems_processed_per_iteration = 32;
187 break;
188 default:
189 ARM_COMPUTE_ERROR("Not supported");
190 break;
191 }
192 break;
193 }
194 case Format::IYUV:
195 {
196 switch(output->info()->format())
197 {
198 case Format::RGB888:
199 _func = colorconvert_iyuv_to_rgb<false>;
200 num_elems_processed_per_iteration = 32;
201 break;
202 case Format::RGBA8888:
203 _func = colorconvert_iyuv_to_rgb<true>;
204 num_elems_processed_per_iteration = 32;
205 break;
206 default:
207 ARM_COMPUTE_ERROR("Not supported");
208 break;
209 }
210 break;
211 }
212 default:
213 ARM_COMPUTE_ERROR("Not supported");
214 break;
215 }
216
217 _input = input;
218 _output = output;
219
220 // Configure kernel window
221 Window win = calculate_max_window(*output->info(), Steps(num_elems_processed_per_iteration));
222 win.set_dimension_step(Window::DimY, 2);
223
224 unsigned int input_plane_count = 3;
225
226 if(input->info()->format() == Format::NV12 || input->info()->format() == Format::NV21)
227 {
228 input_plane_count = 2;
229 }
230
231 AccessWindowHorizontal input0_access(input->plane(0)->info(), 0, num_elems_processed_per_iteration);
232 AccessWindowRectangle input1_access(input->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, 0.5f, 0.5f);
233 AccessWindowRectangle input2_access(input_plane_count == 2 ? nullptr : input->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, 0.5f, 0.5f);
234 AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
235
236 update_window_and_padding(win,
237 input0_access, input1_access, input2_access,
238 output_access);
239
240 ValidRegion intersect_region = intersect_valid_regions(input->plane(0)->info()->valid_region(),
241 input->plane(1)->info()->valid_region());
242
243 if(input_plane_count == 3)
244 {
245 intersect_region = intersect_valid_regions(intersect_region, input->plane(2)->info()->valid_region());
246 }
247
248 output_access.set_valid_region(win, intersect_region);
249
250 INEKernel::configure(win);
251}
252
253void NEColorConvertKernel::configure(const IImage *input, IMultiImage *output)
254{
255 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
256 ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input);
257
258 set_shape_if_empty(*output->plane(0)->info(), input->info()->tensor_shape());
259
260 switch(output->info()->format())
261 {
262 case Format::NV12:
263 {
264 TensorShape subsampled_shape = input->info()->tensor_shape();
265 subsampled_shape.set(0, subsampled_shape[0] / 2);
266 subsampled_shape.set(1, subsampled_shape[1] / 2);
267
268 set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
269
270 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
271 break;
272 }
273 case Format::IYUV:
274 {
275 TensorShape subsampled_shape = input->info()->tensor_shape();
276 subsampled_shape.set(0, subsampled_shape[0] / 2);
277 subsampled_shape.set(1, subsampled_shape[1] / 2);
278
279 set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
280 set_shape_if_empty(*output->plane(2)->info(), subsampled_shape);
281
282 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
283 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(2)->info()->tensor_shape());
284 break;
285 }
286 case Format::YUV444:
287 set_shape_if_empty(*output->plane(1)->info(), input->info()->tensor_shape());
288 set_shape_if_empty(*output->plane(2)->info(), input->info()->tensor_shape());
289
290 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output->plane(1));
291 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output->plane(2));
292 break;
293 default:
294 ARM_COMPUTE_ERROR("Not supported");
295 }
296
297 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output->plane(0));
298
299 unsigned int num_elems_processed_per_iteration = 0;
300
301 switch(input->info()->format())
302 {
303 case Format::RGB888:
304 {
305 switch(output->info()->format())
306 {
307 case Format::NV12:
308 _func = colorconvert_rgb_to_nv12<false>;
309 num_elems_processed_per_iteration = 16;
310 break;
311 case Format::IYUV:
312 _func = colorconvert_rgb_to_iyuv<false>;
313 num_elems_processed_per_iteration = 16;
314 break;
315 case Format::YUV444:
316 _func = colorconvert_rgb_to_yuv4<false>;
317 num_elems_processed_per_iteration = 16;
318 break;
319 default:
320 ARM_COMPUTE_ERROR("Not supported");
321 break;
322 }
323 break;
324 }
325 case Format::RGBA8888:
326 {
327 switch(output->info()->format())
328 {
329 case Format::NV12:
330 _func = colorconvert_rgb_to_nv12<true>;
331 num_elems_processed_per_iteration = 16;
332 break;
333 case Format::IYUV:
334 _func = colorconvert_rgb_to_iyuv<true>;
335 num_elems_processed_per_iteration = 16;
336 break;
337 case Format::YUV444:
338 _func = colorconvert_rgb_to_yuv4<true>;
339 num_elems_processed_per_iteration = 16;
340 break;
341 default:
342 ARM_COMPUTE_ERROR("Not supported");
343 break;
344 }
345 break;
346 }
347 case Format::UYVY422:
348 {
349 switch(output->info()->format())
350 {
351 case Format::NV12:
352 _func = colorconvert_yuyv_to_nv12<false>;
353 num_elems_processed_per_iteration = 32;
354 break;
355 case Format::IYUV:
356 _func = colorconvert_yuyv_to_iyuv<false>;
357 num_elems_processed_per_iteration = 32;
358 break;
359 default:
360 ARM_COMPUTE_ERROR("Not supported");
361 break;
362 }
363 break;
364 }
365 case Format::YUYV422:
366 {
367 switch(output->info()->format())
368 {
369 case Format::NV12:
370 _func = colorconvert_yuyv_to_nv12<true>;
371 num_elems_processed_per_iteration = 32;
372 break;
373 case Format::IYUV:
374 _func = colorconvert_yuyv_to_iyuv<true>;
375 num_elems_processed_per_iteration = 32;
376 break;
377 default:
378 ARM_COMPUTE_ERROR("Not supported");
379 break;
380 }
381 break;
382 }
383 default:
384 ARM_COMPUTE_ERROR("Not supported");
385 break;
386 }
387
388 _input = input;
389 _output = output;
390
391 // Configure kernel window
392 Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
393
394 float sub_sampling = 1.f;
395
396 if((input->info()->format() != Format::RGB888 || output->info()->format() != Format::YUV444) && (input->info()->format() != Format::RGBA8888 || output->info()->format() != Format::YUV444))
397 {
398 win.set_dimension_step(Window::DimY, 2);
399 sub_sampling = 0.5f;
400 }
401
402 unsigned int output_plane_count = 3;
403
404 if(output->info()->format() == Format::NV12 || output->info()->format() == Format::NV21)
405 {
406 output_plane_count = 2;
407 }
408
409 AccessWindowHorizontal output0_access(output->plane(0)->info(), 0, num_elems_processed_per_iteration);
410 AccessWindowRectangle output1_access(output->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, sub_sampling, sub_sampling);
411 AccessWindowRectangle output2_access(output_plane_count == 2 ? nullptr : output->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, sub_sampling, sub_sampling);
412
413 update_window_and_padding(win,
414 AccessWindowHorizontal(input->info(), 0, num_elems_processed_per_iteration),
415 output0_access,
416 output1_access,
417 output2_access);
418
419 output0_access.set_valid_region(win, input->info()->valid_region());
420 output1_access.set_valid_region(win, input->info()->valid_region());
421 output2_access.set_valid_region(win, input->info()->valid_region());
422
423 INEKernel::configure(win);
424}
425
426void NEColorConvertKernel::configure(const IMultiImage *input, IMultiImage *output)
427{
428 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
429 ARM_COMPUTE_ERROR_ON(input == output);
430
431 set_shape_if_empty(*output->plane(0)->info(), input->plane(0)->info()->tensor_shape());
432
433 switch(output->info()->format())
434 {
435 case Format::NV12:
436 {
437 TensorShape subsampled_shape = input->plane(0)->info()->tensor_shape();
438 subsampled_shape.set(0, subsampled_shape[0] / 2);
439 subsampled_shape.set(1, subsampled_shape[1] / 2);
440
441 set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
442
443 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
444 break;
445 }
446 case Format::IYUV:
447 {
448 TensorShape subsampled_shape = input->plane(0)->info()->tensor_shape();
449 subsampled_shape.set(0, subsampled_shape[0] / 2);
450 subsampled_shape.set(1, subsampled_shape[1] / 2);
451
452 set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
453 set_shape_if_empty(*output->plane(2)->info(), subsampled_shape);
454
455 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
456 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(2)->info()->tensor_shape());
457 break;
458 }
459 case Format::YUV444:
460 set_shape_if_empty(*output->plane(1)->info(), input->plane(0)->info()->tensor_shape());
461 set_shape_if_empty(*output->plane(2)->info(), input->plane(0)->info()->tensor_shape());
462
463 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(1));
464 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(2));
465 break;
466 default:
467 ARM_COMPUTE_ERROR("Not supported");
468 }
469
470 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(0));
471
472 switch(input->info()->format())
473 {
474 case Format::NV12:
475 {
476 switch(output->info()->format())
477 {
478 case Format::IYUV:
479 _func = colorconvert_nv12_to_iyuv<true>;
480 break;
481 case Format::YUV444:
482 _func = colorconvert_nv12_to_yuv4<true>;
483 break;
484 default:
485 ARM_COMPUTE_ERROR("Not supported");
486 break;
487 }
488 break;
489 }
490 case Format::NV21:
491 {
492 switch(output->info()->format())
493 {
494 case Format::IYUV:
495 _func = colorconvert_nv12_to_iyuv<false>;
496 break;
497 case Format::YUV444:
498 _func = colorconvert_nv12_to_yuv4<false>;
499 break;
500 default:
501 ARM_COMPUTE_ERROR("Not supported");
502 break;
503 }
504 break;
505 }
506 case Format::IYUV:
507 {
508 switch(output->info()->format())
509 {
510 case Format::NV12:
511 _func = colorconvert_iyuv_to_nv12;
512 break;
513 case Format::YUV444:
514 _func = colorconvert_iyuv_to_yuv4;
515 break;
516 default:
517 ARM_COMPUTE_ERROR("Not supported");
518 break;
519 }
520 break;
521 }
522 default:
523 ARM_COMPUTE_ERROR("Not supported");
524 break;
525 }
526
527 _input = input;
528 _output = output;
529
530 constexpr unsigned int num_elems_processed_per_iteration = 32;
531 constexpr float input_sub_sampling = 0.5f;
532 const float output_sub_sampling = output->info()->format() == Format::YUV444 ? 1.f : 0.5f;
533
534 // Configure kernel window
535 Window win = calculate_max_window(*input->plane(0)->info(), Steps(num_elems_processed_per_iteration));
536 win.set_dimension_step(Window::DimY, 2);
537
538 unsigned int input_plane_count = 3;
539
540 if(input->info()->format() == Format::NV12 || input->info()->format() == Format::NV21)
541 {
542 input_plane_count = 2;
543 }
544
545 unsigned int output_plane_count = 3;
546
547 if(output->info()->format() == Format::NV12 || output->info()->format() == Format::NV21)
548 {
549 output_plane_count = 2;
550 }
551
552 AccessWindowHorizontal output0_access(output->plane(0)->info(), 0, num_elems_processed_per_iteration);
553 AccessWindowRectangle output1_access(output->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, output_sub_sampling, output_sub_sampling);
554 AccessWindowRectangle output2_access(output_plane_count == 2 ? nullptr : output->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, output_sub_sampling, output_sub_sampling);
555
556 update_window_and_padding(win,
557 AccessWindowHorizontal(input->plane(0)->info(), 0, num_elems_processed_per_iteration),
558 AccessWindowRectangle(input->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, input_sub_sampling, input_sub_sampling),
559 AccessWindowRectangle(input_plane_count == 2 ? nullptr : input->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, input_sub_sampling, input_sub_sampling),
560 output0_access,
561 output1_access,
562 output2_access);
563
564 ValidRegion intersect_region = intersect_valid_regions(input->plane(0)->info()->valid_region(),
565 input->plane(1)->info()->valid_region());
566
567 if(input_plane_count == 3)
568 {
569 intersect_region = intersect_valid_regions(intersect_region, input->plane(2)->info()->valid_region());
570 }
571
572 output0_access.set_valid_region(win, intersect_region);
573 output1_access.set_valid_region(win, intersect_region);
574 output2_access.set_valid_region(win, intersect_region);
575
576 INEKernel::configure(win);
577}
578
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100579void NEColorConvertKernel::run(const Window &window, const ThreadInfo &info)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100580{
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100581 ARM_COMPUTE_UNUSED(info);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100582 ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
583 ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window);
584 ARM_COMPUTE_ERROR_ON(_func == nullptr);
585
586 (*_func)(_input, _output, window);
587}