15cbbce535744b89df5ecea95de21ee3733298260Romain Guy/* 25cbbce535744b89df5ecea95de21ee3733298260Romain Guy * Copyright (C) 2010 The Android Open Source Project 35cbbce535744b89df5ecea95de21ee3733298260Romain Guy * 45cbbce535744b89df5ecea95de21ee3733298260Romain Guy * Licensed under the Apache License, Version 2.0 (the "License"); 55cbbce535744b89df5ecea95de21ee3733298260Romain Guy * you may not use this file except in compliance with the License. 65cbbce535744b89df5ecea95de21ee3733298260Romain Guy * You may obtain a copy of the License at 75cbbce535744b89df5ecea95de21ee3733298260Romain Guy * 85cbbce535744b89df5ecea95de21ee3733298260Romain Guy * http://www.apache.org/licenses/LICENSE-2.0 95cbbce535744b89df5ecea95de21ee3733298260Romain Guy * 105cbbce535744b89df5ecea95de21ee3733298260Romain Guy * Unless required by applicable law or agreed to in writing, software 115cbbce535744b89df5ecea95de21ee3733298260Romain Guy * distributed under the License is distributed on an "AS IS" BASIS, 125cbbce535744b89df5ecea95de21ee3733298260Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135cbbce535744b89df5ecea95de21ee3733298260Romain Guy * See the License for the specific language governing permissions and 145cbbce535744b89df5ecea95de21ee3733298260Romain Guy * limitations under the License. 155cbbce535744b89df5ecea95de21ee3733298260Romain Guy */ 165cbbce535744b89df5ecea95de21ee3733298260Romain Guy 175cbbce535744b89df5ecea95de21ee3733298260Romain Guy#define LOG_TAG "OpenGLRenderer" 185cbbce535744b89df5ecea95de21ee3733298260Romain Guy 195cbbce535744b89df5ecea95de21ee3733298260Romain Guy#include "Program.h" 205cbbce535744b89df5ecea95de21ee3733298260Romain Guy 215cbbce535744b89df5ecea95de21ee3733298260Romain Guynamespace android { 225cbbce535744b89df5ecea95de21ee3733298260Romain Guynamespace uirenderer { 235cbbce535744b89df5ecea95de21ee3733298260Romain Guy 245cbbce535744b89df5ecea95de21ee3733298260Romain Guy/////////////////////////////////////////////////////////////////////////////// 255cbbce535744b89df5ecea95de21ee3733298260Romain Guy// Base program 265cbbce535744b89df5ecea95de21ee3733298260Romain Guy/////////////////////////////////////////////////////////////////////////////// 275cbbce535744b89df5ecea95de21ee3733298260Romain Guy 283e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy// TODO: Program instance should be created from a factory method 29f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain GuyProgram::Program(const ProgramDescription& description, const char* vertex, const char* fragment) { 3067f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy mInitialized = false; 3105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mHasColorUniform = false; 322d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mHasSampler = false; 333e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mUse = false; 345cbbce535744b89df5ecea95de21ee3733298260Romain Guy 3524edca8b526515979778e577191089a57f5277d7Romain Guy // No need to cache compiled shaders, rely instead on Android's 3624edca8b526515979778e577191089a57f5277d7Romain Guy // persistent shaders cache 373e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mVertexShader = buildShader(vertex, GL_VERTEX_SHADER); 383e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy if (mVertexShader) { 393e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 403e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy if (mFragmentShader) { 413e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mProgramId = glCreateProgram(); 4267f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy 433e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glAttachShader(mProgramId, mVertexShader); 443e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glAttachShader(mProgramId, mFragmentShader); 4567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy 463e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy position = bindAttrib("position", kBindingPosition); 47f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy if (description.hasTexture || description.hasExternalTexture) { 48f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy texCoords = bindAttrib("texCoords", kBindingTexCoords); 49f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy } else { 50f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy texCoords = -1; 51f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy } 52f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy 5305bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glLinkProgram(mProgramId); 5467f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy 5567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy GLint status; 5605bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glGetProgramiv(mProgramId, GL_LINK_STATUS, &status); 5767f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (status != GL_TRUE) { 583762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("Error while linking shaders:"); 5967f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy GLint infoLen = 0; 6005bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen); 6167f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (infoLen > 1) { 6267f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy GLchar log[infoLen]; 6305bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]); 643762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("%s", log); 6567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 6605bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy 673e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mVertexShader); 683e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mFragmentShader); 6905bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy 703e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mVertexShader); 713e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mFragmentShader); 7205bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy 7305bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glDeleteProgram(mProgramId); 743e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy } else { 753e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mInitialized = true; 7605bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } 7705bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } else { 783e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mVertexShader); 795cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 805cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 81260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy 8267f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (mInitialized) { 8367f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy transform = addUniform("transform"); 8467f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 855cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 865cbbce535744b89df5ecea95de21ee3733298260Romain Guy 875cbbce535744b89df5ecea95de21ee3733298260Romain GuyProgram::~Program() { 8867f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (mInitialized) { 893e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mVertexShader); 903e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mFragmentShader); 913e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 923e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mVertexShader); 933e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mFragmentShader); 943e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 9505bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glDeleteProgram(mProgramId); 9667f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 975cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 985cbbce535744b89df5ecea95de21ee3733298260Romain Guy 995cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::addAttrib(const char* name) { 10005bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy int slot = glGetAttribLocation(mProgramId, name); 10105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mAttributes.add(name, slot); 1025cbbce535744b89df5ecea95de21ee3733298260Romain Guy return slot; 1035cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1045cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1053e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guyint Program::bindAttrib(const char* name, ShaderBindings bindingSlot) { 1063e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glBindAttribLocation(mProgramId, bindingSlot, name); 1073e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mAttributes.add(name, bindingSlot); 1083e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy return bindingSlot; 1093e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy} 1103e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 1115cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::getAttrib(const char* name) { 11205bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy ssize_t index = mAttributes.indexOfKey(name); 113889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy if (index >= 0) { 11405bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy return mAttributes.valueAt(index); 115889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy } 116889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy return addAttrib(name); 1175cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1185cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1195cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::addUniform(const char* name) { 12005bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy int slot = glGetUniformLocation(mProgramId, name); 12105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mUniforms.add(name, slot); 1225cbbce535744b89df5ecea95de21ee3733298260Romain Guy return slot; 1235cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1245cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1255cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::getUniform(const char* name) { 12605bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy ssize_t index = mUniforms.indexOfKey(name); 127889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy if (index >= 0) { 12805bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy return mUniforms.valueAt(index); 129889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy } 130889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy return addUniform(name); 1315cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1325cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1335cbbce535744b89df5ecea95de21ee3733298260Romain GuyGLuint Program::buildShader(const char* source, GLenum type) { 1345cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLuint shader = glCreateShader(type); 1355cbbce535744b89df5ecea95de21ee3733298260Romain Guy glShaderSource(shader, 1, &source, 0); 1365cbbce535744b89df5ecea95de21ee3733298260Romain Guy glCompileShader(shader); 1375cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1385cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLint status; 1395cbbce535744b89df5ecea95de21ee3733298260Romain Guy glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 1405cbbce535744b89df5ecea95de21ee3733298260Romain Guy if (status != GL_TRUE) { 1415cbbce535744b89df5ecea95de21ee3733298260Romain Guy // Some drivers return wrong values for GL_INFO_LOG_LENGTH 1425cbbce535744b89df5ecea95de21ee3733298260Romain Guy // use a fixed size instead 1435cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLchar log[512]; 1445cbbce535744b89df5ecea95de21ee3733298260Romain Guy glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]); 1453762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("Error while compiling shader: %s", log); 1465cbbce535744b89df5ecea95de21ee3733298260Romain Guy glDeleteShader(shader); 14767f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy return 0; 1485cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 1495cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1505cbbce535744b89df5ecea95de21ee3733298260Romain Guy return shader; 1515cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1525cbbce535744b89df5ecea95de21ee3733298260Romain Guy 153889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, 1548a5cc92a150bae38ec43732d941b38bb381fe153Chet Haase const mat4& transformMatrix, bool offset) { 1550b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy mat4 t(projectionMatrix); 1568a5cc92a150bae38ec43732d941b38bb381fe153Chet Haase if (offset) { 15724edca8b526515979778e577191089a57f5277d7Romain Guy // offset screenspace xy by an amount that compensates for typical precision 15824edca8b526515979778e577191089a57f5277d7Romain Guy // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted 15924edca8b526515979778e577191089a57f5277d7Romain Guy // up and to the left. 16024edca8b526515979778e577191089a57f5277d7Romain Guy // This offset value is based on an assumption that some hardware may use as 16124edca8b526515979778e577191089a57f5277d7Romain Guy // little as 12.4 precision, so we offset by slightly more than 1/16. 1628a5cc92a150bae38ec43732d941b38bb381fe153Chet Haase t.translate(.375, .375, 0); 1638a5cc92a150bae38ec43732d941b38bb381fe153Chet Haase } 1640b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy t.multiply(transformMatrix); 1650b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy t.multiply(modelViewMatrix); 1660b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy 1670b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); 1685cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1695cbbce535744b89df5ecea95de21ee3733298260Romain Guy 170707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guyvoid Program::setColor(const float r, const float g, const float b, const float a) { 17105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy if (!mHasColorUniform) { 17205bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mColorUniform = getUniform("color"); 1736752d0ab029a185a42e34e7a933b669e6ed19e89Romain Guy mHasColorUniform = true; 17405bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } 17505bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glUniform4f(mColorUniform, r, g, b, a); 176707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy} 177707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy 178889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::use() { 17905bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glUseProgram(mProgramId); 1802d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy if (texCoords >= 0 && !mHasSampler) { 1812d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy glUniform1i(getUniform("sampler"), 0); 1822d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mHasSampler = true; 1832d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy } 184889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy mUse = true; 185f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy} 186f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy 187889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::remove() { 188889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy mUse = false; 189f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy} 190f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy 1915cbbce535744b89df5ecea95de21ee3733298260Romain Guy}; // namespace uirenderer 1925cbbce535744b89df5ecea95de21ee3733298260Romain Guy}; // namespace android 193