blob: 2d366006fde2a5051177b4576e3d2bdcc7b85fb0 [file] [log] [blame]
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08001#include "include/private/dvr/graphics/shader_program.h"
2
3#include <regex>
4#include <sstream>
5
Alex Vakulenko4fe60582017-02-02 11:35:59 -08006#include <log/log.h>
Alex Vakulenkoe4eec202017-01-27 14:41:04 -08007
8namespace {
9
10static bool CompileShader(GLuint shader, const std::string& shader_string) {
Alex Vakulenko4fe60582017-02-02 11:35:59 -080011 std::string prefix;
12 const std::string kVersion = "#version";
13 if (shader_string.substr(0, kVersion.size()) != kVersion) {
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080014 prefix = "#version 310 es\n";
15 }
16 std::string string_with_prefix = prefix + shader_string;
17 const char* shader_str[] = {string_with_prefix.data()};
18 glShaderSource(shader, 1, shader_str, nullptr);
19 glCompileShader(shader);
20
21 GLint success;
22 glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
23 if (!success) {
24 GLchar infoLog[512];
25 glGetShaderInfoLog(shader, 512, nullptr, infoLog);
Alex Vakulenko4fe60582017-02-02 11:35:59 -080026 ALOGE("Shader Failed to compile: %s -- %s", *shader_str, infoLog);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080027 return false;
28 }
29 return true;
30}
31
32static bool LinkProgram(GLuint program, GLuint vertex_shader,
33 GLuint fragment_shader) {
34 glAttachShader(program, vertex_shader);
35 glAttachShader(program, fragment_shader);
36 glLinkProgram(program);
37
38 // Check for linking errors
39 GLint success;
40 glGetProgramiv(program, GL_LINK_STATUS, &success);
41 if (!success) {
42 GLchar infoLog[512];
43 glGetProgramInfoLog(program, 512, nullptr, infoLog);
Alex Vakulenko4fe60582017-02-02 11:35:59 -080044 ALOGE("Shader failed to link: %s", infoLog);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080045 return false;
46 }
47
48 return true;
49}
50
51static bool LinkProgram(GLuint program, GLuint compute_shader) {
52 glAttachShader(program, compute_shader);
53 glLinkProgram(program);
54
55 // Check for linking errors
56 GLint success;
57 glGetProgramiv(program, GL_LINK_STATUS, &success);
58 if (!success) {
59 GLchar infoLog[512];
60 glGetProgramInfoLog(program, 512, nullptr, infoLog);
Alex Vakulenko4fe60582017-02-02 11:35:59 -080061 ALOGE("Shader failed to link: %s", infoLog);
Alex Vakulenkoe4eec202017-01-27 14:41:04 -080062 return false;
63 }
64
65 return true;
66}
67
68} // anonymous namespace
69
70namespace android {
71namespace dvr {
72
73ShaderProgram::ShaderProgram() : program_(0) {}
74
75ShaderProgram::ShaderProgram(const std::string& vertext_source,
76 const std::string& fragment_source)
77 : program_(0) {
78 Link(vertext_source, fragment_source);
79}
80
81ShaderProgram::ShaderProgram(ShaderProgram&& to_move) {
82 std::swap(program_, to_move.program_);
83}
84
85ShaderProgram::~ShaderProgram() {
86 if (program_)
87 glDeleteProgram(program_);
88}
89
90ShaderProgram& ShaderProgram::operator=(ShaderProgram&& to_move) {
91 std::swap(program_, to_move.program_);
92 return *this;
93}
94
95void ShaderProgram::Link(const std::string& vertext_source,
96 const std::string& fragment_source) {
97 if (program_)
98 glDeleteProgram(program_);
99 program_ = glCreateProgram();
100 GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
101 GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
102
103 bool success = CompileShader(vertex_shader, vertext_source) &&
104 CompileShader(fragment_shader, fragment_source) &&
105 LinkProgram(program_, vertex_shader, fragment_shader);
106
107 glDeleteShader(vertex_shader);
108 glDeleteShader(fragment_shader);
109
110 if (!success) {
111 glDeleteProgram(program_);
112 program_ = 0;
113 }
114}
115
116void ShaderProgram::Link(const std::string& compute_source) {
117 if (program_)
118 glDeleteProgram(program_);
119 program_ = glCreateProgram();
120 GLuint shader = glCreateShader(GL_COMPUTE_SHADER);
121
122 bool success =
123 CompileShader(shader, compute_source) && LinkProgram(program_, shader);
124
125 glDeleteShader(shader);
126
127 if (!success) {
128 glDeleteProgram(program_);
129 program_ = 0;
130 }
131}
132
133void ShaderProgram::Use() const { glUseProgram(program_); }
134
135std::string ComposeShader(const std::string& shader_code,
136 const std::vector<std::string>& variables) {
137 std::stringstream result_stream;
138 std::regex expression("%([0-9]*)");
139 using reg_iter = std::regex_token_iterator<std::string::const_iterator>;
140 reg_iter rend;
141 // match the string and number (drop the %)
142 std::vector<int> submatches = {-1, 1};
143 reg_iter reg(shader_code.begin(), shader_code.end(), expression, submatches);
144 bool is_even = true;
145 while (reg != rend) {
146 if (is_even) {
147 // even entries is the code between the %n's
148 result_stream << *reg;
149 } else {
150 // odd entries are the index into the passed in variables.
151 size_t i = static_cast<size_t>(std::stoi(*reg));
152 if (i < variables.size()) {
153 result_stream << variables[i];
154 }
155 }
156 is_even = !is_even;
157 ++reg;
158 }
159 return result_stream.str();
160}
161
162} // namespace dvr
163} // namespace android