Merge "Prevent opaque windows from making framebuffer translucent"

This commit is contained in:
Jesse Hall 2013-05-24 20:54:18 +00:00 committed by Android (Google) Code Review
commit fb469f1906
3 changed files with 107 additions and 19 deletions

View File

@ -559,32 +559,89 @@ 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);
if (mFlinger->getGlesVersion() == GLES_VERSION_1_0) {
setupOpenGL10(mPremultipliedAlpha, isOpaque(), s.alpha);
} else {
glColor4f(1, 1, 1, alpha);
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);
} 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);
glBlendFunc(mPremultipliedAlpha ? GL_ONE : GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA);
} else {
glDisable(GL_BLEND);
}
}
LayerMesh mesh;
computeGeometry(hw, &mesh);

View File

@ -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);

View File

@ -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<SurfaceFlinger>,
public BnSurfaceComposer,
private IBinder::DeathRecipient,
@ -121,6 +128,11 @@ public:
// TODO: this should be made accessible only to HWComposer
const Vector< sp<Layer> >& 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<IBinder> mBuiltinDisplays[DisplayDevice::NUM_DISPLAY_TYPES];
// Can only accessed from the main thread, these members