diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index c15dfd538..ee692227e 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& 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); - } - glEnable(GL_BLEND); - glBlendFunc(src, GL_ONE_MINUS_SRC_ALPHA); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + if (mFlinger->getGlesVersion() == GLES_VERSION_1_0) { + setupOpenGL10(mPremultipliedAlpha, isOpaque(), s.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); - } + setupOpenGL11(mPremultipliedAlpha, isOpaque(), s.alpha); + } + + if (s.alpha < 0xFF || !isOpaque()) { + glEnable(GL_BLEND); + glBlendFunc(mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA); + } else { + glDisable(GL_BLEND); } LayerMesh mesh; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6ab33ef31..fbd9f2552 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -414,6 +414,22 @@ EGLContext SurfaceFlinger::createGLContext(EGLDisplay display, EGLConfig config) return ctxt; } +static GlesVersion parseGlesVersion(const char* str) { + int major, minor; + if (sscanf(str, "OpenGL ES-CM %d.%d", &major, &minor) != 2) { + ALOGW("Unable to parse GL_VERSION string: \"%s\"", str); + return GLES_VERSION_1_0; + } + + if (major == 1 && minor == 0) return GLES_VERSION_1_0; + if (major == 1 && minor >= 1) return GLES_VERSION_1_1; + if (major == 2 && minor >= 0) return GLES_VERSION_2_0; + if (major == 3 && minor >= 0) return GLES_VERSION_3_0; + + ALOGW("Unrecognized OpenGL ES version: %d.%d", major, minor); + return GLES_VERSION_1_0; +} + void SurfaceFlinger::initializeGL(EGLDisplay display) { GLExtensions& extensions(GLExtensions::getInstance()); extensions.initWithGLStrings( @@ -425,6 +441,8 @@ void SurfaceFlinger::initializeGL(EGLDisplay display) { eglQueryString(display, EGL_VERSION), eglQueryString(display, EGL_EXTENSIONS)); + mGlesVersion = parseGlesVersion(extensions.getVersion()); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize); glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index e7745b8ca..089c2659d 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -72,6 +72,13 @@ enum { eTransactionMask = 0x07 }; +enum GlesVersion { + GLES_VERSION_1_0 = 0x10000, + GLES_VERSION_1_1 = 0x10001, + GLES_VERSION_2_0 = 0x20000, + GLES_VERSION_3_0 = 0x30000, +}; + class SurfaceFlinger : public BinderService, public BnSurfaceComposer, private IBinder::DeathRecipient, @@ -121,6 +128,11 @@ public: // TODO: this should be made accessible only to HWComposer const Vector< sp >& getLayerSortedByZForHwcDisplay(int id); + // return the version of the OpenGL ES composition context + GlesVersion getGlesVersion() const { + return mGlesVersion; + } + private: friend class Client; friend class DisplayEventConnection; @@ -421,6 +433,7 @@ private: EGLConfig mEGLConfig; EGLDisplay mEGLDisplay; EGLint mEGLNativeVisualId; + GlesVersion mGlesVersion; sp mBuiltinDisplays[DisplayDevice::NUM_DISPLAY_TYPES]; // Can only accessed from the main thread, these members