diff options
Diffstat (limited to 'services/surfaceflinger/RenderEngine/ProgramCache.cpp')
-rw-r--r-- | services/surfaceflinger/RenderEngine/ProgramCache.cpp | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp new file mode 100644 index 0000000..835ed8a --- /dev/null +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -0,0 +1,206 @@ +/* + * Copyright 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> + +#include <utils/String8.h> + +#include "ProgramCache.h" +#include "Program.h" +#include "Description.h" + +namespace android { +// ----------------------------------------------------------------------------------------------- + + +/* + * A simple formatter class to automatically add the endl and + * manage the indentation. + */ + +class Formatter; +static Formatter& indent(Formatter& f); +static Formatter& dedent(Formatter& f); + +class Formatter { + String8 mString; + int mIndent; + typedef Formatter& (*FormaterManipFunc)(Formatter&); + friend Formatter& indent(Formatter& f); + friend Formatter& dedent(Formatter& f); +public: + String8 getString() const { + return mString; + } + + friend Formatter& operator << (Formatter& out, const char* in) { + for (int i=0 ; i<out.mIndent ; i++) { + out.mString.append(" "); + } + out.mString.append(in); + out.mString.append("\n"); + return out; + } + friend inline Formatter& operator << (Formatter& out, const String8& in) { + return operator << (out, in.string()); + } + friend inline Formatter& operator<<(Formatter& to, FormaterManipFunc func) { + return (*func)(to); + } +}; +Formatter& indent(Formatter& f) { + f.mIndent++; + return f; +} +Formatter& dedent(Formatter& f) { + f.mIndent--; + return f; +} + +// ----------------------------------------------------------------------------------------------- + +ANDROID_SINGLETON_STATIC_INSTANCE(ProgramCache) + + +ProgramCache::ProgramCache() { +} + +ProgramCache::~ProgramCache() { +} + +ProgramCache::Key ProgramCache::computeKey(const Description& description) { + Key needs; + needs.set(Key::TEXTURE_MASK, + (description.mTextureTarget == GL_TEXTURE_EXTERNAL_OES) ? Key::TEXTURE_EXT : + (description.mTextureTarget == GL_TEXTURE_2D) ? Key::TEXTURE_2D : + Key::TEXTURE_OFF) + .set(Key::PLANE_ALPHA_MASK, + (description.mPlaneAlpha < 1) ? Key::PLANE_ALPHA_LT_ONE : Key::PLANE_ALPHA_EQ_ONE) + .set(Key::BLEND_MASK, + description.mPremultipliedAlpha ? Key::BLEND_PREMULT : Key::BLEND_NORMAL) + .set(Key::OPACITY_MASK, + description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT); + return needs; +} + +String8 ProgramCache::generateVertexShader(const Key& needs) { + Formatter vs; + if (needs.isTexturing()) { + vs << "attribute vec4 texCoords;" + << "varying vec2 outTexCoords;"; + } + vs << "attribute vec4 position;" + << "uniform mat4 projection;" + << "uniform mat4 texture;" + << "void main(void) {" << indent + << "gl_Position = projection * position;"; + if (needs.isTexturing()) { + vs << "outTexCoords = (texture * texCoords).st;"; + } + vs << dedent << "}"; + return vs.getString(); +} + +String8 ProgramCache::generateFragmentShader(const Key& needs) { + Formatter fs; + if (needs.getTextureTarget() == Key::TEXTURE_EXT) { + fs << "#extension GL_OES_EGL_image_external : require"; + } + if (needs.getTextureTarget() == Key::TEXTURE_EXT) { + fs << "uniform samplerExternalOES sampler;" + << "varying vec2 outTexCoords;"; + } else if (needs.getTextureTarget() == Key::TEXTURE_2D) { + fs << "uniform sampler2D sampler;" + << "varying vec2 outTexCoords;"; + } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) { + fs << "uniform vec4 color;"; + } + if (needs.hasPlaneAlpha()) { + fs << "uniform float alphaPlane;"; + } + fs << "void main(void) {" << indent; + if (needs.isTexturing()) { + fs << "gl_FragColor = texture2D(sampler, outTexCoords);"; + } else { + fs << "gl_FragColor = color;"; + } + if (needs.hasPlaneAlpha()) { + // modulate the alpha value with planeAlpha + if (needs.isPremultiplied()) { + // ... and the color too if we're premultiplied + if (needs.isOpaque()) { + // ... we're opaque, only premultiply the color component + fs << "gl_FragColor.rgb *= alphaPlane;" + << "gl_FragColor.a = alphaPlane;"; + } else { + fs << "gl_FragColor *= alphaPlane;"; + } + } else { + // not premultiplied + if (needs.isOpaque()) { + fs << "gl_FragColor.a = alphaPlane;"; + } else { + fs << "gl_FragColor.a *= alphaPlane;"; + } + } + } else { + if (needs.isOpaque()) { + fs << "gl_FragColor.a = 1.0;"; + } + } + fs << dedent << "}"; + return fs.getString(); +} + +Program* ProgramCache::generateProgram(const Key& needs) { + // vertex shader + String8 vs = generateVertexShader(needs); + + // fragment shader + String8 fs = generateFragmentShader(needs); + + Program* program = new Program(needs, vs.string(), fs.string()); + return program; +} + +void ProgramCache::useProgram(const Description& description) { + + // generate the key for the shader based on the description + Key needs(computeKey(description)); + + // look-up the program in the cache + Program* program = mCache.valueFor(needs); + if (program == NULL) { + // we didn't find our program, so generate one... + nsecs_t time = -systemTime(); + program = generateProgram(needs); + mCache.add(needs, program); + time += systemTime(); + + //ALOGD(">>> generated new program: needs=%08X, time=%u ms (%d programs)", + // needs.mNeeds, uint32_t(ns2ms(time)), mCache.size()); + } + + // here we have a suitable program for this description + if (program->isValid()) { + program->use(); + program->setUniforms(description); + } +} + + +} /* namespace android */ |