1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "shader.h"
17
18 #include <EGL/egl.h>
19 #include <GLES2/gl2.h>
20 #include <gslogger.h>
21
22 namespace {
23 DEFINE_HILOG_LABEL("Shader");
24 } // namespace
25
Shader(const std::string & vertexSource,const std::string & fragmentSource)26 Shader::Shader(const std::string& vertexSource, const std::string& fragmentSource)
27 {
28 rendererID_ = CreateShader(vertexSource, fragmentSource);
29 }
30
~Shader()31 Shader::~Shader()
32 {
33 if (rendererID_ != 0) {
34 glDeleteProgram(rendererID_);
35 }
36 }
37
Available()38 bool Shader::Available()
39 {
40 return rendererID_ != 0;
41 }
42
Bind() const43 void Shader::Bind() const
44 {
45 glUseProgram(rendererID_);
46 }
47
Unbind() const48 void Shader::Unbind() const
49 {
50 glUseProgram(0);
51 }
52
SetUniform1i(const std::string & name,int32_t v)53 void Shader::SetUniform1i(const std::string& name, int32_t v)
54 {
55 glUniform1i(GetUniformLocation(name), v);
56 }
57
SetUniform1f(const std::string & name,float v)58 void Shader::SetUniform1f(const std::string& name, float v)
59 {
60 glUniform1f(GetUniformLocation(name), v);
61 }
62
SetUniform4f(const std::string & name,float v0,float v1,float v2,float v3)63 void Shader::SetUniform4f(const std::string& name, float v0, float v1, float v2, float v3)
64 {
65 glUniform4f(GetUniformLocation(name), v0, v1, v2, v3);
66 }
67
SetUniformMat4f(const std::string & name,const Matrix<float> & matrix)68 void Shader::SetUniformMat4f(const std::string& name, const Matrix<float>& matrix)
69 {
70 glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, matrix);
71 }
72
GetAttribLocation(const std::string & name)73 int32_t Shader::GetAttribLocation(const std::string& name)
74 {
75 return glGetAttribLocation(rendererID_, name.c_str());
76 }
77
GetUniformLocation(const std::string & name)78 int32_t Shader::GetUniformLocation(const std::string& name)
79 {
80 if (uniformLocationCache_.find(name) != uniformLocationCache_.end()) {
81 return uniformLocationCache_[name];
82 }
83 auto location = glGetUniformLocation(rendererID_, name.c_str());
84 if (location == -1) {
85 GSLOG2HI(WARN) << "Warning: uniform '" << name << "' doesn't exist!" << std::endl;
86 }
87
88 uniformLocationCache_[name] = location;
89 return location;
90 }
91
CompileShader(uint32_t type,const std::string & source)92 uint32_t Shader::CompileShader(uint32_t type, const std::string& source)
93 {
94 auto id = glCreateShader(type);
95 auto src = source.c_str();
96 glShaderSource(id, 1, &src, nullptr);
97 glCompileShader(id);
98
99 auto result = GL_FALSE;
100 glGetShaderiv(id, GL_COMPILE_STATUS, &result);
101 if (result == GL_FALSE) {
102 int32_t length = 0;
103 glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
104 if (length < 0) {
105 GSLOG2HI(ERROR) << "CompileShader Failed length is not right";
106 return 0;
107 }
108 char* message = static_cast<char*>(malloc(length));
109 if (message == nullptr) {
110 GSLOG2HI(ERROR) << "CompileShader Failed malloc failed";
111 return 0;
112 }
113 glGetShaderInfoLog(id, length, &length, message);
114 GSLOG2HI(ERROR) << "CompileShader[" << type << "] Failed: " << message;
115 glDeleteShader(id);
116 free(message);
117 message = nullptr;
118 return 0;
119 }
120
121 return id;
122 }
123
CreateShader(const std::string & vertexShader,const std::string & fragmentShader)124 uint32_t Shader::CreateShader(const std::string& vertexShader, const std::string& fragmentShader)
125 {
126 auto program = glCreateProgram();
127 auto vs = CompileShader(GL_VERTEX_SHADER, vertexShader);
128 auto fs = CompileShader(GL_FRAGMENT_SHADER, fragmentShader);
129
130 glAttachShader(program, vs);
131 glAttachShader(program, fs);
132 glLinkProgram(program);
133 glDeleteShader(vs);
134 glDeleteShader(fs);
135
136 auto result = GL_FALSE;
137 glGetProgramiv(program, GL_LINK_STATUS, &result);
138 if (result == GL_FALSE) {
139 int32_t length = 0;
140 glGetProgramiv(program, GL_INFO_LOG_LENGTH, &length);
141 if (length < 0) {
142 GSLOG2HI(ERROR) << "CreateShader Failed length is not right";
143 return 0;
144 }
145 char* message = static_cast<char*>(malloc(length));
146 if (message == nullptr) {
147 GSLOG2HI(ERROR) << "CreateShader Failed malloc failed";
148 return 0;
149 }
150 glGetProgramInfoLog(program, length, nullptr, message);
151 GSLOG2HI(ERROR) << "program error[" << glGetError() << "]: " << message;
152 free(message);
153 message = nullptr;
154 return 0;
155 }
156
157 GSLOG2HI(INFO) << "Shader create success " << program;
158 return program;
159 }
160