ProgramCache.cpp revision 892f22dcb96927b4a4f9ab7badd6f2c9f4f37c1f
1/* 2 * Copyright 2013 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#include <GLES2/gl2.h> 18#include <GLES2/gl2ext.h> 19 20#include <utils/String8.h> 21 22#include "ProgramCache.h" 23#include "Program.h" 24#include "Description.h" 25 26namespace android { 27// ----------------------------------------------------------------------------------------------- 28 29 30/* 31 * A simple formatter class to automatically add the endl and 32 * manage the indentation. 33 */ 34 35class Formatter; 36static Formatter& indent(Formatter& f); 37static Formatter& dedent(Formatter& f); 38 39class Formatter { 40 String8 mString; 41 int mIndent; 42 typedef Formatter& (*FormaterManipFunc)(Formatter&); 43 friend Formatter& indent(Formatter& f); 44 friend Formatter& dedent(Formatter& f); 45public: 46 Formatter() : mIndent(0) {} 47 48 String8 getString() const { 49 return mString; 50 } 51 52 friend Formatter& operator << (Formatter& out, const char* in) { 53 for (int i=0 ; i<out.mIndent ; i++) { 54 out.mString.append(" "); 55 } 56 out.mString.append(in); 57 out.mString.append("\n"); 58 return out; 59 } 60 friend inline Formatter& operator << (Formatter& out, const String8& in) { 61 return operator << (out, in.string()); 62 } 63 friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) { 64 return (*func)(to); 65 } 66}; 67Formatter& indent(Formatter& f) { 68 f.mIndent++; 69 return f; 70} 71Formatter& dedent(Formatter& f) { 72 f.mIndent--; 73 return f; 74} 75 76// ----------------------------------------------------------------------------------------------- 77 78ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache) 79 80 81ProgramCache::ProgramCache() { 82} 83 84ProgramCache::~ProgramCache() { 85} 86 87ProgramCache::Key ProgramCache::computeKey(const Description& description) { 88 Key needs; 89 needs.set(Key::TEXTURE_MASK, 90 (description.mTextureTarget == GL_TEXTURE_EXTERNAL_OES) ? Key::TEXTURE_EXT : 91 (description.mTextureTarget == GL_TEXTURE_2D) ? Key::TEXTURE_2D : 92 Key::TEXTURE_OFF) 93 .set(Key::PLANE_ALPHA_MASK, 94 (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE) 95 .set(Key::BLEND_MASK, 96 description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) 97 .set(Key::OPACITY_MASK, 98 description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); 99 return needs; 100} 101 102String8 ProgramCache::generateVertexShader(const Key& needs) { 103 Formatter vs; 104 if (needs.isTexturing()) { 105 vs << "attribute vec4 texCoords;" 106 << "varying vec2 outTexCoords;"; 107 } 108 vs << "attribute vec4 position;" 109 << "uniform mat4 projection;" 110 << "uniform mat4 texture;" 111 << "void main(void) {" << indent 112 << "gl_Position = projection * position;"; 113 if (needs.isTexturing()) { 114 vs << "outTexCoords = (texture * texCoords).st;"; 115 } 116 vs << dedent << "}"; 117 return vs.getString(); 118} 119 120String8 ProgramCache::generateFragmentShader(const Key& needs) { 121 Formatter fs; 122 if (needs.getTextureTarget() == Key::TEXTURE_EXT) { 123 fs << "#extension GL_OES_EGL_image_external : require"; 124 } 125 if (needs.getTextureTarget() == Key::TEXTURE_EXT) { 126 fs << "uniform samplerExternalOES sampler;" 127 << "varying vec2 outTexCoords;"; 128 } else if (needs.getTextureTarget() == Key::TEXTURE_2D) { 129 fs << "uniform sampler2D sampler;" 130 << "varying vec2 outTexCoords;"; 131 } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) { 132 fs << "uniform vec4 color;"; 133 } 134 if (needs.hasPlaneAlpha()) { 135 fs << "uniform float alphaPlane;"; 136 } 137 fs << "void main(void) {" << indent; 138 if (needs.isTexturing()) { 139 fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; 140 } else { 141 fs << "gl_FragColor = color;"; 142 } 143 if (needs.hasPlaneAlpha()) { 144 // modulate the alpha value with planeAlpha 145 if (needs.isPremultiplied()) { 146 // ... and the color too if we're premultiplied 147 if (needs.isOpaque()) { 148 // ... we're opaque, only premultiply the color component 149 fs << "gl_FragColor.rgb *= alphaPlane;" 150 << "gl_FragColor.a = alphaPlane;"; 151 } else { 152 fs << "gl_FragColor *= alphaPlane;"; 153 } 154 } else { 155 // not premultiplied 156 if (needs.isOpaque()) { 157 fs << "gl_FragColor.a = alphaPlane;"; 158 } else { 159 fs << "gl_FragColor.a *= alphaPlane;"; 160 } 161 } 162 } else { 163 if (needs.isOpaque()) { 164 fs << "gl_FragColor.a = 1.0;"; 165 } 166 } 167 fs << dedent << "}"; 168 return fs.getString(); 169} 170 171Program* ProgramCache::generateProgram(const Key& needs) { 172 // vertex shader 173 String8 vs = generateVertexShader(needs); 174 175 // fragment shader 176 String8 fs = generateFragmentShader(needs); 177 178 Program* program = new Program(needs, vs.string(), fs.string()); 179 return program; 180} 181 182void ProgramCache::useProgram(const Description& description) { 183 184 // generate the key for the shader based on the description 185 Key needs(computeKey(description)); 186 187 // look-up the program in the cache 188 Program* program = mCache.valueFor(needs); 189 if (program == NULL) { 190 // we didn't find our program, so generate one... 191 nsecs_t time = -systemTime(); 192 program = generateProgram(needs); 193 mCache.add(needs, program); 194 time += systemTime(); 195 196 //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)", 197 // needs.mNeeds, uint32_t(ns2ms(time)), mCache.size()); 198 } 199 200 // here we have a suitable program for this description 201 if (program->isValid()) { 202 program->use(); 203 program->setUniforms(description); 204 } 205} 206 207 208} /* namespace android */ 209