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) { 6367f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy GLint infoLen = 0; 6405bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glGetProgramiv(mProgramId, GL_INFO_LOG_LENGTH, &infoLen); 6567f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (infoLen > 1) { 6667f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy GLchar log[infoLen]; 6705bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glGetProgramInfoLog(mProgramId, infoLen, 0, &log[0]); 683762c311729fe9f3af085c14c5c1fb471d994c03Steve Block ALOGE("%s", log); 6967f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 7073842582fe1d1268fb9561a59885e1714948d737Chris Craik LOG_ALWAYS_FATAL("Error while linking shaders"); 713e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy } else { 723e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mInitialized = true; 7305bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } 7405bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } else { 753e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mVertexShader); 765cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 775cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 78260e102162322958cf17dbd895cd6bd30dc87e32Romain Guy 7967f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (mInitialized) { 8067f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy transform = addUniform("transform"); 8139284b763a09688468ed3799ebd2ebb76ea5dfd5Romain Guy projection = addUniform("projection"); 8267f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 835cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 845cbbce535744b89df5ecea95de21ee3733298260Romain Guy 855cbbce535744b89df5ecea95de21ee3733298260Romain GuyProgram::~Program() { 8667f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy if (mInitialized) { 873b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // This would ideally happen after linking the program 883b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // but Tegra drivers, especially when perfhud is enabled, 893b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // sometimes crash if we do so 903e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mVertexShader); 913e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDetachShader(mProgramId, mFragmentShader); 923e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 933e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mVertexShader); 943e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glDeleteShader(mFragmentShader); 953e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 9605bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glDeleteProgram(mProgramId); 9767f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy } 985cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 995cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1005cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::addAttrib(const char* name) { 10105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy int slot = glGetAttribLocation(mProgramId, name); 10205bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mAttributes.add(name, slot); 1035cbbce535744b89df5ecea95de21ee3733298260Romain Guy return slot; 1045cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1055cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1063e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guyint Program::bindAttrib(const char* name, ShaderBindings bindingSlot) { 1073e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy glBindAttribLocation(mProgramId, bindingSlot, name); 1083e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy mAttributes.add(name, bindingSlot); 1093e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy return bindingSlot; 1103e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy} 1113e263fac8c9c0e0fb242186b514a7af8efb40961Romain Guy 1125cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::getAttrib(const char* name) { 11305bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy ssize_t index = mAttributes.indexOfKey(name); 114889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy if (index >= 0) { 11505bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy return mAttributes.valueAt(index); 116889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy } 117889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy return addAttrib(name); 1185cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1195cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1205cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::addUniform(const char* name) { 12105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy int slot = glGetUniformLocation(mProgramId, name); 12205bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mUniforms.add(name, slot); 1235cbbce535744b89df5ecea95de21ee3733298260Romain Guy return slot; 1245cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1255cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1265cbbce535744b89df5ecea95de21ee3733298260Romain Guyint Program::getUniform(const char* name) { 12705bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy ssize_t index = mUniforms.indexOfKey(name); 128889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy if (index >= 0) { 12905bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy return mUniforms.valueAt(index); 130889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy } 131889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy return addUniform(name); 1325cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1335cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1345cbbce535744b89df5ecea95de21ee3733298260Romain GuyGLuint Program::buildShader(const char* source, GLenum type) { 13570850ea258cbf91477efa57a1f1a23cc0044cc93Chris Craik ATRACE_NAME("Build GL Shader"); 1363b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy 1375cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLuint shader = glCreateShader(type); 1385cbbce535744b89df5ecea95de21ee3733298260Romain Guy glShaderSource(shader, 1, &source, 0); 1395cbbce535744b89df5ecea95de21ee3733298260Romain Guy glCompileShader(shader); 1405cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1415cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLint status; 1425cbbce535744b89df5ecea95de21ee3733298260Romain Guy glGetShaderiv(shader, GL_COMPILE_STATUS, &status); 1435cbbce535744b89df5ecea95de21ee3733298260Romain Guy if (status != GL_TRUE) { 144fd15f475541a4d13293374f18204cb1b3e010582Rob Tsuk ALOGE("Error while compiling this shader:\n===\n%s\n===", source); 1455cbbce535744b89df5ecea95de21ee3733298260Romain Guy // Some drivers return wrong values for GL_INFO_LOG_LENGTH 1465cbbce535744b89df5ecea95de21ee3733298260Romain Guy // use a fixed size instead 1475cbbce535744b89df5ecea95de21ee3733298260Romain Guy GLchar log[512]; 1485cbbce535744b89df5ecea95de21ee3733298260Romain Guy glGetShaderInfoLog(shader, sizeof(log), 0, &log[0]); 149fd15f475541a4d13293374f18204cb1b3e010582Rob Tsuk LOG_ALWAYS_FATAL("Shader info log: %s", log); 15067f27952c1bcb2230beef9b5ca0bf42edad436a9Romain Guy return 0; 1515cbbce535744b89df5ecea95de21ee3733298260Romain Guy } 1525cbbce535744b89df5ecea95de21ee3733298260Romain Guy 1535cbbce535744b89df5ecea95de21ee3733298260Romain Guy return shader; 1545cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1555cbbce535744b89df5ecea95de21ee3733298260Romain Guy 156889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix, 1578a5cc92a150bae38ec43732d941b38bb381fe153Chet Haase const mat4& transformMatrix, bool offset) { 158d04a6b15f74035fd2068f34225825b55e94521f4Chris Craik if (projectionMatrix != mProjection || offset != mOffset) { 1593b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy if (CC_LIKELY(!offset)) { 1603b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glUniformMatrix4fv(projection, 1, GL_FALSE, &projectionMatrix.data[0]); 1613b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } else { 1623b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy mat4 p(projectionMatrix); 1633b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // offset screenspace xy by an amount that compensates for typical precision 1643b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // issues in GPU hardware that tends to paint hor/vert lines in pixels shifted 1653b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // up and to the left. 1663b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // This offset value is based on an assumption that some hardware may use as 1673b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy // little as 12.4 precision, so we offset by slightly more than 1/16. 168564acf7c9bff822f608cda0d5df0a64a9f9aaefdChris Craik p.translate(Vertex::GeometryFudgeFactor(), Vertex::GeometryFudgeFactor()); 1693b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy glUniformMatrix4fv(projection, 1, GL_FALSE, &p.data[0]); 1703b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy } 1713b748a44c6bd2ea05fe16839caf73dbe50bd7ae9Romain Guy mProjection = projectionMatrix; 172d04a6b15f74035fd2068f34225825b55e94521f4Chris Craik mOffset = offset; 1738a5cc92a150bae38ec43732d941b38bb381fe153Chet Haase } 17439284b763a09688468ed3799ebd2ebb76ea5dfd5Romain Guy 17539284b763a09688468ed3799ebd2ebb76ea5dfd5Romain Guy mat4 t(transformMatrix); 1760b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy t.multiply(modelViewMatrix); 1770b9db91c3dc8007b47c8fd4fb9dd85be97201a88Romain Guy glUniformMatrix4fv(transform, 1, GL_FALSE, &t.data[0]); 1785cbbce535744b89df5ecea95de21ee3733298260Romain Guy} 1795cbbce535744b89df5ecea95de21ee3733298260Romain Guy 180707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guyvoid Program::setColor(const float r, const float g, const float b, const float a) { 18105bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy if (!mHasColorUniform) { 18205bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy mColorUniform = getUniform("color"); 1836752d0ab029a185a42e34e7a933b669e6ed19e89Romain Guy mHasColorUniform = true; 18405bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy } 18505bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glUniform4f(mColorUniform, r, g, b, a); 186707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy} 187707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy 188889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::use() { 18905bbde70fd2a3af737656b9f8c5a25b56429632eRomain Guy glUseProgram(mProgramId); 1902d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy if (texCoords >= 0 && !mHasSampler) { 1910990ffbc4d407e174423a4a04b5902ed83f71db5Chet Haase glUniform1i(getUniform("baseSampler"), 0); 1922d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy mHasSampler = true; 1932d4fd364843d3efc6e6ee59ccc5beb513a86d789Romain Guy } 194889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy mUse = true; 195f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy} 196f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy 197889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyvoid Program::remove() { 198889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy mUse = false; 199f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy} 200f9764a4f532561f6e2e985ff3b25112f1132ce44Romain Guy 2015cbbce535744b89df5ecea95de21ee3733298260Romain Guy}; // namespace uirenderer 2025cbbce535744b89df5ecea95de21ee3733298260Romain Guy}; // namespace android 203