1 /*Gluint
2  * Copyright 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "Program.h"
18 
19 #include <stdint.h>
20 
21 #include <log/log.h>
22 #include <math/mat4.h>
23 #include <utils/String8.h>
24 #include "ProgramCache.h"
25 
26 namespace android {
27 namespace renderengine {
28 namespace gl {
29 
Program(const ProgramCache::Key &,const char * vertex,const char * fragment)30 Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
31       : mInitialized(false) {
32     GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
33     GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
34     GLuint programId = glCreateProgram();
35     glAttachShader(programId, vertexId);
36     glAttachShader(programId, fragmentId);
37     glBindAttribLocation(programId, position, "position");
38     glBindAttribLocation(programId, texCoords, "texCoords");
39     glBindAttribLocation(programId, cropCoords, "cropCoords");
40     glBindAttribLocation(programId, shadowColor, "shadowColor");
41     glBindAttribLocation(programId, shadowParams, "shadowParams");
42     glLinkProgram(programId);
43 
44     GLint status;
45     glGetProgramiv(programId, GL_LINK_STATUS, &status);
46     if (status != GL_TRUE) {
47         ALOGE("Error while linking shaders:");
48         GLint infoLen = 0;
49         glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &infoLen);
50         if (infoLen > 1) {
51             GLchar log[infoLen];
52             glGetProgramInfoLog(programId, infoLen, 0, &log[0]);
53             ALOGE("%s", log);
54         }
55         glDetachShader(programId, vertexId);
56         glDetachShader(programId, fragmentId);
57         glDeleteShader(vertexId);
58         glDeleteShader(fragmentId);
59         glDeleteProgram(programId);
60     } else {
61         mProgram = programId;
62         mVertexShader = vertexId;
63         mFragmentShader = fragmentId;
64         mInitialized = true;
65         mProjectionMatrixLoc = glGetUniformLocation(programId, "projection");
66         mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
67         mSamplerLoc = glGetUniformLocation(programId, "sampler");
68         mColorLoc = glGetUniformLocation(programId, "color");
69         mDisplayMaxLuminanceLoc = glGetUniformLocation(programId, "displayMaxLuminance");
70         mMaxMasteringLuminanceLoc = glGetUniformLocation(programId, "maxMasteringLuminance");
71         mMaxContentLuminanceLoc = glGetUniformLocation(programId, "maxContentLuminance");
72         mInputTransformMatrixLoc = glGetUniformLocation(programId, "inputTransformMatrix");
73         mOutputTransformMatrixLoc = glGetUniformLocation(programId, "outputTransformMatrix");
74         mCornerRadiusLoc = glGetUniformLocation(programId, "cornerRadius");
75         mCropCenterLoc = glGetUniformLocation(programId, "cropCenter");
76 
77         // set-up the default values for our uniforms
78         glUseProgram(programId);
79         glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, mat4().asArray());
80         glEnableVertexAttribArray(0);
81     }
82 }
83 
isValid() const84 bool Program::isValid() const {
85     return mInitialized;
86 }
87 
use()88 void Program::use() {
89     glUseProgram(mProgram);
90 }
91 
getAttrib(const char * name) const92 GLuint Program::getAttrib(const char* name) const {
93     // TODO: maybe use a local cache
94     return glGetAttribLocation(mProgram, name);
95 }
96 
getUniform(const char * name) const97 GLint Program::getUniform(const char* name) const {
98     // TODO: maybe use a local cache
99     return glGetUniformLocation(mProgram, name);
100 }
101 
buildShader(const char * source,GLenum type)102 GLuint Program::buildShader(const char* source, GLenum type) {
103     GLuint shader = glCreateShader(type);
104     glShaderSource(shader, 1, &source, 0);
105     glCompileShader(shader);
106     GLint status;
107     glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
108     if (status != GL_TRUE) {
109         // Some drivers return wrong values for GL_INFO_LOG_LENGTH
110         // use a fixed size instead
111         GLchar log[512];
112         glGetShaderInfoLog(shader, sizeof(log), 0, log);
113         ALOGE("Error while compiling shader: \n%s\n%s", source, log);
114         glDeleteShader(shader);
115         return 0;
116     }
117     return shader;
118 }
119 
setUniforms(const Description & desc)120 void Program::setUniforms(const Description& desc) {
121     // TODO: we should have a mechanism here to not always reset uniforms that
122     // didn't change for this program.
123 
124     if (mSamplerLoc >= 0) {
125         glUniform1i(mSamplerLoc, 0);
126         glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.texture.getMatrix().asArray());
127     }
128     if (mColorLoc >= 0) {
129         const float color[4] = {desc.color.r, desc.color.g, desc.color.b, desc.color.a};
130         glUniform4fv(mColorLoc, 1, color);
131     }
132     if (mInputTransformMatrixLoc >= 0) {
133         mat4 inputTransformMatrix = desc.inputTransformMatrix;
134         glUniformMatrix4fv(mInputTransformMatrixLoc, 1, GL_FALSE, inputTransformMatrix.asArray());
135     }
136     if (mOutputTransformMatrixLoc >= 0) {
137         // The output transform matrix and color matrix can be combined as one matrix
138         // that is applied right before applying OETF.
139         mat4 outputTransformMatrix = desc.colorMatrix * desc.outputTransformMatrix;
140         glUniformMatrix4fv(mOutputTransformMatrixLoc, 1, GL_FALSE, outputTransformMatrix.asArray());
141     }
142     if (mDisplayMaxLuminanceLoc >= 0) {
143         glUniform1f(mDisplayMaxLuminanceLoc, desc.displayMaxLuminance);
144     }
145     if (mMaxMasteringLuminanceLoc >= 0) {
146         glUniform1f(mMaxMasteringLuminanceLoc, desc.maxMasteringLuminance);
147     }
148     if (mMaxContentLuminanceLoc >= 0) {
149         glUniform1f(mMaxContentLuminanceLoc, desc.maxContentLuminance);
150     }
151     if (mCornerRadiusLoc >= 0) {
152         glUniform1f(mCornerRadiusLoc, desc.cornerRadius);
153     }
154     if (mCropCenterLoc >= 0) {
155         glUniform2f(mCropCenterLoc, desc.cropSize.x / 2.0f, desc.cropSize.y / 2.0f);
156     }
157     // these uniforms are always present
158     glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.projectionMatrix.asArray());
159 }
160 
161 } // namespace gl
162 } // namespace renderengine
163 } // namespace android
164