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 <stdint.h>
18
19#include <log/log.h>
20#include <utils/String8.h>
21
22#include "Program.h"
23#include "ProgramCache.h"
24#include "Description.h"
25
26namespace android {
27
28Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const char* fragment)
29        : mInitialized(false) {
30    GLuint vertexId = buildShader(vertex, GL_VERTEX_SHADER);
31    GLuint fragmentId = buildShader(fragment, GL_FRAGMENT_SHADER);
32    GLuint programId = glCreateProgram();
33    glAttachShader(programId, vertexId);
34    glAttachShader(programId, fragmentId);
35    glBindAttribLocation(programId, position, "position");
36    glBindAttribLocation(programId, texCoords, "texCoords");
37    glLinkProgram(programId);
38
39    GLint status;
40    glGetProgramiv(programId, GL_LINK_STATUS, &status);
41    if (status != GL_TRUE) {
42        ALOGE("Error while linking shaders:");
43        GLint infoLen = 0;
44        glGetProgramiv(programId, GL_INFO_LOG_LENGTH, &infoLen);
45        if (infoLen > 1) {
46            GLchar log[infoLen];
47            glGetProgramInfoLog(programId, infoLen, 0, &log[0]);
48            ALOGE("%s", log);
49        }
50        glDetachShader(programId, vertexId);
51        glDetachShader(programId, fragmentId);
52        glDeleteShader(vertexId);
53        glDeleteShader(fragmentId);
54        glDeleteProgram(programId);
55    } else {
56        mProgram = programId;
57        mVertexShader = vertexId;
58        mFragmentShader = fragmentId;
59        mInitialized = true;
60
61        mColorMatrixLoc = glGetUniformLocation(programId, "colorMatrix");
62        mProjectionMatrixLoc = glGetUniformLocation(programId, "projection");
63        mTextureMatrixLoc = glGetUniformLocation(programId, "texture");
64        mSamplerLoc = glGetUniformLocation(programId, "sampler");
65        mColorLoc = glGetUniformLocation(programId, "color");
66        mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane");
67
68        // set-up the default values for our uniforms
69        glUseProgram(programId);
70        const GLfloat m[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
71        glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, m);
72        glEnableVertexAttribArray(0);
73    }
74}
75
76Program::~Program() {
77}
78
79bool Program::isValid() const {
80    return mInitialized;
81}
82
83void Program::use() {
84    glUseProgram(mProgram);
85}
86
87GLuint Program::getAttrib(const char* name) const {
88    // TODO: maybe use a local cache
89    return glGetAttribLocation(mProgram, name);
90}
91
92GLint Program::getUniform(const char* name) const {
93    // TODO: maybe use a local cache
94    return glGetUniformLocation(mProgram, name);
95}
96
97GLuint Program::buildShader(const char* source, GLenum type) {
98    GLuint shader = glCreateShader(type);
99    glShaderSource(shader, 1, &source, 0);
100    glCompileShader(shader);
101    GLint status;
102    glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
103    if (status != GL_TRUE) {
104        // Some drivers return wrong values for GL_INFO_LOG_LENGTH
105        // use a fixed size instead
106        GLchar log[512];
107        glGetShaderInfoLog(shader, sizeof(log), 0, log);
108        ALOGE("Error while compiling shader: \n%s\n%s", source, log);
109        glDeleteShader(shader);
110        return 0;
111    }
112    return shader;
113}
114
115String8& Program::dumpShader(String8& result, GLenum /*type*/) {
116    GLuint shader = GL_FRAGMENT_SHADER ? mFragmentShader : mVertexShader;
117    GLint l;
118    glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &l);
119    char* src = new char[l];
120    glGetShaderSource(shader, l, NULL, src);
121    result.append(src);
122    delete [] src;
123    return result;
124}
125
126void Program::setUniforms(const Description& desc) {
127
128    // TODO: we should have a mechanism here to not always reset uniforms that
129    // didn't change for this program.
130
131    if (mSamplerLoc >= 0) {
132        glUniform1i(mSamplerLoc, 0);
133        glUniformMatrix4fv(mTextureMatrixLoc, 1, GL_FALSE, desc.mTexture.getMatrix().asArray());
134    }
135    if (mAlphaPlaneLoc >= 0) {
136        glUniform1f(mAlphaPlaneLoc, desc.mPlaneAlpha);
137    }
138    if (mColorLoc >= 0) {
139        glUniform4fv(mColorLoc, 1, desc.mColor);
140    }
141    if (mColorMatrixLoc >= 0) {
142        glUniformMatrix4fv(mColorMatrixLoc, 1, GL_FALSE, desc.mColorMatrix.asArray());
143    }
144    // these uniforms are always present
145    glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray());
146}
147
148} /* namespace android */
149