Program.cpp revision f3a910b423db7ad79cf61518bdd9278c048ad0d8
1/* 2 * Copyright (C) 2010 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#define LOG_TAG "OpenGLRenderer" 18 19#include "Program.h" 20 21namespace android { 22namespace uirenderer { 23 24/////////////////////////////////////////////////////////////////////////////// 25// Base program 26/////////////////////////////////////////////////////////////////////////////// 27 28// TODO: Program instance should be created from a factory method 29Program::Program(const ProgramDescription& description, const char* vertex, const char* fragment) { 30 mInitialized = false; 31 mHasColorUniform = false; 32 mUse = false; 33 34 // No need to cache compiled shaders, rely instead on Android's 35 // persistent shaders cache 36 mVertexShader = buildShader(vertex, GL_VERTEX_SHADER); 37 if (mVertexShader) { 38 mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 39 if (mFragmentShader) { 40 mProgramId = glCreateProgram(); 41 42 glAttachShader(mProgramId, mVertexShader); 43 glAttachShader(mProgramId, mFragmentShader); 44 45 position = bindAttrib("position", kBindingPosition); 46 if (description.hasTexture || description.hasExternalTexture) { 47 texCoords = bindAttrib("texCoords", kBindingTexCoords); 48 } else { 49 texCoords = -1; 50 } 51 52 glLinkProgram(mProgramId); 53 54 GLint status; 55 glGetProgramiv(mProgramId, GL_LINK_STATUS, &status); 56 if (status != GL_TRUE) { 57 LOGE("Error while linking shaders:"); 58 GLint infoLen = 0; 59 glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen); 60 if (infoLen > 1) { 61 GLchar log[infoLen]; 62 glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]); 63 LOGE("%s", log); 64 } 65 66 glDetachShader(mProgramId, mVertexShader); 67 glDetachShader(mProgramId, mFragmentShader); 68 69 glDeleteShader(mVertexShader); 70 glDeleteShader(mFragmentShader); 71 72 glDeleteProgram(mProgramId); 73 } else { 74 mInitialized = true; 75 } 76 } else { 77 glDeleteShader(mVertexShader); 78 } 79 } 80 81 if (mInitialized) { 82 transform = addUniform("transform"); 83 } 84} 85 86Program::~Program() { 87 if (mInitialized) { 88 glDetachShader(mProgramId, mVertexShader); 89 glDetachShader(mProgramId, mFragmentShader); 90 91 glDeleteShader(mVertexShader); 92 glDeleteShader(mFragmentShader); 93 94 glDeleteProgram(mProgramId); 95 } 96} 97 98int Program::addAttrib(const char* name) { 99 int slot = glGetAttribLocation(mProgramId, name); 100 mAttributes.add(name, slot); 101 return slot; 102} 103 104int Program::bindAttrib(const char* name, ShaderBindings bindingSlot) { 105 glBindAttribLocation(mProgramId, bindingSlot, name); 106 mAttributes.add(name, bindingSlot); 107 return bindingSlot; 108} 109 110int Program::getAttrib(const char* name) { 111 ssize_t index = mAttributes.indexOfKey(name); 112 if (index >= 0) { 113 return mAttributes.valueAt(index); 114 } 115 return addAttrib(name); 116} 117 118int Program::addUniform(const char* name) { 119 int slot = glGetUniformLocation(mProgramId, name); 120 mUniforms.add(name, slot); 121 return slot; 122} 123 124int Program::getUniform(const char* name) { 125 ssize_t index = mUniforms.indexOfKey(name); 126 if (index >= 0) { 127 return mUniforms.valueAt(index); 128 } 129 return addUniform(name); 130} 131 132GLuint Program::buildShader(const char* source, GLenum type) { 133 GLuint shader = glCreateShader(type); 134 glShaderSource(shader, 1, &source, 0); 135 glCompileShader(shader); 136 137 GLint status; 138 glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 139 if (status != GL_TRUE) { 140 // Some drivers return wrong values for GL_INFO_LOG_LENGTH 141 // use a fixed size instead 142 GLchar log[512]; 143 glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]); 144 LOGE("Error while compiling shader: %s", log); 145 glDeleteShader(shader); 146 return 0; 147 } 148 149 return shader; 150} 151 152void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, 153 const mat4& transformMatrix, bool offset) { 154 mat4 t(projectionMatrix); 155 if (offset) { 156 // offset screenspace xy by an amount that compensates for typical precision 157 // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted 158 // up and to the left. 159 // This offset value is based on an assumption that some hardware may use as 160 // little as 12.4 precision, so we offset by slightly more than 1/16. 161 t.translate(.375, .375, 0); 162 } 163 t.multiply(transformMatrix); 164 t.multiply(modelViewMatrix); 165 166 glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); 167} 168 169void Program::setColor(const float r, const float g, const float b, const float a) { 170 if (!mHasColorUniform) { 171 mColorUniform = getUniform("color"); 172 mHasColorUniform = true; 173 } 174 glUniform4f(mColorUniform, r, g, b, a); 175} 176 177void Program::use() { 178 glUseProgram(mProgramId); 179 mUse = true; 180} 181 182void Program::remove() { 183 mUse = false; 184} 185 186}; // namespace uirenderer 187}; // namespace android 188