replicant-frameworks_native/services/surfaceflinger/RenderEngine/ProgramCache.cpp
Mathias Agopian 2eaefe198a Simplify handling of opaque layers in shader generation
just ensure the alpha value is 1.0 in the opaque case
when reading the color from the texture or the
global color.

Bug: 8679321

Change-Id: Ia38b30e97c3bce5a2d534a40c0d66e0bfc3ea40d
2013-08-15 15:11:01 -07:00

197 lines
5.8 KiB
C++

/*
* 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:
Formatter() : mIndent(0) {}
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.isOpaque()) {
fs << "gl_FragColor.a = 1.0;";
}
if (needs.hasPlaneAlpha()) {
// modulate the alpha value with planeAlpha
if (needs.isPremultiplied()) {
// ... and the color too if we're premultiplied
fs << "gl_FragColor *= alphaPlane;";
} else {
fs << "gl_FragColor.a *= alphaPlane;";
}
}
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 */