blob: f446859a8d61661812fcf412739fdcb6aaea17f6 [file] [log] [blame]
Anthony Barbier7068f992017-10-26 15:23:08 +01001/*
2 * Copyright (c) 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/GLES_COMPUTE/GCKernelLibrary.h"
25
26#include "arm_compute/core/Error.h"
27#include "arm_compute/core/Utils.h"
28
29#include <fstream>
30#include <iomanip>
31#include <iostream>
32#include <regex>
33#include <utility>
34#include <vector>
35
36using namespace arm_compute;
37
38GCProgram::GCProgram()
39 : _name(), _source()
40{
41}
42
43GCProgram::GCProgram(std::string name, std::string source)
44 : _name(std::move(name)), _source(std::move(source))
45{
46}
47
48GLuint GCProgram::link_program(GLuint shader)
49{
50 GLuint program = ARM_COMPUTE_GL_CHECK(glCreateProgram());
51
52 GLint rvalue;
53 GLsizei length;
54
55 ARM_COMPUTE_GL_CHECK(glAttachShader(program, shader));
56 ARM_COMPUTE_GL_CHECK(glLinkProgram(program));
57 ARM_COMPUTE_GL_CHECK(glDetachShader(program, shader));
58 ARM_COMPUTE_GL_CHECK(glDeleteShader(shader));
59
60 // Check if there were some issues when linking the shader.
61 ARM_COMPUTE_GL_CHECK(glGetProgramiv(program, GL_LINK_STATUS, &rvalue));
62
63 if(rvalue == 0)
64 {
65 ARM_COMPUTE_GL_CHECK(glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length));
66
67 std::vector<GLchar> log(length);
68 ARM_COMPUTE_GL_CHECK(glGetProgramInfoLog(program, length, nullptr, log.data()));
69 ARM_COMPUTE_ERROR("Error: Linker log:\n%s\n", log.data());
70
71 return 0;
72 }
73
74 ARM_COMPUTE_GL_CHECK(glUseProgram(program));
75
76 return program;
77}
78
79GLuint GCProgram::compile_shader(const std::string &build_options)
80{
81 GLuint shader = ARM_COMPUTE_GL_CHECK(glCreateShader(GL_COMPUTE_SHADER));
82
83 const char *src[]
84 {
85 "#version 310 es\n",
86 build_options.c_str(),
87 _source.c_str()
88 };
89
90 ARM_COMPUTE_GL_CHECK(glShaderSource(shader, sizeof(src) / sizeof(src[0]), src, nullptr));
91
92 ARM_COMPUTE_GL_CHECK(glCompileShader(shader));
93
94 // Check if there were any issues when compiling the shader
95 GLint rvalue;
96 GLsizei length;
97
98 ARM_COMPUTE_GL_CHECK(glGetShaderiv(shader, GL_COMPILE_STATUS, &rvalue));
99
100 if(rvalue == 0)
101 {
102 ARM_COMPUTE_GL_CHECK(glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length));
103
104 std::vector<GLchar> log(length);
105 ARM_COMPUTE_GL_CHECK(glGetShaderInfoLog(shader, length, nullptr, log.data()));
106
107#ifdef ARM_COMPUTE_DEBUG_ENABLED
108 std::istringstream ss(_source);
109 std::stringstream output_stream;
110 std::string line;
111 size_t line_num = 1;
112
113 ARM_COMPUTE_LOG_INFO_MSG_WITH_FORMAT_CORE("GLES Shader build options:\n%s\n", build_options.c_str());
114 while(std::getline(ss, line, '\n'))
115 {
116 output_stream << std::setw(6) << line_num << ": " << line << std::endl;
117 line_num++;
118 }
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800119 ARM_COMPUTE_LOG_INFO_STREAM_CORE("GLES Shader source code:\n"
120 << output_stream.rdbuf());
Anthony Barbier7068f992017-10-26 15:23:08 +0100121#endif /* ARM_COMPUTE_DEBUG_ENABLED */
122
123 ARM_COMPUTE_ERROR("Error: Compiler log:\n%s\n", log.data());
124
125 return 0;
126 }
127
128 return shader;
129}
130
131GCKernel::GCKernel()
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800132 : _name(), _program(), _shader_arguments(), _shader_params_ubo_name(), _shader_params_binding_point(), _shader_params_index(), _shader_params_size()
Anthony Barbier7068f992017-10-26 15:23:08 +0100133{
134}
135
136GCKernel::GCKernel(std::string name, GLuint program)
137 : _name(std::move(name)),
138 _program(program),
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800139 _shader_arguments(),
140 _shader_params_ubo_name(0),
Anthony Barbier7068f992017-10-26 15:23:08 +0100141 _shader_params_binding_point(0),
142 _shader_params_index(0),
143 _shader_params_size(0)
144{
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800145 _shader_arguments.clear();
Anthony Barbier7068f992017-10-26 15:23:08 +0100146
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800147 ARM_COMPUTE_GL_CHECK(glGenBuffers(1, &_shader_params_ubo_name));
Anthony Barbier7068f992017-10-26 15:23:08 +0100148
149 _shader_params_index = ARM_COMPUTE_GL_CHECK(glGetUniformBlockIndex(_program, _shader_params_name));
150 ARM_COMPUTE_ERROR_ON_MSG((_shader_params_index == GL_INVALID_INDEX), "Failed to get index of %s", _shader_params_name);
151 ARM_COMPUTE_GL_CHECK(glGetActiveUniformBlockiv(_program, _shader_params_index, GL_UNIFORM_BLOCK_DATA_SIZE, &_shader_params_size));
152 ARM_COMPUTE_ERROR_ON_MSG((_shader_params_size == 0), "Failed to get size of %s", _shader_params_name);
153}
154
155void GCKernel::cleanup()
156{
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800157 ARM_COMPUTE_GL_CHECK(glDeleteBuffers(1, &_shader_params_ubo_name));
Anthony Barbier7068f992017-10-26 15:23:08 +0100158 ARM_COMPUTE_GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));
159 ARM_COMPUTE_GL_CHECK(glDeleteProgram(_program));
160 ARM_COMPUTE_GL_CHECK(glUseProgram(0));
161}
162
163void GCKernel::use()
164{
165 ARM_COMPUTE_GL_CHECK(glUseProgram(_program));
166}
167
168void GCKernel::unuse()
169{
170 ARM_COMPUTE_GL_CHECK(glUseProgram(0));
171}
172
173void GCKernel::update_shader_params()
174{
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800175 ARM_COMPUTE_ERROR_ON_MSG((_shader_params_size != (int)(_shader_arguments.size() * sizeof(_shader_arguments[0]))), "Arguments size (%d) is not equal to shader params block size (%d)",
176 _shader_arguments.size() * sizeof(_shader_arguments[0]), _shader_params_size);
Anthony Barbier7068f992017-10-26 15:23:08 +0100177
178 ARM_COMPUTE_GL_CHECK(glUniformBlockBinding(_program, _shader_params_index, _shader_params_binding_point));
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800179 ARM_COMPUTE_GL_CHECK(glBindBufferBase(GL_UNIFORM_BUFFER, _shader_params_binding_point, _shader_params_ubo_name));
180 ARM_COMPUTE_GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, _shader_params_ubo_name));
181 ARM_COMPUTE_GL_CHECK(glBufferData(GL_UNIFORM_BUFFER, _shader_params_size, _shader_arguments.data(), GL_DYNAMIC_DRAW));
Anthony Barbier7068f992017-10-26 15:23:08 +0100182 ARM_COMPUTE_GL_CHECK(glBindBuffer(GL_UNIFORM_BUFFER, 0));
183}
184
185const std::map<std::string, std::string> GCKernelLibrary::_shader_program_map =
186{
187 { "absdiff", "absdiff.cs" },
188 { "col2im", "convolution_layer.cs" },
189 { "direct_convolution1x1", "direct_convolution1x1.cs" },
190 { "direct_convolution3x3", "direct_convolution3x3.cs" },
191 { "direct_convolution5x5", "direct_convolution5x5.cs" },
192 { "pooling_layer_2", "pooling_layer.cs" },
193 { "pooling_layer_3", "pooling_layer.cs" },
194 { "pooling_layer_7", "pooling_layer.cs" },
195 { "pooling_layer_3_optimized", "pooling_layer.cs" },
196 { "pooling_layer_n", "pooling_layer.cs" },
197 { "fill_image_borders_replicate", "fill_border.cs" },
198 { "fill_image_borders_constant", "fill_border.cs" },
199 { "gemm_accumulate_biases", "gemm.cs" },
200 { "gemm_interleave4x4", "gemm.cs" },
201 { "gemm_ma", "gemm.cs" },
202 { "gemm_mm_interleaved_transposed", "gemm.cs" },
203 { "gemm_mm_floating_point", "gemm.cs" },
204 { "gemm_transpose1x4", "gemm.cs" },
205 { "im2col_kernel3x3_padx0_pady0", "convolution_layer.cs" },
206 { "im2col_generic", "convolution_layer.cs" },
207 { "im2col_reduced", "convolution_layer.cs" },
208 { "transpose", "transpose.cs" },
209 { "activation_layer", "activation_layer.cs" },
210 { "softmax_layer_max", "softmax_layer.cs" },
211 { "softmax_layer_shift_exp_sum", "softmax_layer.cs" },
212 { "softmax_layer_norm", "softmax_layer.cs" },
213 { "pixelwise_mul_float", "pixelwise_mul_float.cs" },
214 { "normalization_layer", "normalization_layer.cs" },
215 { "batchnormalization_layer", "batchnormalization_layer.cs" },
216 { "concatenate_depth", "concatenate.cs" },
217 { "dropout", "dropout.cs" },
218};
219
220const std::map<std::string, std::string> GCKernelLibrary::_program_source_map =
221{
222#ifdef EMBEDDED_KERNELS
223 {
224 "absdiff.cs",
225#include "./cs_shaders/absdiff.csembed"
226 },
227 {
228 "convolution_layer.cs",
229#include "./cs_shaders/convolution_layer.csembed"
230 },
231 {
232 "direct_convolution1x1.cs",
233#include "./cs_shaders/direct_convolution1x1.csembed"
234 },
235 {
236 "direct_convolution3x3.cs",
237#include "./cs_shaders/direct_convolution3x3.csembed"
238 },
239 {
240 "direct_convolution5x5.cs",
241#include "./cs_shaders/direct_convolution5x5.csembed"
242 },
243 {
244 "pooling_layer.cs",
245#include "./cs_shaders/pooling_layer.csembed"
246 },
247 {
248 "fill_border.cs",
249#include "./cs_shaders/fill_border.csembed"
250 },
251 {
252 "gemm.cs",
253#include "./cs_shaders/gemm.csembed"
254 },
255 {
256 "transpose.cs",
257#include "./cs_shaders/transpose.csembed"
258 },
259 {
260 "activation_layer.cs",
261#include "./cs_shaders/activation_layer.csembed"
262 },
263 {
264 "softmax_layer.cs",
265#include "./cs_shaders/softmax_layer.csembed"
266 },
267 {
268 "pixelwise_mul_float.cs",
269#include "./cs_shaders/pixelwise_mul_float.csembed"
270 },
271 {
272 "normalization_layer.cs",
273#include "./cs_shaders/normalization_layer.csembed"
274 },
275 {
276 "batchnormalization_layer.cs",
277#include "./cs_shaders/batchnormalization_layer.csembed"
278 },
279 {
280 "concatenate.cs",
281#include "./cs_shaders/concatenate.csembed"
282 },
283 {
284 "dropout.cs",
285#include "./cs_shaders/dropout.csembed"
286 },
287#endif /* EMBEDDED_KERNELS */
288};
289
290GCKernelLibrary::GCKernelLibrary()
291 : _display(EGL_NO_DISPLAY), _context(EGL_NO_CONTEXT), _frame_buffer(0), _tex_rt(0), _own_context(false), _shader_path("./"), _programs_map(), _built_programs_map()
292{
293}
294
295GCKernelLibrary &GCKernelLibrary::get()
296{
297 static GCKernelLibrary _kernel_library;
298 return _kernel_library;
299}
300
301GCKernel GCKernelLibrary::create_kernel(const std::string &shader_name, const StringSet &build_options_set) const
302{
303 // Find which program contains the kernel
304 auto shader_program_it = _shader_program_map.find(shader_name);
305
306 if(_shader_program_map.end() == shader_program_it)
307 {
308 ARM_COMPUTE_ERROR("Shader %s not found in the GCKernelLibrary", shader_name.c_str());
309 }
310
311 // Check if the program has been built before with same build options.
312 const std::string program_name = shader_program_it->second;
313 const std::string build_options = stringify_set(build_options_set);
314 const std::string built_program_name = program_name + "_" + build_options;
315 auto built_program_it = _built_programs_map.find(built_program_name);
316
317 GCKernel kernel;
318
319 if(_built_programs_map.end() != built_program_it)
320 {
321 // If program has been built, retrieve to create kernel from it
322 kernel = built_program_it->second;
Anthony Barbier7068f992017-10-26 15:23:08 +0100323 }
324 else
325 {
326 GCProgram program = load_program(program_name);
327
328 std::string source_name = _shader_path + shader_program_it->second;
329
330 // load shader
331 GLuint shader = program.compile_shader(build_options);
332
333 // Build program
334 GLuint gles_program = program.link_program(shader);
335
336 // Create GCKernel
337 kernel = GCKernel(shader_name, gles_program);
338
339 // Add built program to internal map
340 _built_programs_map.emplace(built_program_name, kernel);
341 }
342
Joel Liangf1f3ebd2017-11-10 09:59:19 +0800343 kernel.use();
344 kernel.clear_arguments();
345 // set shader params binding point
346 kernel.set_shader_params_binding_point(0);
347
Anthony Barbier7068f992017-10-26 15:23:08 +0100348 return kernel;
349}
350
351const std::string GCKernelLibrary::preprocess_shader(const std::string &shader_source) const
352{
353 enum class ParserStage
354 {
355 FIRST,
356 SKIP_COMMENTS = FIRST,
357 RESOLVE_INCLUDES,
358 SKIP_PREPROCESSOR_DIRECTIVES,
359 SEARCH_MACRO_DEFINITIONS,
360 EXPAND_MACRO_USES,
361 LAST
362 };
363
364 struct MacroDefinitionInfo
365 {
366 const std::vector<std::string> param_list;
367 const std::string content;
368 };
369
370 // Found macro definitions so far
371 std::map<const std::string, const MacroDefinitionInfo> macro_definitions;
372
373 // Define a GLES compute shader parser function
374 std::function<std::string(const std::string &, ParserStage, int)> cs_parser;
375 cs_parser = [&](const std::string & src, ParserStage stage, int nested_level) -> std::string
376 {
377 std::string dst;
378
379 if(stage == ParserStage::LAST || std::regex_match(src, std::regex(R"(\s*)")))
380 {
381 return src;
382 }
383 auto next_stage = static_cast<ParserStage>(static_cast<int>(stage) + 1);
384
385 std::string search_pattern;
386 switch(stage)
387 {
388 case ParserStage::SKIP_COMMENTS:
389 search_pattern = R"((/\*([^*]|\n|(\*+([^*/]|\n)))*\*+/)|(//.*))";
390 break;
391 case ParserStage::RESOLVE_INCLUDES:
392 search_pattern = R"rgx((?:^|\n)[ \t]*#include "(.*)")rgx";
393 break;
394 case ParserStage::SKIP_PREPROCESSOR_DIRECTIVES:
395 search_pattern = R"((^|\n)[ \t]*(#ifdef|#ifndef|#if)[^\n]+)";
396 break;
397 case ParserStage::SEARCH_MACRO_DEFINITIONS:
398 search_pattern = R"((?:^|\n)[ \t]*#define[ \t]+(\w+)(?:\((\w+(?:[ \t]*,[ \t]*\w+)*)\))?(?: |\t|\\\n)*((?:(?:[^\\\n]|\\[^\n])*\\+\n)*(?:[ \t]*[^ \t\n]+)*)[ \t]*)";
399 break;
400 case ParserStage::EXPAND_MACRO_USES:
401 {
402 if(macro_definitions.empty())
403 {
404 // Nothing to expand
405 return src;
406 }
407 int i = 0;
408 for(auto &def : macro_definitions)
409 {
410 if(i == 0)
411 {
412 search_pattern = R"((\b)" + def.first;
413 }
414 else
415 {
416 search_pattern += R"(\b|\b)" + def.first;
417 }
418 i++;
419 }
420 search_pattern += R"(\b))";
421 break;
422 }
423 default:
424 break;
425 }
426
427 std::regex search_regex(search_pattern);
428 std::smatch match;
429 ptrdiff_t parsed_pos = 0;
430 if(std::regex_search(src, match, search_regex))
431 {
432 // Pass the content before the match to the next stage
433 dst.append(cs_parser(src.substr(0, match.position()), next_stage, 0));
434 parsed_pos = match.position() + match.length();
435
436 // Deal with the matched content
437 switch(stage)
438 {
439 case ParserStage::RESOLVE_INCLUDES:
440 {
441 // Replace with the included file contents
442 // And parse the content from the first stage
443 const std::string source_name = _shader_path + match.str(1);
444 dst.append(cs_parser(read_file(source_name, false), ParserStage::FIRST, 0));
445 break;
446 }
447 case ParserStage::SEARCH_MACRO_DEFINITIONS:
448 {
449 std::regex params_regex(R"(\b\w+\b)");
450 const std::string macro_param_str = match.str(2);
451 const std::vector<std::string> macro_param_list(
452 std::sregex_token_iterator(macro_param_str.begin(),
453 macro_param_str.end(),
454 params_regex),
455 std::sregex_token_iterator());
456
457 const MacroDefinitionInfo info =
458 {
459 macro_param_list,
460 match.str(3)
461 };
462 // Collect the macro definition data and not change the shader source
463 macro_definitions.insert(std::pair<const std::string, const MacroDefinitionInfo>(match.str(1), info));
464 dst.append(match.str());
465 break;
466 }
467 case ParserStage::EXPAND_MACRO_USES:
468 {
469 ptrdiff_t args_str_length = 0;
470 std::vector<std::string> args_list;
471
472 // Walk through argument list, because the regular expression does NOT support nested parentheses
473 size_t cur_args_str_pos = match.position() + match.length();
474 if(src[cur_args_str_pos++] == '(')
475 {
476 int nested_parentheses = 0;
477 ptrdiff_t cur_arg_pos = cur_args_str_pos;
478 ptrdiff_t cur_arg_length = 0;
479
480 args_str_length++;
481 while(src[cur_args_str_pos] != ')' || nested_parentheses != 0)
482 {
483 switch(src[cur_args_str_pos++])
484 {
485 case '(':
486 nested_parentheses++;
487 cur_arg_length++;
488 break;
489 case ',':
490 if(nested_parentheses == 0)
491 {
492 args_list.push_back(src.substr(cur_arg_pos, cur_arg_length));
493 cur_arg_pos = cur_args_str_pos;
494 cur_arg_length = 0;
495 }
496 else
497 {
498 cur_arg_length++;
499 }
500 break;
501 case ' ':
502 case '\t':
503 if(cur_arg_length == 0)
504 {
505 cur_arg_pos++;
506 }
507 else
508 {
509 cur_arg_length++;
510 }
511 break;
512 case ')':
513 nested_parentheses--;
514 // no break here!
515 default:
516 cur_arg_length++;
517 break;
518 }
519 args_str_length++;
520 }
521 if(src[cur_args_str_pos] == ')' && nested_parentheses == 0)
522 {
523 args_list.push_back(src.substr(cur_arg_pos, cur_arg_length));
524 }
525 args_str_length++;
526 }
527
528 std::string expanded_content = match.str();
529 const std::vector<std::string> macro_param_list = macro_definitions.at(match.str()).param_list;
530
531 if((nested_level != 0 || !macro_param_list.empty()) && macro_param_list.size() == args_list.size())
532 {
533 parsed_pos += args_str_length;
534 expanded_content = macro_definitions.at(match.str()).content;
535 size_t i = 0;
536 for(auto &param_name : macro_param_list)
537 {
538 std::regex params_regex(R"(\b)" + param_name + R"(\b)");
539 expanded_content.assign(std::regex_replace(expanded_content, params_regex, args_list[i]));
540 ++i;
541 }
542 // Expand macro recursively
543 expanded_content = cs_parser(expanded_content, stage, nested_level + 1);
544
545 if(nested_level == 0)
546 {
547 const std::regex token_pasting_rgx = std::regex(R"(\b##\b)");
548 if(std::regex_search(expanded_content, token_pasting_rgx))
549 {
550 // Remove token pasting operator "##"
551 expanded_content.assign(std::regex_replace(expanded_content, std::regex(token_pasting_rgx), ""));
552 // Trim trailing whitespace
553 expanded_content.assign(std::regex_replace(expanded_content, std::regex(R"([ \t]*\\\n)"), "\n"));
554 }
555 else
556 {
557 // Do not expand the macro if the result does not have token pasting operator "##"
558 expanded_content = src.substr(match.position(), match.length() + args_str_length);
559 }
560 }
561 }
562 dst.append(expanded_content);
563 break;
564 }
565 case ParserStage::SKIP_COMMENTS:
566 case ParserStage::SKIP_PREPROCESSOR_DIRECTIVES:
567 default:
568 dst.append(match.str());
569 break;
570 }
571 next_stage = stage;
572 }
573 dst.append(cs_parser(src.substr(parsed_pos, src.length() - parsed_pos), next_stage, 0));
574
575 return dst;
576 };
577
578 return cs_parser(shader_source, ParserStage::FIRST, 0);
579}
580
581const GCProgram &GCKernelLibrary::load_program(const std::string &program_name) const
582{
583 const auto program_it = _programs_map.find(program_name);
584
585 if(program_it != _programs_map.end())
586 {
587 return program_it->second;
588 }
589
590 GCProgram program;
591
592#ifdef EMBEDDED_KERNELS
593 const auto program_source_it = _program_source_map.find(program_name);
594
595 if(_program_source_map.end() == program_source_it)
596 {
597 ARM_COMPUTE_ERROR("Embedded program for %s does not exist.", program_name.c_str());
598 }
599
600 // TODO(APPBROWSER-298): Do not call shader preprocessor here
601 // We should do the preprocess at compile time
602 // The preprocess_shader function is used for support "#include" directive and token pasting operator "##".
603 // This job could be done at compile time by using a python script in order to get better performance at runtime.
604 // BTW: We usually defined EMBEDDED_KERNELS in release build.
605 program = GCProgram(program_name, preprocess_shader(program_source_it->second));
606#else /* EMBEDDED_KERNELS */
607 // Check for binary
608 std::string source_name = _shader_path + program_name;
609 if(std::ifstream(source_name).is_open())
610 {
611 program = GCProgram(program_name, preprocess_shader(read_file(source_name, false)));
612 }
613 else
614 {
615 ARM_COMPUTE_ERROR("Shader file %s does not exist.", source_name.c_str());
616 }
617#endif /* EMBEDDED_KERNELS */
618
619 // Insert program to program map
620 const auto new_program = _programs_map.emplace(program_name, std::move(program));
621
622 return new_program.first->second;
623}
624
625void GCKernelLibrary::setup_context()
626{
627 EGLBoolean res;
628 _display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
629
630 ARM_COMPUTE_ERROR_ON_MSG(_display == EGL_NO_DISPLAY, "Failed to get display: 0x%x.", eglGetError());
631
632 res = eglInitialize(_display, nullptr, nullptr);
633
634 ARM_COMPUTE_ERROR_ON_MSG(res == EGL_FALSE, "Failed to initialize egl: 0x%x.", eglGetError());
635 ARM_COMPUTE_UNUSED(res);
636
637 const char *egl_extension_st = eglQueryString(_display, EGL_EXTENSIONS);
638 ARM_COMPUTE_ERROR_ON_MSG((strstr(egl_extension_st, "EGL_KHR_create_context") == nullptr), "Failed to query EGL_KHR_create_context");
639 ARM_COMPUTE_ERROR_ON_MSG((strstr(egl_extension_st, "EGL_KHR_surfaceless_context") == nullptr), "Failed to query EGL_KHR_surfaceless_context");
640 ARM_COMPUTE_UNUSED(egl_extension_st);
641
642 const EGLint config_attribs[] =
643 {
644 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
645 EGL_NONE
646 };
647 EGLConfig cfg;
648 EGLint count;
649
650 res = eglChooseConfig(_display, config_attribs, &cfg, 1, &count);
651
652 ARM_COMPUTE_ERROR_ON_MSG(res == EGL_FALSE, "Failed to choose config: 0x%x.", eglGetError());
653 ARM_COMPUTE_UNUSED(res);
654
655 res = eglBindAPI(EGL_OPENGL_ES_API);
656
657 ARM_COMPUTE_ERROR_ON_MSG(res == EGL_FALSE, "Failed to bind api: 0x%x.", eglGetError());
658
659 const EGLint attribs[] =
660 {
661 EGL_CONTEXT_CLIENT_VERSION, 3,
662 EGL_NONE
663 };
664 _context = eglCreateContext(_display,
665 cfg,
666 EGL_NO_CONTEXT,
667 attribs);
668
669 ARM_COMPUTE_ERROR_ON_MSG(_context == EGL_NO_CONTEXT, "Failed to create context: 0x%x.", eglGetError());
670 ARM_COMPUTE_UNUSED(res);
671
672 res = eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, _context);
673
674 ARM_COMPUTE_ERROR_ON_MSG(res == EGL_FALSE, "Failed to make current: 0x%x.", eglGetError());
675 ARM_COMPUTE_UNUSED(res);
676}
677
678void GCKernelLibrary::setup_dummy_fbo()
679{
680 ARM_COMPUTE_GL_CHECK(glGenFramebuffers(1, &_frame_buffer));
681 ARM_COMPUTE_GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, _frame_buffer));
682 ARM_COMPUTE_GL_CHECK(glGenTextures(1, &_tex_rt));
683 ARM_COMPUTE_GL_CHECK(glBindTexture(GL_TEXTURE_2D, _tex_rt));
684 ARM_COMPUTE_GL_CHECK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr));
685 ARM_COMPUTE_GL_CHECK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _tex_rt, 0));
686}
687
688GCKernelLibrary::~GCKernelLibrary()
689{
690 for(auto &program : _built_programs_map)
691 {
692 static_cast<GCKernel>(program.second).cleanup();
693 }
694
695 ARM_COMPUTE_GL_CHECK(glBindTexture(GL_TEXTURE_2D, 0));
696 ARM_COMPUTE_GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
697 ARM_COMPUTE_GL_CHECK(glDeleteTextures(1, &_tex_rt));
698 ARM_COMPUTE_GL_CHECK(glDeleteFramebuffers(1, &_frame_buffer));
699
700 if(_own_context)
701 {
702 eglDestroyContext(_display, _context);
703 eglTerminate(_display);
704
705 _context = EGL_NO_CONTEXT;
706 _display = EGL_NO_DISPLAY;
707 }
708}
709
710std::string GCKernelLibrary::stringify_set(const StringSet &s) const
711{
712 std::string concat_set;
713
714 // Concatenate set
715 for(const auto &el : s)
716 {
717 concat_set += el + "\n";
718 }
719
720 return concat_set;
721}