ProgramCache.cpp revision 3f84483382be2d528918cc1a6fbc6a7d68e0b181
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:
463f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    String8 getString() const {
473f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        return mString;
483f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
493f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
503f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    friend Formatter& operator << (Formatter& out, const char* in) {
513f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        for (int i=0 ; i<out.mIndent ; i++) {
523f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            out.mString.append("    ");
533f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        }
543f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        out.mString.append(in);
553f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        out.mString.append("\n");
563f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        return out;
573f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
583f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    friend inline Formatter& operator << (Formatter& out, const String8& in) {
593f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        return operator << (out, in.string());
603f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
613f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) {
623f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        return (*func)(to);
633f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
643f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian};
653f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianFormatter& indent(Formatter& f) {
663f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    f.mIndent++;
673f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    return f;
683f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
693f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianFormatter& dedent(Formatter& f) {
703f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    f.mIndent--;
713f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    return f;
723f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
733f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
743f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian// -----------------------------------------------------------------------------------------------
753f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
763f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache)
773f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
783f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
793f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianProgramCache::ProgramCache() {
803f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
813f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
823f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianProgramCache::~ProgramCache() {
833f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
843f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
853f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianProgramCache::Key ProgramCache::computeKey(const Description& description) {
863f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    Key needs;
873f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    needs.set(Key::TEXTURE_MASK,
883f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            (description.mTextureTarget == GL_TEXTURE_EXTERNAL_OES) ? Key::TEXTURE_EXT :
893f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            (description.mTextureTarget == GL_TEXTURE_2D)           ? Key::TEXTURE_2D :
903f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            Key::TEXTURE_OFF)
913f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    .set(Key::PLANE_ALPHA_MASK,
923f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE)
933f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    .set(Key::BLEND_MASK,
943f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL)
953f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    .set(Key::OPACITY_MASK,
963f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT);
973f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    return needs;
983f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
993f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1003f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianString8 ProgramCache::generateVertexShader(const Key& needs) {
1013f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    Formatter vs;
1023f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (needs.isTexturing()) {
1033f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        vs  << "attribute vec4 texCoords;"
1043f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            << "varying vec2 outTexCoords;";
1053f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
1063f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    vs << "attribute vec4 position;"
1073f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian       << "uniform mat4 projection;"
1083f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian       << "uniform mat4 texture;"
1093f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian       << "void main(void) {" << indent
1103f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian       << "gl_Position = projection * position;";
1113f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (needs.isTexturing()) {
1123f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        vs << "outTexCoords = (texture * texCoords).st;";
1133f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
1143f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    vs << dedent << "}";
1153f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    return vs.getString();
1163f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
1173f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1183f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianString8 ProgramCache::generateFragmentShader(const Key& needs) {
1193f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    Formatter fs;
1203f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
1213f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        fs << "#extension GL_OES_EGL_image_external : require";
1223f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
1233f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (needs.getTextureTarget() == Key::TEXTURE_EXT) {
1243f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        fs << "uniform samplerExternalOES sampler;"
1253f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian           << "varying vec2 outTexCoords;";
1263f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    } else if (needs.getTextureTarget() == Key::TEXTURE_2D) {
1273f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        fs << "uniform sampler2D sampler;"
1283f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian           << "varying vec2 outTexCoords;";
1293f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
1303f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        fs << "uniform vec4 color;";
1313f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
1323f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (needs.hasPlaneAlpha()) {
1333f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        fs << "uniform float alphaPlane;";
1343f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
1353f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    fs << "void main(void) {" << indent;
1363f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (needs.isTexturing()) {
1373f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
1383f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    } else {
1393f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        fs << "gl_FragColor = color;";
1403f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
1413f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (needs.hasPlaneAlpha()) {
1423f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        // modulate the alpha value with planeAlpha
1433f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        if (needs.isPremultiplied()) {
1443f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            // ... and the color too if we're premultiplied
1453f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            if (needs.isOpaque()) {
1463f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian                // ... we're opaque, only premultiply the color component
1473f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian                fs << "gl_FragColor.rgb *= alphaPlane;"
1483f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian                   << "gl_FragColor.a = alphaPlane;";
1493f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            } else {
1503f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian                fs << "gl_FragColor *= alphaPlane;";
1513f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            }
1523f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        } else {
1533f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            // not premultiplied
1543f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            if (needs.isOpaque()) {
1553f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian                fs << "gl_FragColor.a = alphaPlane;";
1563f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            } else {
1573f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian                fs << "gl_FragColor.a *= alphaPlane;";
1583f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            }
1593f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        }
1603f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    } else {
1613f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        if (needs.isOpaque()) {
1623f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian            fs << "gl_FragColor.a = 1.0;";
1633f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        }
1643f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
1653f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    fs << dedent << "}";
1663f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    return fs.getString();
1673f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
1683f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1693f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias AgopianProgram* ProgramCache::generateProgram(const Key& needs) {
1703f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    // vertex shader
1713f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    String8 vs = generateVertexShader(needs);
1723f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1733f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    // fragment shader
1743f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    String8 fs = generateFragmentShader(needs);
1753f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1763f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    Program* program = new Program(needs, vs.string(), fs.string());
1773f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    return program;
1783f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
1793f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1803f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopianvoid ProgramCache::useProgram(const Description& description) {
1813f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1823f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    // generate the key for the shader based on the description
1833f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    Key needs(computeKey(description));
1843f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1853f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian     // look-up the program in the cache
1863f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    Program* program = mCache.valueFor(needs);
1873f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (program == NULL) {
1883f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        // we didn't find our program, so generate one...
1893f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        nsecs_t time = -systemTime();
1903f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        program = generateProgram(needs);
1913f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        mCache.add(needs, program);
1923f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        time += systemTime();
1933f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1943f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)",
1953f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        //        needs.mNeeds, uint32_t(ns2ms(time)), mCache.size());
1963f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
1973f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
1983f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    // here we have a suitable program for this description
1993f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    if (program->isValid()) {
2003f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        program->use();
2013f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian        program->setUniforms(description);
2023f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian    }
2033f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian}
2043f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
2053f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian
2063f84483382be2d528918cc1a6fbc6a7d68e0b181Mathias Agopian} /* namespace android */
207