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" 183b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#define ATRACE_TAG ATRACE_TAG_VIEW 193b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 203b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy#include <utils/Trace.h> 215cbbce535744b89df5ecea95de21ee3733298260Romain Guy 225cbbce535744b89df5ecea95de21ee3733298260Romain Guy#include "Program.h" 2332f05e343c5ffb17f3235942bcda651bd3b9f1d6Chris Craik#include "Vertex.h" 245cbbce535744b89df5ecea95de21ee3733298260Romain Guy 255cbbce535744b89df5ecea95de21ee3733298260Romain Guynamespace android { 265cbbce535744b89df5ecea95de21ee3733298260Romain Guynamespace uirenderer { 275cbbce535744b89df5ecea95de21ee3733298260Romain Guy 285cbbce535744b89df5ecea95de21ee3733298260Romain Guy/////////////////////////////////////////////////////////////////////////////// 295cbbce535744b89df5ecea95de21ee3733298260Romain Guy// Base program 305cbbce535744b89df5ecea95de21ee3733298260Romain Guy/////////////////////////////////////////////////////////////////////////////// 315cbbce535744b89df5ecea95de21ee3733298260Romain Guy 32f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain GuyProgram::Program(const ProgramDescription& description, const char* vertex, const char* fragment) { 3367f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy mInitialized = false; 3405bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mHasColorUniform = false; 352d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mHasSampler = false; 363e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mUse = false; 375cbbce535744b89df5ecea95de21ee3733298260Romain Guy 3824edca8b526515979778e577191089a57f5277d7Romain Guy // No need to cache compiled shaders, rely instead on Android's 3924edca8b526515979778e577191089a57f5277d7Romain Guy // persistent shaders cache 403e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mVertexShader = buildShader(vertex, GL_VERTEX_SHADER); 413e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy if (mVertexShader) { 423e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mFragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER); 433e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy if (mFragmentShader) { 443e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mProgramId = glCreateProgram(); 4567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy 463e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glAttachShader(mProgramId, mVertexShader); 473e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glAttachShader(mProgramId, mFragmentShader); 4867f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy 493e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy position = bindAttrib("position", kBindingPosition); 50f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy if (description.hasTexture || description.hasExternalTexture) { 51f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy texCoords = bindAttrib("texCoords", kBindingTexCoords); 52f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy } else { 53f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy texCoords = -1; 54f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy } 55f3a910b423db7ad79cf61518bdd9278c048ad0d8Romain Guy 563b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ATRACE_BEGIN("linkProgram"); 5705bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glLinkProgram(mProgramId); 583b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ATRACE_END(); 5967f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy 6067f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy GLint status; 6105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glGetProgramiv(mProgramId, GL_LINK_STATUS, &status); 6267f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (status != GL_TRUE) { 633762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("Error while linking shaders:"); 6467f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy GLint infoLen = 0; 6505bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen); 6667f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (infoLen > 1) { 6767f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy GLchar log[infoLen]; 6805bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]); 693762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("%s", log); 7067f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 7105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy 723e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mVertexShader); 733e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mFragmentShader); 7405bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy 753e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mVertexShader); 763e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mFragmentShader); 7705bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy 7805bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glDeleteProgram(mProgramId); 793e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy } else { 803e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mInitialized = true; 8105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } 8205bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } else { 833e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mVertexShader); 845cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 855cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 86260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy 8767f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (mInitialized) { 8867f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy transform = addUniform("transform"); 8939284b763a09688468ed3799ebd2ebb76ea5dfd5Romain Guy projection = addUniform("projection"); 9067f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 915cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 925cbbce535744b89df5ecea95de21ee3733298260Romain Guy 935cbbce535744b89df5ecea95de21ee3733298260Romain GuyProgram::~Program() { 9467f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (mInitialized) { 953b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // This would ideally happen after linking the program 963b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // but Tegra drivers, especially when perfhud is enabled, 973b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // sometimes crash if we do so 983e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mVertexShader); 993e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mFragmentShader); 1003e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 1013e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mVertexShader); 1023e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mFragmentShader); 1033e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 10405bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glDeleteProgram(mProgramId); 10567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 1065cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1075cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1085cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::addAttrib(const char* name) { 10905bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy int slot = glGetAttribLocation(mProgramId, name); 11005bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mAttributes.add(name, slot); 1115cbbce535744b89df5ecea95de21ee3733298260Romain Guy return slot; 1125cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1135cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1143e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guyint Program::bindAttrib(const char* name, ShaderBindings bindingSlot) { 1153e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glBindAttribLocation(mProgramId, bindingSlot, name); 1163e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mAttributes.add(name, bindingSlot); 1173e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy return bindingSlot; 1183e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy} 1193e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 1205cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::getAttrib(const char* name) { 12105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy ssize_t index = mAttributes.indexOfKey(name); 122889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy if (index >= 0) { 12305bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy return mAttributes.valueAt(index); 124889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy } 125889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy return addAttrib(name); 1265cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1275cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1285cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::addUniform(const char* name) { 12905bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy int slot = glGetUniformLocation(mProgramId, name); 13005bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mUniforms.add(name, slot); 1315cbbce535744b89df5ecea95de21ee3733298260Romain Guy return slot; 1325cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1335cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1345cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::getUniform(const char* name) { 13505bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy ssize_t index = mUniforms.indexOfKey(name); 136889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy if (index >= 0) { 13705bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy return mUniforms.valueAt(index); 138889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy } 139889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy return addUniform(name); 1405cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1415cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1425cbbce535744b89df5ecea95de21ee3733298260Romain GuyGLuint Program::buildShader(const char* source, GLenum type) { 1433b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy ATRACE_CALL(); 1443b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1455cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLuint shader = glCreateShader(type); 1465cbbce535744b89df5ecea95de21ee3733298260Romain Guy glShaderSource(shader, 1, &source, 0); 1475cbbce535744b89df5ecea95de21ee3733298260Romain Guy glCompileShader(shader); 1485cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1495cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLint status; 1505cbbce535744b89df5ecea95de21ee3733298260Romain Guy glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 1515cbbce535744b89df5ecea95de21ee3733298260Romain Guy if (status != GL_TRUE) { 1525cbbce535744b89df5ecea95de21ee3733298260Romain Guy // Some drivers return wrong values for GL_INFO_LOG_LENGTH 1535cbbce535744b89df5ecea95de21ee3733298260Romain Guy // use a fixed size instead 1545cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLchar log[512]; 1555cbbce535744b89df5ecea95de21ee3733298260Romain Guy glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]); 1563762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("Error while compiling shader: %s", log); 1575cbbce535744b89df5ecea95de21ee3733298260Romain Guy glDeleteShader(shader); 15867f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy return 0; 1595cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 1605cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1615cbbce535744b89df5ecea95de21ee3733298260Romain Guy return shader; 1625cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1635cbbce535744b89df5ecea95de21ee3733298260Romain Guy 164889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, 1658a5cc92a150bae38ec43732d941b38bb381fe153Chet Haase const mat4& transformMatrix, bool offset) { 1665d39a77992ba6573fbc0cd4d85e0390bb5feb637Chris Craik if (projectionMatrix != mProjection || offset != mOffset) { 1673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (CC_LIKELY(!offset)) { 1683b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glUniformMatrix4fv(projection, 1, GL_FALSE, &projectionMatrix.data[0]); 1693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } else { 1703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy mat4 p(projectionMatrix); 1713b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // offset screenspace xy by an amount that compensates for typical precision 1723b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted 1733b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // up and to the left. 1743b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // This offset value is based on an assumption that some hardware may use as 1753b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // little as 12.4 precision, so we offset by slightly more than 1/16. 17632f05e343c5ffb17f3235942bcda651bd3b9f1d6Chris Craik p.translate(Vertex::gGeometryFudgeFactor, Vertex::gGeometryFudgeFactor); 1773b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]); 1783b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1793b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy mProjection = projectionMatrix; 1805d39a77992ba6573fbc0cd4d85e0390bb5feb637Chris Craik mOffset = offset; 1818a5cc92a150bae38ec43732d941b38bb381fe153Chet Haase } 18239284b763a09688468ed3799ebd2ebb76ea5dfd5Romain Guy 18339284b763a09688468ed3799ebd2ebb76ea5dfd5Romain Guy mat4 t(transformMatrix); 1840b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy t.multiply(modelViewMatrix); 1850b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); 1865cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1875cbbce535744b89df5ecea95de21ee3733298260Romain Guy 188707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guyvoid Program::setColor(const float r, const float g, const float b, const float a) { 18905bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy if (!mHasColorUniform) { 19005bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mColorUniform = getUniform("color"); 1916752d0ab029a185a42e34e7a933b669e6ed19e89Romain Guy mHasColorUniform = true; 19205bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } 19305bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glUniform4f(mColorUniform, r, g, b, a); 194707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy} 195707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy 196889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::use() { 19705bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glUseProgram(mProgramId); 1982d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy if (texCoords >= 0 && !mHasSampler) { 1990990ffbc4d407e174423a4a04b5902ed83f71db5Chet Haase glUniform1i(getUniform("baseSampler"), 0); 2002d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mHasSampler = true; 2012d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy } 202889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy mUse = true; 203f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy} 204f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy 205889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::remove() { 206889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy mUse = false; 207f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy} 208f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy 2095cbbce535744b89df5ecea95de21ee3733298260Romain Guy}; // namespace uirenderer 2105cbbce535744b89df5ecea95de21ee3733298260Romain Guy}; // namespace android 211