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