Home | History | Annotate | Download | only in RenderEngine
      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 
     26 namespace android {
     27 // -----------------------------------------------------------------------------------------------
     28 
     29 
     30 /*
     31  * A simple formatter class to automatically add the endl and
     32  * manage the indentation.
     33  */
     34 
     35 class Formatter;
     36 static Formatter& indent(Formatter& f);
     37 static Formatter& dedent(Formatter& f);
     38 
     39 class Formatter {
     40     String8 mString;
     41     int mIndent;
     42     typedef Formatter& (*FormaterManipFunc)(Formatter&);
     43     friend Formatter& indent(Formatter& f);
     44     friend Formatter& dedent(Formatter& f);
     45 public:
     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 };
     67 Formatter& indent(Formatter& f) {
     68     f.mIndent++;
     69     return f;
     70 }
     71 Formatter& dedent(Formatter& f) {
     72     f.mIndent--;
     73     return f;
     74 }
     75 
     76 // -----------------------------------------------------------------------------------------------
     77 
     78 ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
     79 
     80 ProgramCache::ProgramCache() {
     81     // Until surfaceflinger has a dependable blob cache on the filesystem,
     82     // generate shaders on initialization so as to avoid jank.
     83     primeCache();
     84 }
     85 
     86 ProgramCache::~ProgramCache() {
     87 }
     88 
     89 void ProgramCache::primeCache() {
     90     uint32_t shaderCount = 0;
     91     uint32_t keyMask = Key::BLEND_MASK | Key::OPACITY_MASK |
     92                        Key::PLANE_ALPHA_MASK | Key::TEXTURE_MASK;
     93     // Prime the cache for all combinations of the above masks,
     94     // leaving off the experimental color matrix mask options.
     95 
     96     nsecs_t timeBefore = systemTime();
     97     for (uint32_t keyVal = 0; keyVal <= keyMask; keyVal++) {
     98         Key shaderKey;
     99         shaderKey.set(keyMask, keyVal);
    100         uint32_t tex = shaderKey.getTextureTarget();
    101         if (tex != Key::TEXTURE_OFF &&
    102             tex != Key::TEXTURE_EXT &&
    103             tex != Key::TEXTURE_2D) {
    104             continue;
    105         }
    106         Program* program = mCache.valueFor(shaderKey);
    107         if (program == NULL) {
    108             program = generateProgram(shaderKey);
    109             mCache.add(shaderKey, program);
    110             shaderCount++;
    111         }
    112     }
    113     nsecs_t timeAfter = systemTime();
    114     float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
    115     ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs);
    116 }
    117 
    118 ProgramCache::Key ProgramCache::computeKey(const Description& description) {
    119     Key needs;
    120     needs.set(Key::TEXTURE_MASK,
    121             !description.mTextureEnabled ? Key::TEXTURE_OFF :
    122             description.mTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_EXT :
    123             description.mTexture.getTextureTarget() == GL_TEXTURE_2D           ? Key::TEXTURE_2D :
    124             Key::TEXTURE_OFF)
    125     .set(Key::PLANE_ALPHA_MASK,
    126             (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
    127     .set(Key::BLEND_MASK,
    128             description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
    129     .set(Key::OPACITY_MASK,
    130             description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
    131     .set(Key::COLOR_MATRIX_MASK,
    132             description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON :  Key::COLOR_MATRIX_OFF);
    133     return needs;
    134 }
    135 
    136 String8 ProgramCache::generateVertexShader(const Key& needs) {
    137     Formatter vs;
    138     if (needs.isTexturing()) {
    139         vs  << "attribute vec4 texCoords;"
    140             << "varying vec2 outTexCoords;";
    141     }
    142     vs << "attribute vec4 position;"
    143        << "uniform mat4 projection;"
    144        << "uniform mat4 texture;"
    145        << "void main(void) {" << indent
    146        << "gl_Position = projection * position;";
    147     if (needs.isTexturing()) {
    148         vs << "outTexCoords = (texture * texCoords).st;";
    149     }
    150     vs << dedent << "}";
    151     return vs.getString();
    152 }
    153 
    154 String8 ProgramCache::generateFragmentShader(const Key& needs) {
    155     Formatter fs;
    156     if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
    157         fs << "#extension GL_OES_EGL_image_external : require";
    158     }
    159 
    160     // default precision is required-ish in fragment shaders
    161     fs << "precision mediump float;";
    162 
    163     if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
    164         fs << "uniform samplerExternalOES sampler;"
    165            << "varying vec2 outTexCoords;";
    166     } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
    167         fs << "uniform sampler2D sampler;"
    168            << "varying vec2 outTexCoords;";
    169     } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
    170         fs << "uniform vec4 color;";
    171     }
    172     if (needs.hasPlaneAlpha()) {
    173         fs << "uniform float alphaPlane;";
    174     }
    175     if (needs.hasColorMatrix()) {
    176         fs << "uniform mat4 colorMatrix;";
    177     }
    178     fs << "void main(void) {" << indent;
    179     if (needs.isTexturing()) {
    180         fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
    181     } else {
    182         fs << "gl_FragColor = color;";
    183     }
    184     if (needs.isOpaque()) {
    185         fs << "gl_FragColor.a = 1.0;";
    186     }
    187     if (needs.hasPlaneAlpha()) {
    188         // modulate the alpha value with planeAlpha
    189         if (needs.isPremultiplied()) {
    190             // ... and the color too if we're premultiplied
    191             fs << "gl_FragColor *= alphaPlane;";
    192         } else {
    193             fs << "gl_FragColor.a *= alphaPlane;";
    194         }
    195     }
    196 
    197     if (needs.hasColorMatrix()) {
    198         if (!needs.isOpaque() && needs.isPremultiplied()) {
    199             // un-premultiply if needed before linearization
    200             fs << "gl_FragColor.rgb = gl_FragColor.rgb/gl_FragColor.a;";
    201         }
    202         fs << "vec4 transformed = colorMatrix * vec4(gl_FragColor.rgb, 1);";
    203         fs << "gl_FragColor.rgb = transformed.rgb/transformed.a;";
    204         if (!needs.isOpaque() && needs.isPremultiplied()) {
    205             // and re-premultiply if needed after gamma correction
    206             fs << "gl_FragColor.rgb = gl_FragColor.rgb*gl_FragColor.a;";
    207         }
    208     }
    209 
    210     fs << dedent << "}";
    211     return fs.getString();
    212 }
    213 
    214 Program* ProgramCache::generateProgram(const Key& needs) {
    215     // vertex shader
    216     String8 vs = generateVertexShader(needs);
    217 
    218     // fragment shader
    219     String8 fs = generateFragmentShader(needs);
    220 
    221     Program* program = new Program(needs, vs.string(), fs.string());
    222     return program;
    223 }
    224 
    225 void ProgramCache::useProgram(const Description& description) {
    226 
    227     // generate the key for the shader based on the description
    228     Key needs(computeKey(description));
    229 
    230      // look-up the program in the cache
    231     Program* program = mCache.valueFor(needs);
    232     if (program == NULL) {
    233         // we didn't find our program, so generate one...
    234         nsecs_t time = -systemTime();
    235         program = generateProgram(needs);
    236         mCache.add(needs, program);
    237         time += systemTime();
    238 
    239         //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
    240         //        needs.mNeeds, uint32_t(ns2ms(time)), mCache.size());
    241     }
    242 
    243     // here we have a suitable program for this description
    244     if (program->isValid()) {
    245         program->use();
    246         program->setUniforms(description);
    247     }
    248 }
    249 
    250 
    251 } /* namespace android */
    252