OSDN Git Service

Prevent opaque windows from making framebuffer translucent
[android-x86/frameworks-native.git] / services / surfaceflinger / Layer.cpp
index 44ef0b8..ee69222 100644 (file)
@@ -36,6 +36,7 @@
 #include <gui/Surface.h>
 
 #include "clz.h"
+#include "Colorizer.h"
 #include "DisplayDevice.h"
 #include "GLExtensions.h"
 #include "Layer.h"
@@ -52,7 +53,8 @@ namespace android {
 
 int32_t Layer::sSequence = 1;
 
-Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client)
+Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
+        const String8& name, uint32_t w, uint32_t h, uint32_t flags)
     :   contentDirty(false),
         sequence(uint32_t(android_atomic_inc(&sSequence))),
         mFlinger(flinger),
@@ -79,18 +81,42 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client)
 {
     mCurrentCrop.makeInvalid();
     glGenTextures(1, &mTextureName);
+
+    uint32_t layerFlags = 0;
+    if (flags & ISurfaceComposerClient::eHidden)
+        layerFlags = layer_state_t::eLayerHidden;
+
+    if (flags & ISurfaceComposerClient::eNonPremultiplied)
+        mPremultipliedAlpha = false;
+
+    mName = name;
+
+    mCurrentState.active.w = w;
+    mCurrentState.active.h = h;
+    mCurrentState.active.crop.makeInvalid();
+    mCurrentState.z = 0;
+    mCurrentState.alpha = 0xFF;
+    mCurrentState.layerStack = 0;
+    mCurrentState.flags = layerFlags;
+    mCurrentState.sequence = 0;
+    mCurrentState.transform.set(0, 0);
+    mCurrentState.requested = mCurrentState.active;
+
+    // drawing state & current state are identical
+    mDrawingState = mCurrentState;
 }
 
 void Layer::onFirstRef()
 {
     // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
-    sp<BufferQueue> bq = new SurfaceTextureLayer();
+    sp<BufferQueue> bq = new SurfaceTextureLayer(mFlinger);
     mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
             GL_TEXTURE_EXTERNAL_OES, false, bq);
 
     mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mSurfaceFlingerConsumer->setFrameAvailableListener(this);
     mSurfaceFlingerConsumer->setSynchronousMode(true);
+    mSurfaceFlingerConsumer->setName(mName);
 
 #ifdef TARGET_DISABLE_TRIPLE_BUFFERING
 #warning "disabling triple buffering"
@@ -103,8 +129,7 @@ void Layer::onFirstRef()
     updateTransformHint(hw);
 }
 
-Layer::~Layer()
-{
+Layer::~Layer() {
     sp<Client> c(mClientRef.promote());
     if (c != 0) {
         c->detachLayer(this);
@@ -120,7 +145,7 @@ void Layer::onLayerDisplayed(const sp<const DisplayDevice>& hw,
         HWComposer::HWCLayerInterface* layer) {
     if (layer) {
         layer->onDisplayed();
-        mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFenceFd());
+        mSurfaceFlingerConsumer->setReleaseFence(layer->getAndResetReleaseFence());
     }
 }
 
@@ -129,8 +154,9 @@ void Layer::onFrameAvailable() {
     mFlinger->signalLayerUpdate();
 }
 
-// called with SurfaceFlinger::mStateLock as soon as the layer is entered
-// in the purgatory list
+// called with SurfaceFlinger::mStateLock from the drawing thread after
+// the layer has been remove from the current state list (and just before
+// it's removed from the drawing state list)
 void Layer::onRemoved() {
     mSurfaceFlingerConsumer->abandon();
 }
@@ -139,39 +165,10 @@ void Layer::onRemoved() {
 // set-up
 // ---------------------------------------------------------------------------
 
-void Layer::setName(const String8& name) {
-    mName = name;
-    mSurfaceFlingerConsumer->setName(name);
-}
-
 String8 Layer::getName() const {
     return mName;
 }
 
-void Layer::initStates(uint32_t w, uint32_t h, uint32_t flags)
-{
-    uint32_t layerFlags = 0;
-    if (flags & ISurfaceComposerClient::eHidden)
-        layerFlags = layer_state_t::eLayerHidden;
-
-    if (flags & ISurfaceComposerClient::eNonPremultiplied)
-        mPremultipliedAlpha = false;
-
-    mCurrentState.active.w = w;
-    mCurrentState.active.h = h;
-    mCurrentState.active.crop.makeInvalid();
-    mCurrentState.z = 0;
-    mCurrentState.alpha = 0xFF;
-    mCurrentState.layerStack = 0;
-    mCurrentState.flags = layerFlags;
-    mCurrentState.sequence = 0;
-    mCurrentState.transform.set(0, 0);
-    mCurrentState.requested = mCurrentState.active;
-
-    // drawing state & current state are identical
-    mDrawingState = mCurrentState;
-}
-
 status_t Layer::setBuffers( uint32_t w, uint32_t h,
                             PixelFormat format, uint32_t flags)
 {
@@ -207,59 +204,47 @@ status_t Layer::setBuffers( uint32_t w, uint32_t h,
     return NO_ERROR;
 }
 
-sp<ISurface> Layer::createSurface() {
+sp<IBinder> Layer::getHandle() {
+    Mutex::Autolock _l(mLock);
+
+    LOG_ALWAYS_FATAL_IF(mHasSurface,
+            "Layer::getHandle() has already been called");
+
+    mHasSurface = true;
+
     /*
-     * This class provides an implementation of BnSurface (the "native" or
-     * "remote" side of the Binder IPC interface ISurface), and mixes in
-     * LayerCleaner to ensure that mFlinger->onLayerDestroyed() is called for
-     * this layer when the BSurface is destroyed.
-     *
-     * The idea is to provide a handle to the Layer through ISurface that
-     * is cleaned up automatically when the last reference to the ISurface
-     * goes away.  (The references will be held on the "proxy" side, while
-     * the Layer exists on the "native" side.)
+     * The layer handle is just a BBinder object passed to the client
+     * (remote process) -- we don't keep any reference on our side such that
+     * the dtor is called when the remote side let go of its reference.
      *
-     * The Layer has a reference to an instance of SurfaceFlinger's variant
-     * of GLConsumer, which holds a reference to the BufferQueue.  The
-     * getSurfaceTexture() call returns a Binder interface reference for
-     * the producer interface of the buffer queue associated with the Layer.
+     * LayerCleaner ensures that mFlinger->onLayerDestroyed() is called for
+     * this layer when the handle is destroyed.
      */
-    class BSurface : public BnSurface, public LayerCleaner {
+
+    class Handle : public BBinder, public LayerCleaner {
         wp<const Layer> mOwner;
-        virtual sp<IGraphicBufferProducer> getSurfaceTexture() const {
-            sp<IGraphicBufferProducer> res;
-            sp<const Layer> that( mOwner.promote() );
-            if (that != NULL) {
-                res = that->mSurfaceFlingerConsumer->getBufferQueue();
-            }
-            return res;
-        }
     public:
-        BSurface(const sp<SurfaceFlinger>& flinger,
-                const sp<Layer>& layer)
-            : LayerCleaner(flinger, layer), mOwner(layer) { }
+        Handle(const sp<SurfaceFlinger>& flinger, const sp<Layer>& layer)
+            : LayerCleaner(flinger, layer), mOwner(layer) {
+        }
     };
-    sp<ISurface> sur(new BSurface(mFlinger, this));
-    return sur;
-}
 
-wp<IBinder> Layer::getSurfaceTextureBinder() const {
-    return mSurfaceFlingerConsumer->getBufferQueue()->asBinder();
+    return new Handle(mFlinger, this);
 }
 
-sp<ISurface> Layer::getSurface()
-{
-    sp<ISurface> s;
-    Mutex::Autolock _l(mLock);
-
-    LOG_ALWAYS_FATAL_IF(mHasSurface,
-            "Layer::getSurface() has already been called");
-
-    mHasSurface = true;
-    s = createSurface();
-    return s;
+sp<BufferQueue> Layer::getBufferQueue() const {
+    return mSurfaceFlingerConsumer->getBufferQueue();
 }
 
+//virtual sp<IGraphicBufferProducer> getSurfaceTexture() const {
+//    sp<IGraphicBufferProducer> res;
+//    sp<const Layer> that( mOwner.promote() );
+//    if (that != NULL) {
+//        res = that->mSurfaceFlingerConsumer->getBufferQueue();
+//    }
+//    return res;
+//}
+
 // ---------------------------------------------------------------------------
 // h/w composer set-up
 // ---------------------------------------------------------------------------
@@ -285,13 +270,24 @@ uint32_t Layer::getContentTransform() const {
     return mCurrentTransform;
 }
 
+static Rect reduce(const Rect& win, const Region& exclude) {
+    if (CC_LIKELY(exclude.isEmpty())) {
+        return win;
+    }
+    if (exclude.isRect()) {
+        return win.reduce(exclude.getBounds());
+    }
+    return Region(win).subtract(exclude).getBounds();
+}
+
 Rect Layer::computeBounds() const {
     const Layer::State& s(drawingState());
     Rect win(s.active.w, s.active.h);
     if (!s.active.crop.isEmpty()) {
         win.intersect(s.active.crop, &win);
     }
-    return win;
+    // subtract the transparent region and snap to the bounds
+    return reduce(win, s.activeTransparentRegion);
 }
 
 Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
@@ -325,6 +321,9 @@ Rect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
     // window's bounds
     activeCrop.intersect(Rect(s.active.w, s.active.h), &activeCrop);
 
+    // subtract the transparent region and snap to the bounds
+    activeCrop = reduce(activeCrop, s.activeTransparentRegion);
+
     if (!activeCrop.isEmpty()) {
         // Transform the window crop to match the buffer coordinate system,
         // which means using the inverse of the current transform set on the
@@ -560,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;
@@ -681,6 +737,8 @@ void Layer::computeGeometry(const sp<const DisplayDevice>& hw, LayerMesh* mesh)
     if (!s.active.crop.isEmpty()) {
         win.intersect(s.active.crop, &win);
     }
+    // subtract the transparent region and snap to the bounds
+    win = reduce(win, s.activeTransparentRegion);
     if (mesh) {
         tr.transform(mesh->mVertices[0], win.left,  win.top);
         tr.transform(mesh->mVertices[1], win.left,  win.bottom);
@@ -897,8 +955,7 @@ bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) {
     return true;
 }
 bool Layer::setTransparentRegionHint(const Region& transparent) {
-    mCurrentState.sequence++;
-    mCurrentState.transparentRegion = transparent;
+    mCurrentState.requestedTransparentRegion = transparent;
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
@@ -1024,7 +1081,6 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
                     swap(bufWidth, bufHeight);
                 }
 
-
                 bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
                 if (front.active != front.requested) {
 
@@ -1077,6 +1133,27 @@ Region Layer::latchBuffer(bool& recomputeVisibleRegions)
                         return true;
                     }
                 }
+
+                // if the transparent region has changed (this test is
+                // conservative, but that's fine, worst case we're doing
+                // a bit of extra work), we latch the new one and we
+                // trigger a visible-region recompute.
+                if (!front.activeTransparentRegion.isTriviallyEqual(
+                        front.requestedTransparentRegion)) {
+                    front.activeTransparentRegion = front.requestedTransparentRegion;
+
+                    // We also need to update the current state so that
+                    // we don't end-up overwriting the drawing state with
+                    // this stale current state during the next transaction
+                    //
+                    // NOTE: We don't need to hold the transaction lock here
+                    // because State::active is only accessed from this thread.
+                    current.activeTransparentRegion = front.activeTransparentRegion;
+
+                    // recompute visible region
+                    recomputeVisibleRegions = true;
+                }
+
                 return false;
             }
         };
@@ -1175,21 +1252,21 @@ void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
 // debugging
 // ----------------------------------------------------------------------------
 
-void Layer::dump(String8& result, char* buffer, size_t SIZE) const
+void Layer::dump(String8& result, Colorizer& colorizer) const
 {
     const Layer::State& s(drawingState());
 
-    snprintf(buffer, SIZE,
+    colorizer.colorize(result, Colorizer::GREEN);
+    result.appendFormat(
             "+ %s %p (%s)\n",
             getTypeId(), this, getName().string());
-    result.append(buffer);
+    colorizer.reset(result);
 
-    s.transparentRegion.dump(result, "transparentRegion");
+    s.activeTransparentRegion.dump(result, "transparentRegion");
     visibleRegion.dump(result, "visibleRegion");
     sp<Client> client(mClientRef.promote());
 
-    snprintf(buffer, SIZE,
-            "      "
+    result.appendFormat(            "      "
             "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
             "isOpaque=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
@@ -1202,7 +1279,6 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const
             s.transform[0][0], s.transform[0][1],
             s.transform[1][0], s.transform[1][1],
             client.get());
-    result.append(buffer);
 
     sp<const GraphicBuffer> buf0(mActiveBuffer);
     uint32_t w0=0, h0=0, s0=0, f0=0;
@@ -1212,26 +1288,19 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const
         s0 = buf0->getStride();
         f0 = buf0->format;
     }
-    snprintf(buffer, SIZE,
+    result.appendFormat(
             "      "
             "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
             " queued-frames=%d, mRefreshPending=%d\n",
             mFormat, w0, h0, s0,f0,
             mQueuedFrames, mRefreshPending);
 
-    result.append(buffer);
-
     if (mSurfaceFlingerConsumer != 0) {
-        mSurfaceFlingerConsumer->dump(result, "            ", buffer, SIZE);
+        mSurfaceFlingerConsumer->dump(result, "            ");
     }
 }
 
-
-void Layer::shortDump(String8& result, char* scratch, size_t size) const {
-    Layer::dump(result, scratch, size);
-}
-
-void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const {
+void Layer::dumpStats(String8& result) const {
     mFrameTracker.dump(result);
 }