blob: 347aeaede611a3724ae072043561ee3c327ba00a [file] [log] [blame]
Anthony Barbier6ff3b192017-09-04 18:44:23 +01001/*
2 * Copyright (c) 2016, 2017 ARM Limited.
3 *
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;
115 default:
116 ARM_COMPUTE_ERROR("Not supported");
117 break;
118 }
119 break;
120 }
121 default:
122 ARM_COMPUTE_ERROR("Not supported");
123 break;
124 }
125
126 _input = input;
127 _output = output;
128
129 // Configure kernel window
130 Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
131 AccessWindowHorizontal input_access(input->info(), 0, num_elems_processed_per_iteration);
132 AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
133
134 update_window_and_padding(win, input_access, output_access);
135
136 output_access.set_valid_region(win, input->info()->valid_region());
137
138 INEKernel::configure(win);
139}
140
141void NEColorConvertKernel::configure(const IMultiImage *input, IImage *output)
142{
143 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
144 ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(output);
145
146 set_shape_if_empty(*output->info(), input->plane(0)->info()->tensor_shape());
147
148 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output);
149
150 unsigned int num_elems_processed_per_iteration = 0;
151
152 switch(input->info()->format())
153 {
154 case Format::NV12:
155 {
156 switch(output->info()->format())
157 {
158 case Format::RGB888:
159 _func = colorconvert_nv12_to_rgb<true, false>;
160 num_elems_processed_per_iteration = 32;
161 break;
162 case Format::RGBA8888:
163 _func = colorconvert_nv12_to_rgb<true, true>;
164 num_elems_processed_per_iteration = 32;
165 break;
166 default:
167 ARM_COMPUTE_ERROR("Not supported");
168 break;
169 }
170 break;
171 }
172 case Format::NV21:
173 {
174 switch(output->info()->format())
175 {
176 case Format::RGB888:
177 _func = colorconvert_nv12_to_rgb<false, false>;
178 num_elems_processed_per_iteration = 32;
179 break;
180 case Format::RGBA8888:
181 _func = colorconvert_nv12_to_rgb<false, true>;
182 num_elems_processed_per_iteration = 32;
183 break;
184 default:
185 ARM_COMPUTE_ERROR("Not supported");
186 break;
187 }
188 break;
189 }
190 case Format::IYUV:
191 {
192 switch(output->info()->format())
193 {
194 case Format::RGB888:
195 _func = colorconvert_iyuv_to_rgb<false>;
196 num_elems_processed_per_iteration = 32;
197 break;
198 case Format::RGBA8888:
199 _func = colorconvert_iyuv_to_rgb<true>;
200 num_elems_processed_per_iteration = 32;
201 break;
202 default:
203 ARM_COMPUTE_ERROR("Not supported");
204 break;
205 }
206 break;
207 }
208 default:
209 ARM_COMPUTE_ERROR("Not supported");
210 break;
211 }
212
213 _input = input;
214 _output = output;
215
216 // Configure kernel window
217 Window win = calculate_max_window(*output->info(), Steps(num_elems_processed_per_iteration));
218 win.set_dimension_step(Window::DimY, 2);
219
220 unsigned int input_plane_count = 3;
221
222 if(input->info()->format() == Format::NV12 || input->info()->format() == Format::NV21)
223 {
224 input_plane_count = 2;
225 }
226
227 AccessWindowHorizontal input0_access(input->plane(0)->info(), 0, num_elems_processed_per_iteration);
228 AccessWindowRectangle input1_access(input->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, 0.5f, 0.5f);
229 AccessWindowRectangle input2_access(input_plane_count == 2 ? nullptr : input->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, 0.5f, 0.5f);
230 AccessWindowHorizontal output_access(output->info(), 0, num_elems_processed_per_iteration);
231
232 update_window_and_padding(win,
233 input0_access, input1_access, input2_access,
234 output_access);
235
236 ValidRegion intersect_region = intersect_valid_regions(input->plane(0)->info()->valid_region(),
237 input->plane(1)->info()->valid_region());
238
239 if(input_plane_count == 3)
240 {
241 intersect_region = intersect_valid_regions(intersect_region, input->plane(2)->info()->valid_region());
242 }
243
244 output_access.set_valid_region(win, intersect_region);
245
246 INEKernel::configure(win);
247}
248
249void NEColorConvertKernel::configure(const IImage *input, IMultiImage *output)
250{
251 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
252 ARM_COMPUTE_ERROR_ON_TENSOR_NOT_2D(input);
253
254 set_shape_if_empty(*output->plane(0)->info(), input->info()->tensor_shape());
255
256 switch(output->info()->format())
257 {
258 case Format::NV12:
259 {
260 TensorShape subsampled_shape = input->info()->tensor_shape();
261 subsampled_shape.set(0, subsampled_shape[0] / 2);
262 subsampled_shape.set(1, subsampled_shape[1] / 2);
263
264 set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
265
266 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
267 break;
268 }
269 case Format::IYUV:
270 {
271 TensorShape subsampled_shape = input->info()->tensor_shape();
272 subsampled_shape.set(0, subsampled_shape[0] / 2);
273 subsampled_shape.set(1, subsampled_shape[1] / 2);
274
275 set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
276 set_shape_if_empty(*output->plane(2)->info(), subsampled_shape);
277
278 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
279 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(2)->info()->tensor_shape());
280 break;
281 }
282 case Format::YUV444:
283 set_shape_if_empty(*output->plane(1)->info(), input->info()->tensor_shape());
284 set_shape_if_empty(*output->plane(2)->info(), input->info()->tensor_shape());
285
286 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output->plane(1));
287 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output->plane(2));
288 break;
289 default:
290 ARM_COMPUTE_ERROR("Not supported");
291 }
292
293 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input, output->plane(0));
294
295 unsigned int num_elems_processed_per_iteration = 0;
296
297 switch(input->info()->format())
298 {
299 case Format::RGB888:
300 {
301 switch(output->info()->format())
302 {
303 case Format::NV12:
304 _func = colorconvert_rgb_to_nv12<false>;
305 num_elems_processed_per_iteration = 16;
306 break;
307 case Format::IYUV:
308 _func = colorconvert_rgb_to_iyuv<false>;
309 num_elems_processed_per_iteration = 16;
310 break;
311 case Format::YUV444:
312 _func = colorconvert_rgb_to_yuv4<false>;
313 num_elems_processed_per_iteration = 16;
314 break;
315 default:
316 ARM_COMPUTE_ERROR("Not supported");
317 break;
318 }
319 break;
320 }
321 case Format::RGBA8888:
322 {
323 switch(output->info()->format())
324 {
325 case Format::NV12:
326 _func = colorconvert_rgb_to_nv12<true>;
327 num_elems_processed_per_iteration = 16;
328 break;
329 case Format::IYUV:
330 _func = colorconvert_rgb_to_iyuv<true>;
331 num_elems_processed_per_iteration = 16;
332 break;
333 case Format::YUV444:
334 _func = colorconvert_rgb_to_yuv4<true>;
335 num_elems_processed_per_iteration = 16;
336 break;
337 default:
338 ARM_COMPUTE_ERROR("Not supported");
339 break;
340 }
341 break;
342 }
343 case Format::UYVY422:
344 {
345 switch(output->info()->format())
346 {
347 case Format::NV12:
348 _func = colorconvert_yuyv_to_nv12<false>;
349 num_elems_processed_per_iteration = 32;
350 break;
351 case Format::IYUV:
352 _func = colorconvert_yuyv_to_iyuv<false>;
353 num_elems_processed_per_iteration = 32;
354 break;
355 default:
356 ARM_COMPUTE_ERROR("Not supported");
357 break;
358 }
359 break;
360 }
361 case Format::YUYV422:
362 {
363 switch(output->info()->format())
364 {
365 case Format::NV12:
366 _func = colorconvert_yuyv_to_nv12<true>;
367 num_elems_processed_per_iteration = 32;
368 break;
369 case Format::IYUV:
370 _func = colorconvert_yuyv_to_iyuv<true>;
371 num_elems_processed_per_iteration = 32;
372 break;
373 default:
374 ARM_COMPUTE_ERROR("Not supported");
375 break;
376 }
377 break;
378 }
379 default:
380 ARM_COMPUTE_ERROR("Not supported");
381 break;
382 }
383
384 _input = input;
385 _output = output;
386
387 // Configure kernel window
388 Window win = calculate_max_window(*input->info(), Steps(num_elems_processed_per_iteration));
389
390 float sub_sampling = 1.f;
391
392 if((input->info()->format() != Format::RGB888 || output->info()->format() != Format::YUV444) && (input->info()->format() != Format::RGBA8888 || output->info()->format() != Format::YUV444))
393 {
394 win.set_dimension_step(Window::DimY, 2);
395 sub_sampling = 0.5f;
396 }
397
398 unsigned int output_plane_count = 3;
399
400 if(output->info()->format() == Format::NV12 || output->info()->format() == Format::NV21)
401 {
402 output_plane_count = 2;
403 }
404
405 AccessWindowHorizontal output0_access(output->plane(0)->info(), 0, num_elems_processed_per_iteration);
406 AccessWindowRectangle output1_access(output->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, sub_sampling, sub_sampling);
407 AccessWindowRectangle output2_access(output_plane_count == 2 ? nullptr : output->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, sub_sampling, sub_sampling);
408
409 update_window_and_padding(win,
410 AccessWindowHorizontal(input->info(), 0, num_elems_processed_per_iteration),
411 output0_access,
412 output1_access,
413 output2_access);
414
415 output0_access.set_valid_region(win, input->info()->valid_region());
416 output1_access.set_valid_region(win, input->info()->valid_region());
417 output2_access.set_valid_region(win, input->info()->valid_region());
418
419 INEKernel::configure(win);
420}
421
422void NEColorConvertKernel::configure(const IMultiImage *input, IMultiImage *output)
423{
424 ARM_COMPUTE_ERROR_ON_NULLPTR(input, output);
425 ARM_COMPUTE_ERROR_ON(input == output);
426
427 set_shape_if_empty(*output->plane(0)->info(), input->plane(0)->info()->tensor_shape());
428
429 switch(output->info()->format())
430 {
431 case Format::NV12:
432 {
433 TensorShape subsampled_shape = input->plane(0)->info()->tensor_shape();
434 subsampled_shape.set(0, subsampled_shape[0] / 2);
435 subsampled_shape.set(1, subsampled_shape[1] / 2);
436
437 set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
438
439 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
440 break;
441 }
442 case Format::IYUV:
443 {
444 TensorShape subsampled_shape = input->plane(0)->info()->tensor_shape();
445 subsampled_shape.set(0, subsampled_shape[0] / 2);
446 subsampled_shape.set(1, subsampled_shape[1] / 2);
447
448 set_shape_if_empty(*output->plane(1)->info(), subsampled_shape);
449 set_shape_if_empty(*output->plane(2)->info(), subsampled_shape);
450
451 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(1)->info()->tensor_shape());
452 ARM_COMPUTE_ERROR_ON_MISMATCHING_DIMENSIONS(subsampled_shape, output->plane(2)->info()->tensor_shape());
453 break;
454 }
455 case Format::YUV444:
456 set_shape_if_empty(*output->plane(1)->info(), input->plane(0)->info()->tensor_shape());
457 set_shape_if_empty(*output->plane(2)->info(), input->plane(0)->info()->tensor_shape());
458
459 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(1));
460 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(2));
461 break;
462 default:
463 ARM_COMPUTE_ERROR("Not supported");
464 }
465
466 ARM_COMPUTE_ERROR_ON_MISMATCHING_SHAPES(input->plane(0), output->plane(0));
467
468 switch(input->info()->format())
469 {
470 case Format::NV12:
471 {
472 switch(output->info()->format())
473 {
474 case Format::IYUV:
475 _func = colorconvert_nv12_to_iyuv<true>;
476 break;
477 case Format::YUV444:
478 _func = colorconvert_nv12_to_yuv4<true>;
479 break;
480 default:
481 ARM_COMPUTE_ERROR("Not supported");
482 break;
483 }
484 break;
485 }
486 case Format::NV21:
487 {
488 switch(output->info()->format())
489 {
490 case Format::IYUV:
491 _func = colorconvert_nv12_to_iyuv<false>;
492 break;
493 case Format::YUV444:
494 _func = colorconvert_nv12_to_yuv4<false>;
495 break;
496 default:
497 ARM_COMPUTE_ERROR("Not supported");
498 break;
499 }
500 break;
501 }
502 case Format::IYUV:
503 {
504 switch(output->info()->format())
505 {
506 case Format::NV12:
507 _func = colorconvert_iyuv_to_nv12;
508 break;
509 case Format::YUV444:
510 _func = colorconvert_iyuv_to_yuv4;
511 break;
512 default:
513 ARM_COMPUTE_ERROR("Not supported");
514 break;
515 }
516 break;
517 }
518 default:
519 ARM_COMPUTE_ERROR("Not supported");
520 break;
521 }
522
523 _input = input;
524 _output = output;
525
526 constexpr unsigned int num_elems_processed_per_iteration = 32;
527 constexpr float input_sub_sampling = 0.5f;
528 const float output_sub_sampling = output->info()->format() == Format::YUV444 ? 1.f : 0.5f;
529
530 // Configure kernel window
531 Window win = calculate_max_window(*input->plane(0)->info(), Steps(num_elems_processed_per_iteration));
532 win.set_dimension_step(Window::DimY, 2);
533
534 unsigned int input_plane_count = 3;
535
536 if(input->info()->format() == Format::NV12 || input->info()->format() == Format::NV21)
537 {
538 input_plane_count = 2;
539 }
540
541 unsigned int output_plane_count = 3;
542
543 if(output->info()->format() == Format::NV12 || output->info()->format() == Format::NV21)
544 {
545 output_plane_count = 2;
546 }
547
548 AccessWindowHorizontal output0_access(output->plane(0)->info(), 0, num_elems_processed_per_iteration);
549 AccessWindowRectangle output1_access(output->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, output_sub_sampling, output_sub_sampling);
550 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);
551
552 update_window_and_padding(win,
553 AccessWindowHorizontal(input->plane(0)->info(), 0, num_elems_processed_per_iteration),
554 AccessWindowRectangle(input->plane(1)->info(), 0, 0, num_elems_processed_per_iteration, 1, input_sub_sampling, input_sub_sampling),
555 AccessWindowRectangle(input_plane_count == 2 ? nullptr : input->plane(2)->info(), 0, 0, num_elems_processed_per_iteration, 1, input_sub_sampling, input_sub_sampling),
556 output0_access,
557 output1_access,
558 output2_access);
559
560 ValidRegion intersect_region = intersect_valid_regions(input->plane(0)->info()->valid_region(),
561 input->plane(1)->info()->valid_region());
562
563 if(input_plane_count == 3)
564 {
565 intersect_region = intersect_valid_regions(intersect_region, input->plane(2)->info()->valid_region());
566 }
567
568 output0_access.set_valid_region(win, intersect_region);
569 output1_access.set_valid_region(win, intersect_region);
570 output2_access.set_valid_region(win, intersect_region);
571
572 INEKernel::configure(win);
573}
574
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100575void NEColorConvertKernel::run(const Window &window, const ThreadInfo &info)
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100576{
Moritz Pflanzerc186b572017-09-07 09:48:04 +0100577 ARM_COMPUTE_UNUSED(info);
Anthony Barbier6ff3b192017-09-04 18:44:23 +0100578 ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
579 ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window);
580 ARM_COMPUTE_ERROR_ON(_func == nullptr);
581
582 (*_func)(_input, _output, window);
583}