blob: 699a5d92992f8c710e5a6b4bfbabfb956a736ac3 [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/NEFillInnerBorderKernel.h"
25
26#include "arm_compute/core/Error.h"
27#include "arm_compute/core/Helpers.h"
28#include "arm_compute/core/ITensor.h"
29#include "arm_compute/core/TensorInfo.h"
30#include "arm_compute/core/Validate.h"
31#include "arm_compute/core/Window.h"
32
33#include <algorithm>
34#include <cstddef>
35#include <cstdint>
36
37using namespace arm_compute;
38
39namespace arm_compute
40{
41class Coordinates;
42} // namespace arm_compute
43
44NEFillInnerBorderKernel::NEFillInnerBorderKernel()
45 : _tensor(nullptr), _border_size(0), _constant_border_value(0)
46{
47}
48
49void NEFillInnerBorderKernel::configure(ITensor *input, BorderSize border_size, const PixelValue &constant_border_value)
50{
51 ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(input, 1, DataType::U8, DataType::S16, DataType::S32, DataType::F32);
52
53 _tensor = input;
54 _border_size = border_size;
55 _constant_border_value = constant_border_value;
56
57 Window win;
58 win.set(Window::DimX, Window::Dimension(0, 1, 1));
59 win.set(Window::DimY, Window::Dimension(0, 1, 1));
60 win.use_tensor_dimensions(_tensor->info(), Window::DimZ);
61 INEKernel::configure(win);
62}
63
64void NEFillInnerBorderKernel::run(const Window &window)
65{
66 ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
67 ARM_COMPUTE_ERROR_ON_INVALID_SUBWINDOW(INEKernel::window(), window);
68
69 // If there is no border: early exit
70 if(_border_size.empty())
71 {
72 return;
73 }
74
75 switch(_tensor->info()->data_type())
76 {
77 case DataType::U8:
78 fill_value_single_channel<uint8_t>(window);
79 break;
80 case DataType::S16:
81 fill_value_single_channel<int16_t>(window);
82 break;
83 case DataType::S32:
84 fill_value_single_channel<int32_t>(window);
85 break;
86 case DataType::F32:
87 static_assert(sizeof(float) == 4, "Float must be 32 bit");
88 fill_value_single_channel<float>(window);
89 break;
90 default:
91 ARM_COMPUTE_ERROR("Not handled");
92 break;
93 }
94}
95
96template <typename T>
97void NEFillInnerBorderKernel::fill_value_single_channel(const Window &window)
98{
99 const size_t stride = _tensor->info()->strides_in_bytes()[1];
100 const size_t width = _tensor->info()->dimension(0);
101 const size_t height = _tensor->info()->dimension(1);
102
103 T constant_border_value;
104 _constant_border_value.get(constant_border_value);
105
106 // Left and right border
107 // All X values are set at once
108 Window vertical(window);
109 vertical.set(Window::DimY, Window::Dimension(0, height, 1));
110
111 Iterator vertical_it(_tensor, vertical);
112
113 execute_window_loop(vertical, [&](const Coordinates & id)
114 {
115 std::fill_n(reinterpret_cast<T *>(vertical_it.ptr()), _border_size.left, constant_border_value);
116 std::fill_n(reinterpret_cast<T *>(vertical_it.ptr()) + width - _border_size.right, _border_size.right, constant_border_value);
117 },
118 vertical_it);
119
120 // Top and bottom border
121 // All values are set at once
122 Iterator horizontal_it(_tensor, window);
123
124 execute_window_loop(window, [&](const Coordinates & id)
125 {
126 for(size_t i = 0; i < _border_size.top; ++i)
127 {
128 std::fill_n(reinterpret_cast<T *>(horizontal_it.ptr() + i * stride), width, constant_border_value);
129 }
130
131 for(size_t i = 0; i < _border_size.bottom; ++i)
132 {
133 std::fill_n(reinterpret_cast<T *>(horizontal_it.ptr() + (height - i - 1) * stride), width, constant_border_value);
134 }
135 },
136 horizontal_it);
137}