ProgramCache.cpp revision 458197de008be8fe561286b09f4edddb2f5c540a
13f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian/* 23f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * Copyright 2013 The Android Open Source Project 33f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * 43f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * Licensed under the Apache License, Version 2.0 (the "License"); 53f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * you may not use this file except in compliance with the License. 63f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * You may obtain a copy of the License at 73f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * 83f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * http://www.apache.org/licenses/LICENSE-2.0 93f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * 103f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * Unless required by applicable law or agreed to in writing, software 113f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * distributed under the License is distributed on an "AS IS" BASIS, 123f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * See the License for the specific language governing permissions and 143f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * limitations under the License. 153f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian */ 163f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 173f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include <GLES2/gl2.h> 183f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include <GLES2/gl2ext.h> 193f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 203f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include <utils/String8.h> 213f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 223f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include "ProgramCache.h" 233f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include "Program.h" 243f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian#include "Description.h" 253f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 263f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopiannamespace android { 273f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian// ----------------------------------------------------------------------------------------------- 283f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 293f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 303f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian/* 313f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * A simple formatter class to automatically add the endl and 323f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian * manage the indentation. 333f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian */ 343f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 353f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianclass Formatter; 363f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianstatic Formatter& indent(Formatter& f); 373f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianstatic Formatter& dedent(Formatter& f); 383f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 393f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianclass Formatter { 403f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian String8 mString; 413f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian int mIndent; 423f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian typedef Formatter& (*FormaterManipFunc)(Formatter&); 433f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian friend Formatter& indent(Formatter& f); 443f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian friend Formatter& dedent(Formatter& f); 453f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianpublic: 46892f22dcb96927b4a4f9ab7badd6f2c9f4f37c1fAndy McFadden Formatter() : mIndent(0) {} 47892f22dcb96927b4a4f9ab7badd6f2c9f4f37c1fAndy McFadden 483f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian String8 getString() const { 493f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return mString; 503f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 513f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 523f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian friend Formatter& operator << (Formatter& out, const char* in) { 533f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian for (int i=0 ; i<out.mIndent ; i++) { 543f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian out.mString.append(" "); 553f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 563f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian out.mString.append(in); 573f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian out.mString.append("\n"); 583f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return out; 593f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 603f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian friend inline Formatter& operator << (Formatter& out, const String8& in) { 613f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return operator << (out, in.string()); 623f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 633f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) { 643f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return (*func)(to); 653f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 663f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}; 673f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianFormatter& indent(Formatter& f) { 683f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian f.mIndent++; 693f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return f; 703f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 713f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianFormatter& dedent(Formatter& f) { 723f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian f.mIndent--; 733f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return f; 743f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 753f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 763f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian// ----------------------------------------------------------------------------------------------- 773f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 783f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache) 793f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 803f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 813f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianProgramCache::ProgramCache() { 823f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 833f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 843f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianProgramCache::~ProgramCache() { 853f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 863f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 873f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianProgramCache::Key ProgramCache::computeKey(const Description& description) { 883f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian Key needs; 893f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian needs.set(Key::TEXTURE_MASK, 903f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian (description.mTextureTarget == GL_TEXTURE_EXTERNAL_OES) ? Key::TEXTURE_EXT : 913f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian (description.mTextureTarget == GL_TEXTURE_2D) ? Key::TEXTURE_2D : 923f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian Key::TEXTURE_OFF) 933f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian .set(Key::PLANE_ALPHA_MASK, 943f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE) 953f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian .set(Key::BLEND_MASK, 963f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) 973f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian .set(Key::OPACITY_MASK, 983f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); 993f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return needs; 1003f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 1013f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1023f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianString8 ProgramCache::generateVertexShader(const Key& needs) { 1033f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian Formatter vs; 1043f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.isTexturing()) { 1053f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian vs << "attribute vec4 texCoords;" 1063f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian << "varying vec2 outTexCoords;"; 1073f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1083f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian vs << "attribute vec4 position;" 1093f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian << "uniform mat4 projection;" 1103f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian << "uniform mat4 texture;" 1113f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian << "void main(void) {" << indent 1123f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian << "gl_Position = projection * position;"; 1133f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.isTexturing()) { 1143f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian vs << "outTexCoords = (texture * texCoords).st;"; 1153f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1163f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian vs << dedent << "}"; 1173f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return vs.getString(); 1183f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 1193f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1203f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianString8 ProgramCache::generateFragmentShader(const Key& needs) { 1213f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian Formatter fs; 1223f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.getTextureTarget() == Key::TEXTURE_EXT) { 1233f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "#extension GL_OES_EGL_image_external : require"; 1243f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 125458197de008be8fe561286b09f4edddb2f5c540aMathias Agopian 126458197de008be8fe561286b09f4edddb2f5c540aMathias Agopian // default precision is required-ish in fragment shaders 127458197de008be8fe561286b09f4edddb2f5c540aMathias Agopian fs << "precision mediump float;"; 128458197de008be8fe561286b09f4edddb2f5c540aMathias Agopian 1293f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.getTextureTarget() == Key::TEXTURE_EXT) { 1303f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "uniform samplerExternalOES sampler;" 1313f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian << "varying vec2 outTexCoords;"; 1323f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } else if (needs.getTextureTarget() == Key::TEXTURE_2D) { 1333f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "uniform sampler2D sampler;" 1343f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian << "varying vec2 outTexCoords;"; 1353f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) { 1363f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "uniform vec4 color;"; 1373f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1383f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.hasPlaneAlpha()) { 1393f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "uniform float alphaPlane;"; 1403f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1413f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "void main(void) {" << indent; 1423f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.isTexturing()) { 1433f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; 1443f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } else { 1453f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "gl_FragColor = color;"; 1463f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1473f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.hasPlaneAlpha()) { 1483f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // modulate the alpha value with planeAlpha 1493f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.isPremultiplied()) { 1503f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // ... and the color too if we're premultiplied 1513f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.isOpaque()) { 1523f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // ... we're opaque, only premultiply the color component 1533f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "gl_FragColor.rgb *= alphaPlane;" 1543f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian << "gl_FragColor.a = alphaPlane;"; 1553f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } else { 1563f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "gl_FragColor *= alphaPlane;"; 1573f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1583f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } else { 1593f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // not premultiplied 1603f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.isOpaque()) { 1613f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "gl_FragColor.a = alphaPlane;"; 1623f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } else { 1633f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "gl_FragColor.a *= alphaPlane;"; 1643f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1653f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1663f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } else { 1673f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (needs.isOpaque()) { 1683f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << "gl_FragColor.a = 1.0;"; 1693f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1703f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 1713f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian fs << dedent << "}"; 1723f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return fs.getString(); 1733f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 1743f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1753f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianProgram* ProgramCache::generateProgram(const Key& needs) { 1763f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // vertex shader 1773f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian String8 vs = generateVertexShader(needs); 1783f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1793f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // fragment shader 1803f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian String8 fs = generateFragmentShader(needs); 1813f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1823f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian Program* program = new Program(needs, vs.string(), fs.string()); 1833f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian return program; 1843f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 1853f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1863f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianvoid ProgramCache::useProgram(const Description& description) { 1873f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1883f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // generate the key for the shader based on the description 1893f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian Key needs(computeKey(description)); 1903f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 1913f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // look-up the program in the cache 1923f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian Program* program = mCache.valueFor(needs); 1933f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (program == NULL) { 1943f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // we didn't find our program, so generate one... 1953f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian nsecs_t time = -systemTime(); 1963f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian program = generateProgram(needs); 1973f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian mCache.add(needs, program); 1983f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian time += systemTime(); 1993f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 2003f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)", 2013f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // needs.mNeeds, uint32_t(ns2ms(time)), mCache.size()); 2023f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 2033f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 2043f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian // here we have a suitable program for this description 2053f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian if (program->isValid()) { 2063f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian program->use(); 2073f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian program->setUniforms(description); 2083f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian } 2093f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} 2103f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 2113f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian 2123f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} /* namespace android */ 213