summaryrefslogtreecommitdiff
path: root/services/surfaceflinger/Layer.cpp
diff options
context:
space:
mode:
author Jesse Hall <jessehall@google.com> 2013-05-24 20:54:18 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2013-05-24 20:54:18 +0000
commitfb469f1906f2120fdf73d31c3ea14b1f0fb5e225 (patch)
treef811b28ea51d057b9f00e86f8eb28068eb3c4790 /services/surfaceflinger/Layer.cpp
parent80391a1e35121c855d24feaf9608acd9a4f4aefe (diff)
parent29c3f352797d9d2ddf055d8f888e7694ef8b3947 (diff)
Merge "Prevent opaque windows from making framebuffer translucent"
Diffstat (limited to 'services/surfaceflinger/Layer.cpp')
-rw-r--r--services/surfaceflinger/Layer.cpp93
1 files changed, 75 insertions, 18 deletions
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c15dfd5386..ee692227eb 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -559,31 +559,88 @@ void Layer::clearWithOpenGL(
clearWithOpenGL(hw, clip, 0,0,0,0);
}
+static void setupOpenGL10(bool premultipliedAlpha, bool opaque, int alpha) {
+ // OpenGL ES 1.0 doesn't support texture combiners.
+ // This path doesn't properly handle opaque layers that have non-opaque
+ // alpha values. The alpha channel will be copied into the framebuffer or
+ // screenshot, so if the framebuffer or screenshot is blended on top of
+ // something else, whatever is below the window will incorrectly show
+ // through.
+ if (CC_UNLIKELY(alpha < 0xFF)) {
+ GLfloat floatAlpha = alpha * (1.0f / 255.0f);
+ if (premultipliedAlpha) {
+ glColor4f(floatAlpha, floatAlpha, floatAlpha, floatAlpha);
+ } else {
+ glColor4f(1.0f, 1.0f, 1.0f, floatAlpha);
+ }
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ } else {
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ }
+}
+
+static void setupOpenGL11(bool premultipliedAlpha, bool opaque, int alpha) {
+ GLenum combineRGB;
+ GLenum combineAlpha;
+ GLenum src0Alpha;
+ GLfloat envColor[4];
+
+ if (CC_UNLIKELY(alpha < 0xFF)) {
+ // Cv = premultiplied ? Cs*alpha : Cs
+ // Av = !opaque ? alpha*As : 1.0
+ combineRGB = premultipliedAlpha ? GL_MODULATE : GL_REPLACE;
+ combineAlpha = !opaque ? GL_MODULATE : GL_REPLACE;
+ src0Alpha = GL_CONSTANT;
+ envColor[0] = alpha * (1.0f / 255.0f);
+ } else {
+ // Cv = Cs
+ // Av = opaque ? 1.0 : As
+ combineRGB = GL_REPLACE;
+ combineAlpha = GL_REPLACE;
+ src0Alpha = opaque ? GL_CONSTANT : GL_TEXTURE;
+ envColor[0] = 1.0f;
+ }
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, combineRGB);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
+ if (combineRGB == GL_MODULATE) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+ }
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, combineAlpha);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, src0Alpha);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
+ if (combineAlpha == GL_MODULATE) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
+ }
+ if (combineRGB == GL_MODULATE || src0Alpha == GL_CONSTANT) {
+ envColor[1] = envColor[0];
+ envColor[2] = envColor[0];
+ envColor[3] = envColor[0];
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor);
+ }
+}
+
void Layer::drawWithOpenGL(
const sp<const DisplayDevice>& hw, const Region& clip) const {
const uint32_t fbHeight = hw->getHeight();
const State& s(drawingState());
- GLenum src = mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA;
- if (CC_UNLIKELY(s.alpha < 0xFF)) {
- const GLfloat alpha = s.alpha * (1.0f/255.0f);
- if (mPremultipliedAlpha) {
- glColor4f(alpha, alpha, alpha, alpha);
- } else {
- glColor4f(1, 1, 1, alpha);
- }
+ if (mFlinger->getGlesVersion() == GLES_VERSION_1_0) {
+ setupOpenGL10(mPremultipliedAlpha, isOpaque(), s.alpha);
+ } else {
+ setupOpenGL11(mPremultipliedAlpha, isOpaque(), s.alpha);
+ }
+
+ if (s.alpha < 0xFF || !isOpaque()) {
glEnable(GL_BLEND);
- glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glBlendFunc(mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA);
} else {
- glColor4f(1, 1, 1, 1);
- glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
- if (!isOpaque()) {
- glEnable(GL_BLEND);
- glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA);
- } else {
- glDisable(GL_BLEND);
- }
+ glDisable(GL_BLEND);
}
LayerMesh mesh;