• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2017-2020 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/GLES_COMPUTE/kernels/GCFillBorderKernel.h"
25 
26 #include "arm_compute/core/Error.h"
27 #include "arm_compute/core/GLES_COMPUTE/GCHelpers.h"
28 #include "arm_compute/core/GLES_COMPUTE/GCKernelLibrary.h"
29 #include "arm_compute/core/GLES_COMPUTE/IGCTensor.h"
30 #include "arm_compute/core/GLES_COMPUTE/OpenGLES.h"
31 #include "arm_compute/core/TensorInfo.h"
32 #include "arm_compute/core/Utils.h"
33 #include "arm_compute/core/Validate.h"
34 #include "arm_compute/core/Window.h"
35 #include "src/core/helpers/AutoConfiguration.h"
36 #include "src/core/helpers/WindowHelpers.h"
37 #include "support/StringSupport.h"
38 
39 #include <cstdint>
40 #include <set>
41 #include <string>
42 
43 using namespace arm_compute;
44 
GCFillBorderKernel()45 GCFillBorderKernel::GCFillBorderKernel()
46     : IGCKernel(), _tensor(nullptr)
47 {
48 }
49 
is_parallelisable() const50 bool GCFillBorderKernel::is_parallelisable() const
51 {
52     return false;
53 }
54 
55 template <class T>
set_constant_border(unsigned int idx,const PixelValue & constant_border_value)56 void GCFillBorderKernel::set_constant_border(unsigned int idx, const PixelValue &constant_border_value)
57 {
58     T value;
59     constant_border_value.get(value);
60     _kernel.set_argument(idx, static_cast<T>(value));
61 }
62 
configure(const IGCTensor * tensor,BorderSize border_size,BorderMode border_mode,const PixelValue & constant_border_value)63 void GCFillBorderKernel::configure(const IGCTensor *tensor, BorderSize border_size, BorderMode border_mode, const PixelValue &constant_border_value)
64 {
65     ARM_COMPUTE_ERROR_ON(tensor == nullptr);
66     ARM_COMPUTE_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(tensor, 1, DataType::F32, DataType::F16);
67     ARM_COMPUTE_ERROR_ON(tensor->info()->num_channels() != 1);
68 
69     border_size.limit(tensor->info()->padding());
70 
71     // If there is no border: early exit
72     if(border_size.empty() || border_mode == BorderMode::UNDEFINED)
73     {
74         return;
75     }
76 
77     // Select appropriate kernel
78     std::string kernel_name = "fill_image_borders_" + lower_string(string_from_border_mode(border_mode));
79 
80     // Define build options
81     std::set<std::string> build_opts;
82     build_opts.emplace("#define LOCAL_SIZE_X " + support::cpp11::to_string(1));
83     build_opts.emplace("#define LOCAL_SIZE_Y " + support::cpp11::to_string(1));
84     build_opts.emplace("#define LOCAL_SIZE_Z " + support::cpp11::to_string(1));
85     build_opts.emplace("#define BORDER_SIZE_TOP " + support::cpp11::to_string(border_size.top));
86     build_opts.emplace("#define BORDER_SIZE_BOTTOM " + support::cpp11::to_string(border_size.bottom));
87     build_opts.emplace("#define BORDER_SIZE_LEFT " + support::cpp11::to_string(border_size.left));
88     build_opts.emplace("#define BORDER_SIZE_RIGHT " + support::cpp11::to_string(border_size.right));
89 
90     if(border_mode == BorderMode::REPLICATE)
91     {
92         build_opts.emplace("#define FILL_IMAGE_BORDERS_REPLICATE\n");
93     }
94     else
95     {
96         build_opts.emplace("#define FILL_IMAGE_BORDERS_CONSTANT\n");
97     }
98 
99     switch(tensor->info()->data_type())
100     {
101         case DataType::F16:
102             build_opts.emplace("#define DATA_TYPE_FP16");
103             break;
104 
105         case DataType::F32:
106             build_opts.emplace("#define DATA_TYPE_FP32");
107             break;
108 
109         default:
110             ARM_COMPUTE_ERROR("Current data type is not supported");
111             break;
112     }
113 
114     // Create kernel
115     _kernel = static_cast<GCKernel>(GCKernelLibrary::get().create_kernel(kernel_name, build_opts));
116     _tensor = tensor;
117 
118     // Create static kernel arguments
119     const unsigned int valid_width       = tensor->info()->valid_region().shape[0];
120     const unsigned int valid_height      = tensor->info()->valid_region().shape[1];
121     const unsigned int total_valid_width = border_size.left + valid_width + border_size.right;
122 
123     // Set static kernel arguments
124     unsigned int idx = num_arguments_per_3D_tensor(); //Skip the tensor parameters
125     _kernel.set_argument(idx++, valid_width);
126     _kernel.set_argument(idx++, valid_height);
127     _kernel.set_argument(idx++, tensor->info()->valid_region().anchor[0]);
128     _kernel.set_argument(idx++, tensor->info()->valid_region().anchor[1]);
129 
130     if(BorderMode::CONSTANT == border_mode)
131     {
132         set_constant_border<float>(idx++, constant_border_value);
133     }
134 
135     // Configure kernel window
136     Window win;
137     win.set(Window::DimX, Window::Dimension(0, total_valid_width + valid_height));
138     win.set(Window::DimY, Window::Dimension(0, 1, 1));
139     win.use_tensor_dimensions(tensor->info()->tensor_shape(), Window::DimZ);
140 
141     IGCKernel::configure(win);
142 }
143 
run(const Window & window)144 void GCFillBorderKernel::run(const Window &window)
145 {
146     // Border mode undefined or border width == 0
147     if(_kernel.get_program() == 0)
148     {
149         return;
150     }
151 
152     ARM_COMPUTE_ERROR_ON_UNCONFIGURED_KERNEL(this);
153     ARM_COMPUTE_ERROR_ON_MISMATCHING_WINDOWS(IGCKernel::window(), window);
154 
155     _kernel.use();
156     Window slice = window.first_slice_window_3D();
157 
158     do
159     {
160         unsigned int idx = 0;
161         add_3D_tensor_argument(idx, _tensor, 1, slice);
162 
163         _kernel.update_shader_params();
164 
165         enqueue(*this, slice);
166     }
167     while(window.slide_window_slice_3D(slice));
168 }
169