OSDN Git Service

SurfaceFlinger: Native changes to add blur effect
authorByunghun Jeon <bjeon@codeaurora.org>
Sat, 6 Dec 2014 02:28:32 +0000 (18:28 -0800)
committerSteve Kondik <steve@cyngn.com>
Sun, 8 Nov 2015 09:07:13 +0000 (01:07 -0800)
Native changes to add blur-behind and blur mask effect

Change-Id: I54faf82d750e8299de6d261f6a893ab26d08df84

SurfaceFlinger: Adding template for LayerBlur files

Change-Id: I444009113b7bdd6c5284863fd1f56358e67d9fe6

SurfaceFlinger: Featurize libuiblur module for OSS build

Change-Id: Ifdc176e699434125d17b111c044b8ba954cf717c

27 files changed:
include/gui/ISurfaceComposerClient.h
include/gui/SurfaceComposerClient.h
include/gui/SurfaceControl.h
include/private/gui/LayerState.h
libs/gui/LayerState.cpp
libs/gui/SurfaceComposerClient.cpp
libs/gui/SurfaceControl.cpp
services/surfaceflinger/Android.mk
services/surfaceflinger/FrameRateHelper.h [new file with mode: 0644]
services/surfaceflinger/Layer.cpp
services/surfaceflinger/Layer.h
services/surfaceflinger/LayerBlur.cpp [new file with mode: 0644]
services/surfaceflinger/LayerBlur.h [new file with mode: 0644]
services/surfaceflinger/LayerDim.cpp
services/surfaceflinger/LayerDim.h
services/surfaceflinger/RenderEngine/Description.cpp
services/surfaceflinger/RenderEngine/Description.h
services/surfaceflinger/RenderEngine/GLES11RenderEngine.h
services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
services/surfaceflinger/RenderEngine/GLES20RenderEngine.h
services/surfaceflinger/RenderEngine/Program.cpp
services/surfaceflinger/RenderEngine/Program.h
services/surfaceflinger/RenderEngine/ProgramCache.cpp
services/surfaceflinger/RenderEngine/ProgramCache.h
services/surfaceflinger/RenderEngine/RenderEngine.h
services/surfaceflinger/SurfaceFlinger.cpp
services/surfaceflinger/SurfaceFlinger.h

index bb79bd0..d3e8b8b 100644 (file)
@@ -50,6 +50,7 @@ public:
         eCursorWindow       = 0x00002000,
 
         eFXSurfaceNormal    = 0x00000000,
+        eFXSurfaceBlur      = 0x00010000,
         eFXSurfaceDim       = 0x00020000,
         eFXSurfaceMask      = 0x000F0000,
     };
index 37d953e..9ec3f23 100644 (file)
@@ -163,6 +163,11 @@ public:
             const Rect& layerStackRect,
             const Rect& displayRect);
 
+    status_t    setBlur(const sp<IBinder>& id, float blur);
+    status_t    setBlurMaskSurface(const sp<IBinder>& id, const sp<IBinder>& maskSurfaceId);
+    status_t    setBlurMaskSampling(const sp<IBinder>& id, uint32_t blurMaskSampling);
+    status_t    setBlurMaskAlphaThreshold(const sp<IBinder>& id, float alpha);
+
 private:
     virtual void onFirstRef();
     Composer& getComposer();
index 9f62f7c..5fa45d1 100644 (file)
@@ -77,6 +77,11 @@ public:
     status_t clearLayerFrameStats() const;
     status_t getLayerFrameStats(FrameStats* outStats) const;
 
+    status_t    setBlur(float blur = 0);
+    status_t    setBlurMaskSurface(const sp<SurfaceControl>& maskSurface);
+    status_t    setBlurMaskSampling(uint32_t blurMaskSampling);
+    status_t    setBlurMaskAlphaThreshold(float alpha);
+
 private:
     // can't be copied
     SurfaceControl& operator = (SurfaceControl& rhs);
index cbe8733..9ff8409 100644 (file)
@@ -52,12 +52,16 @@ struct layer_state_t {
         eFlagsChanged               = 0x00000040,
         eLayerStackChanged          = 0x00000080,
         eCropChanged                = 0x00000100,
+        eBlurChanged                = 0x00400000,
+        eBlurMaskSurfaceChanged     = 0x00800000,
+        eBlurMaskSamplingChanged    = 0x01000000,
+        eBlurMaskAlphaThresholdChanged = 0x02000000,
     };
 
     layer_state_t()
         :   what(0),
-            x(0), y(0), z(0), w(0), h(0), layerStack(0),
-            alpha(0), flags(0), mask(0),
+            x(0), y(0), z(0), w(0), h(0), layerStack(0), blur(0),
+            blurMaskSampling(0), blurMaskAlphaThreshold(0), alpha(0), flags(0), mask(0),
             reserved(0)
     {
         matrix.dsdx = matrix.dtdy = 1.0f;
@@ -82,6 +86,10 @@ struct layer_state_t {
             uint32_t        w;
             uint32_t        h;
             uint32_t        layerStack;
+            float           blur;
+            sp<IBinder>     blurMaskSurface;
+            uint32_t        blurMaskSampling;
+            float           blurMaskAlphaThreshold;
             float           alpha;
             uint8_t         flags;
             uint8_t         mask;
index 00323dc..85452e6 100644 (file)
@@ -32,6 +32,10 @@ status_t layer_state_t::write(Parcel& output) const
     output.writeUint32(w);
     output.writeUint32(h);
     output.writeUint32(layerStack);
+    output.writeFloat(blur);
+    output.writeStrongBinder(blurMaskSurface);
+    output.writeUint32(blurMaskSampling);
+    output.writeFloat(blurMaskAlphaThreshold);
     output.writeFloat(alpha);
     output.writeUint32(flags);
     output.writeUint32(mask);
@@ -52,6 +56,10 @@ status_t layer_state_t::read(const Parcel& input)
     w = input.readUint32();
     h = input.readUint32();
     layerStack = input.readUint32();
+    blur = input.readFloat();
+    blurMaskSurface = input.readStrongBinder();
+    blurMaskSampling = input.readUint32();
+    blurMaskAlphaThreshold = input.readFloat();
     alpha = input.readFloat();
     flags = static_cast<uint8_t>(input.readUint32());
     mask = static_cast<uint8_t>(input.readUint32());
index 9955faf..82bdd6b 100644 (file)
@@ -144,6 +144,14 @@ public:
             uint32_t w, uint32_t h);
     status_t setLayer(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             uint32_t z);
+    status_t setBlur(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+            float blur);
+    status_t setBlurMaskSurface(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+            const sp<IBinder>& maskSurfaceId);
+    status_t setBlurMaskSampling(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+            uint32_t blurMaskSampling);
+    status_t setBlurMaskAlphaThreshold(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
+            float alpha);
     status_t setFlags(const sp<SurfaceComposerClient>& client, const sp<IBinder>& id,
             uint32_t flags, uint32_t mask);
     status_t setTransparentRegionHint(
@@ -303,6 +311,50 @@ status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
     return NO_ERROR;
 }
 
+status_t Composer::setBlur(const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id, float blur) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= layer_state_t::eBlurChanged;
+    s->blur = blur;
+    return NO_ERROR;
+}
+
+status_t Composer::setBlurMaskSurface(const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id, const sp<IBinder>& maskSurfaceId) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= layer_state_t::eBlurMaskSurfaceChanged;
+    s->blurMaskSurface = maskSurfaceId;
+    return NO_ERROR;
+}
+
+status_t Composer::setBlurMaskSampling(const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id, uint32_t blurMaskSampling) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= layer_state_t::eBlurMaskSamplingChanged;
+    s->blurMaskSampling = blurMaskSampling;
+    return NO_ERROR;
+}
+
+status_t Composer::setBlurMaskAlphaThreshold(const sp<SurfaceComposerClient>& client,
+        const sp<IBinder>& id, float alpha) {
+    Mutex::Autolock _l(mLock);
+    layer_state_t* s = getLayerStateLocked(client, id);
+    if (!s)
+        return BAD_INDEX;
+    s->what |= layer_state_t::eBlurMaskAlphaThresholdChanged;
+    s->blurMaskAlphaThreshold = alpha;
+    return NO_ERROR;
+}
+
 status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
         const sp<IBinder>& id, uint32_t flags,
         uint32_t mask) {
@@ -574,6 +626,22 @@ status_t SurfaceComposerClient::setLayer(const sp<IBinder>& id, uint32_t z) {
     return getComposer().setLayer(this, id, z);
 }
 
+status_t SurfaceComposerClient::setBlur(const sp<IBinder>& id, float blur) {
+    return getComposer().setBlur(this, id, blur);
+}
+
+status_t SurfaceComposerClient::setBlurMaskSurface(const sp<IBinder>& id, const sp<IBinder>& maskSurfaceId) {
+    return getComposer().setBlurMaskSurface(this, id, maskSurfaceId);
+}
+
+status_t SurfaceComposerClient::setBlurMaskSampling(const sp<IBinder>& id, uint32_t blurMaskSampling) {
+    return getComposer().setBlurMaskSampling(this, id, blurMaskSampling);
+}
+
+status_t SurfaceComposerClient::setBlurMaskAlphaThreshold(const sp<IBinder>& id, float alpha) {
+    return getComposer().setBlurMaskAlphaThreshold(this, id, alpha);
+}
+
 status_t SurfaceComposerClient::hide(const sp<IBinder>& id) {
     return getComposer().setFlags(this, id,
             layer_state_t::eLayerHidden,
index 1983027..8212b90 100644 (file)
@@ -99,6 +99,26 @@ status_t SurfaceControl::setLayer(uint32_t layer) {
     if (err < 0) return err;
     return mClient->setLayer(mHandle, layer);
 }
+status_t SurfaceControl::setBlur(float blur) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->setBlur(mHandle, blur);
+}
+status_t SurfaceControl::setBlurMaskSurface(const sp<SurfaceControl>& maskSurface) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->setBlurMaskSurface(mHandle, maskSurface != 0 ? maskSurface->mHandle : 0);
+}
+status_t SurfaceControl::setBlurMaskSampling(uint32_t blurMaskSampling) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->setBlurMaskSampling(mHandle, blurMaskSampling);
+}
+status_t SurfaceControl::setBlurMaskAlphaThreshold(float alpha) {
+    status_t err = validate();
+    if (err < 0) return err;
+    return mClient->setBlurMaskAlphaThreshold(mHandle, alpha);
+}
 status_t SurfaceControl::setPosition(float x, float y) {
     status_t err = validate();
     if (err < 0) return err;
index 276a242..c921329 100644 (file)
@@ -13,6 +13,7 @@ LOCAL_SRC_FILES := \
     FrameTracker.cpp \
     Layer.cpp \
     LayerDim.cpp \
+    LayerBlur.cpp \
     MessageQueue.cpp \
     MonitoredProducer.cpp \
     SurfaceFlinger.cpp \
@@ -117,6 +118,12 @@ ifeq ($(TARGET_USES_QCOM_BSP), true)
     LOCAL_CFLAGS += -DQTI_BSP
 endif
 
+ifeq ($(TARGET_HAVE_UI_BLUR),true)
+    LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/ui
+    LOCAL_SHARED_LIBRARIES += libuiblur
+    LOCAL_CFLAGS += -DUI_BLUR
+endif
+
 LOCAL_MODULE := libsurfaceflinger
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
diff --git a/services/surfaceflinger/FrameRateHelper.h b/services/surfaceflinger/FrameRateHelper.h
new file mode 100644 (file)
index 0000000..1a69fed
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_SF_FRAME_RATE_HELPER_H
+#define ANDROID_SF_FRAME_RATE_HELPER_H
+
+#include <utils/Timers.h>
+
+namespace android {
+
+class FrameRateHelper {
+public:
+        FrameRateHelper() : mTime(0), mFps(0), mFpsCount(0) {}
+        ~FrameRateHelper() {}
+
+    bool update() {
+        mFpsCount++;
+
+        nsecs_t now = systemTime();
+        if (ns2ms(now - mTime) > 1000) {
+            mFps = mFpsCount;
+            mFpsCount = 0;
+            mTime = now;
+            return true;
+        }
+
+        return false;
+    }
+
+    unsigned int get() const {
+        return mFps;
+    }
+
+private:
+    nsecs_t mTime;
+    unsigned int mFps;
+    unsigned int mFpsCount;
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SF_FRAME_RATE_HELPER_H
index bcd5915..1ee7242 100644 (file)
@@ -108,6 +108,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client,
     mCurrentState.active.crop.makeInvalid();
     mCurrentState.z = 0;
     mCurrentState.alpha = 0xFF;
+    mCurrentState.blur = 0xFF;
     mCurrentState.layerStack = 0;
     mCurrentState.flags = layerFlags;
     mCurrentState.sequence = 0;
@@ -607,21 +608,21 @@ Rect Layer::getPosition(
 // drawing...
 // ---------------------------------------------------------------------------
 
-void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) const {
+void Layer::draw(const sp<const DisplayDevice>& hw, const Region& clip) {
     onDraw(hw, clip, false);
 }
 
 void Layer::draw(const sp<const DisplayDevice>& hw,
-        bool useIdentityTransform) const {
+        bool useIdentityTransform) {
     onDraw(hw, Region(hw->bounds()), useIdentityTransform);
 }
 
-void Layer::draw(const sp<const DisplayDevice>& hw) const {
+void Layer::draw(const sp<const DisplayDevice>& hw) {
     onDraw(hw, Region(hw->bounds()), false);
 }
 
 void Layer::onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
-        bool useIdentityTransform) const
+        bool useIdentityTransform)
 {
     ATRACE_CALL();
 
@@ -1031,6 +1032,14 @@ bool Layer::setLayer(uint32_t z) {
     setTransactionFlags(eTransactionNeeded);
     return true;
 }
+bool Layer::setBlur(uint8_t blur) {
+    if (mCurrentState.blur == blur)
+        return false;
+    mCurrentState.sequence++;
+    mCurrentState.blur = blur;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
 bool Layer::setSize(uint32_t w, uint32_t h) {
     if (mCurrentState.requested.w == w && mCurrentState.requested.h == h)
         return false;
@@ -1479,13 +1488,13 @@ void Layer::dump(String8& result, Colorizer& colorizer) const
     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"
+            "alpha=0x%02x, blur=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n"
             "      client=%p\n",
             s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
             s.active.crop.left, s.active.crop.top,
             s.active.crop.right, s.active.crop.bottom,
             isOpaque(s), contentDirty,
-            s.alpha, s.flags,
+            s.alpha, s.blur, s.flags,
             s.transform[0][0], s.transform[0][1],
             s.transform[1][0], s.transform[1][1],
             client.get());
index c0c8bf5..e2cb791 100644 (file)
@@ -57,6 +57,7 @@ class Colorizer;
 class DisplayDevice;
 class GraphicBuffer;
 class SurfaceFlinger;
+class LayerBlur;
 
 // ---------------------------------------------------------------------------
 
@@ -70,6 +71,8 @@ class SurfaceFlinger;
 class Layer : public SurfaceFlingerConsumer::ContentsChangedListener {
     static int32_t sSequence;
 
+    friend class LayerBlur;
+
 public:
 #ifdef QTI_BSP
     friend class ExLayer;
@@ -108,6 +111,7 @@ public:
         Geometry requested;
         uint32_t z;
         uint32_t layerStack;
+        uint8_t blur;
         uint8_t alpha;
         uint8_t flags;
         uint8_t reserved[2];
@@ -133,6 +137,10 @@ public:
     // modify current state
     bool setPosition(float x, float y);
     bool setLayer(uint32_t z);
+    bool setBlur(uint8_t blur);
+    virtual bool setBlurMaskLayer(sp<Layer>& /*maskLayer*/) { return false; }
+    virtual bool setBlurMaskSampling(int32_t /*sampling*/) { return false; }
+    virtual bool setBlurMaskAlphaThreshold(float /*alpha*/) { return false; }
     bool setSize(uint32_t w, uint32_t h);
     bool setAlpha(uint8_t alpha);
     bool setMatrix(const layer_state_t::matrix22_t& matrix);
@@ -195,12 +203,17 @@ public:
      */
     virtual bool isFixedSize() const;
 
+    /*
+     * isBlurLayer - true if this is a LayerBlur instance
+     */
+    virtual bool isBlurLayer() const { return false; }
+
 protected:
     /*
      * onDraw - draws the surface.
      */
     virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
-            bool useIdentityTransform) const;
+            bool useIdentityTransform);
 
 public:
     // -----------------------------------------------------------------------
@@ -237,9 +250,9 @@ public:
      * draw - performs some global clipping optimizations
      * and calls onDraw().
      */
-    void draw(const sp<const DisplayDevice>& hw, const Region& clip) const;
-    void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform) const;
-    void draw(const sp<const DisplayDevice>& hw) const;
+    void draw(const sp<const DisplayDevice>& hw, const Region& clip);
+    void draw(const sp<const DisplayDevice>& hw, bool useIdentityTransform);
+    void draw(const sp<const DisplayDevice>& hw);
 
     /*
      * doTransaction - process the transaction. This is a good place to figure
diff --git a/services/surfaceflinger/LayerBlur.cpp b/services/surfaceflinger/LayerBlur.cpp
new file mode 100644 (file)
index 0000000..5c9e8ac
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2007 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+//#define LOG_NDEBUG 0
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+
+#include "LayerBlur.h"
+#include "SurfaceFlinger.h"
+#include "DisplayDevice.h"
+#include "RenderEngine/RenderEngine.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+// Automatically disables scissor test and restores it when destroyed
+class ScopedScissorDisabler {
+    bool scissorEnabled;
+public:
+    ScopedScissorDisabler(bool enabled) : scissorEnabled(enabled) {
+        if(scissorEnabled) {
+            glDisable(GL_SCISSOR_TEST);
+        }
+    }
+    ~ScopedScissorDisabler() {
+        if(scissorEnabled) {
+            glEnable(GL_SCISSOR_TEST);
+        }
+    };
+};
+
+static void setupMeshPartial(Mesh& mesh, Rect rcDraw, Rect rcTexture, int texWidth, int texHeight, int viewportHeight) {
+    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+    position[0] = vec2(rcDraw.left, rcDraw.top);
+    position[1] = vec2(rcDraw.left, rcDraw.bottom);
+    position[2] = vec2(rcDraw.right, rcDraw.bottom);
+    position[3] = vec2(rcDraw.right, rcDraw.top);
+    for(size_t i=0; i<4; ++i) {
+        position[i].y = viewportHeight - position[i].y;
+    }
+
+    Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
+    texCoords[0] = vec2(rcTexture.left/(float)texWidth, 1.0f - rcTexture.top/(float)texHeight);
+    texCoords[1] = vec2(rcTexture.left/(float)texWidth, 1.0f - rcTexture.bottom/(float)texHeight);
+    texCoords[2] = vec2(rcTexture.right/(float)texWidth, 1.0f - rcTexture.bottom/(float)texHeight);
+    texCoords[3] = vec2(rcTexture.right/(float)texWidth, 1.0f - rcTexture.top/(float)texHeight);
+}
+
+static void setupMesh(Mesh& mesh, int width, int height, int viewportHeight) {
+    Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
+    position[0] = vec2(0, 0);
+    position[1] = vec2(0, height);
+    position[2] = vec2(width, height);
+    position[3] = vec2(width, 0);
+    for(size_t i=0; i<4; ++i) {
+        position[i].y = viewportHeight - position[i].y;
+    }
+
+    Mesh::VertexArray<vec2> texCoords(mesh.getTexCoordArray<vec2>());
+    texCoords[0] = vec2(0, 1.0f);
+    texCoords[1] = vec2(0, 0);
+    texCoords[2] = vec2(1.0f, 0);
+    texCoords[3] = vec2(1.0f, 1.0f);
+}
+
+
+LayerBlur::LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client,
+        const String8& name, uint32_t w, uint32_t h, uint32_t flags)
+    : Layer(flinger, client, name, w, h, flags), mBlurMaskSampling(1), mBlurMaskAlphaThreshold(0.0f)
+    ,mLastFrameSequence(0)
+{
+#ifdef UI_BLUR
+    mBlurToken = qtiblur::initBlurToken();
+#endif
+
+    GLuint texnames[3];
+    mFlinger->getRenderEngine().genTextures(3, texnames);
+    mTextureCapture.init(Texture::TEXTURE_2D, texnames[0]);
+    mTextureBlur.init(Texture::TEXTURE_2D, texnames[1]);
+    mTextureMasking.init(Texture::TEXTURE_2D, texnames[2]);
+}
+
+LayerBlur::~LayerBlur() {
+#ifdef UI_BLUR
+    qtiblur::releaseBlurToken(mBlurToken);
+#endif
+
+    releaseFbo(mFboCapture);
+    releaseFbo(mFboMasking);
+    mFlinger->deleteTextureAsync(mTextureCapture.getTextureName());
+    mFlinger->deleteTextureAsync(mTextureBlur.getTextureName());
+    mFlinger->deleteTextureAsync(mTextureMasking.getTextureName());
+}
+
+void LayerBlur::onDraw(const sp<const DisplayDevice>& hw, const Region& /*clip*/,
+        bool useIdentityTransform)
+{
+    clock_t t1 = clock();
+    const ScopedTrace traceTotal(ATRACE_TAG, "Blur.onDraw");
+
+    const Layer::State& s(getDrawingState());
+
+    if (s.alpha==0) {
+        return;
+    }
+
+    /////
+    // NOTE:
+    //
+    // Scissor test has been turned on by SurfaceFlinger for NON-primary display
+    // We need to turn off the scissor test during our fbo drawing
+    GLboolean isScissorEnabled = false;
+    glGetBooleanv(GL_SCISSOR_TEST, &isScissorEnabled);
+    ScopedScissorDisabler _(isScissorEnabled);
+    //
+    /////
+
+
+    int hwWidth = hw->getWidth();
+    int hwHeight = hw->getHeight();
+
+    RenderEngine& engine(mFlinger->getRenderEngine());
+
+    bool savedProjectionYSwap = engine.getProjectionYSwap();
+    Rect savedProjectionSourceCrop = engine.getProjectionSourceCrop();
+    Transform::orientation_flags savedProjectionRotation = engine.getProjectionRotation();
+    size_t savedViewportWidth = engine.getViewportWidth();
+    size_t savedViewportHeight = engine.getViewportHeight();
+
+
+    if (mLastFrameSequence != mFlinger->mActiveFrameSequence ||
+            mTextureBlur.getWidth() == 0 || mTextureBlur.getHeight() == 0) {
+        // full drawing needed.
+
+
+        // capture
+        if (!captureScreen(hw, mFboCapture, mTextureCapture, hwWidth, hwHeight)) {
+            return;
+        }
+
+        // blur
+        size_t outTexWidth = mTextureBlur.getWidth();
+        size_t outTexHeight = mTextureBlur.getHeight();
+#ifdef UI_BLUR
+        if (!qtiblur::blur(mBlurToken,
+                s.blur,
+                mTextureCapture.getTextureName(),
+                mTextureCapture.getWidth(),
+                mTextureCapture.getHeight(),
+                mTextureBlur.getTextureName(),
+                &outTexWidth,
+                &outTexHeight)) {
+            return;
+        }
+#endif
+
+        // mTextureBlur now has "Blurred image"
+        mTextureBlur.setDimensions(outTexWidth, outTexHeight);
+
+    } else {
+        // We can just re-use mTextureBlur.
+        // SurfaceFlinger or other LayerBlur object called my draw() multiple times
+        // while making one frame.
+        //
+        // Fall through
+    }
+
+    // masking
+    bool masking = false;
+    sp<Layer> maskLayer = mBlurMaskLayer.promote();
+    if (maskLayer != 0) {
+        // The larger sampling, the faster drawing.
+        // The smaller sampling, the prettier out line.
+        int sampling = mBlurMaskSampling >= 1 ? mBlurMaskSampling : 1;
+        //ALOGV("maskLayer available, sampling:%d", sampling);
+        masking = drawMaskLayer(maskLayer, hw, mFboMasking, hwWidth, hwHeight, sampling, mTextureMasking);
+    }
+
+
+    // final draw
+    doDrawFinal(hw,
+            savedViewportWidth, savedViewportHeight,
+            savedProjectionSourceCrop,
+            savedProjectionYSwap,
+            savedProjectionRotation,
+            useIdentityTransform,
+            masking ? &mTextureMasking : 0
+            );
+
+    mLastFrameSequence = mFlinger->mActiveFrameSequence;
+
+    clock_t t2 = clock();
+    ALOGV("onDraw took %d ms", (int)(1000*(t2-t1)/CLOCKS_PER_SEC));
+}
+
+
+bool LayerBlur::captureScreen(const sp<const DisplayDevice>& hw, FBO& fbo, Texture& texture, int width, int height) {
+    ATRACE_CALL();
+    ensureFbo(fbo, width, height, texture.getTextureName());
+    if(fbo.fbo == 0) {
+        ALOGE("captureScreen(). fbo.fbo == 0");
+        return false;
+    }
+
+    GLint savedFramebuffer = 0;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &savedFramebuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)fbo.fbo);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+            texture.getTextureTarget(),
+            texture.getTextureName(), 0);
+
+    mFlinger->getRenderEngine().clearWithColor(0.0f, 0.0f, 0.0f, 1.0f);
+    mFlinger->renderScreenImplLocked(
+                hw,
+                Rect(0,0,width,height),
+                width, height,
+                0, getDrawingState().z-1,
+                false,
+                false,
+                Transform::ROT_0);
+
+    glBindFramebuffer(GL_FRAMEBUFFER, savedFramebuffer);
+
+    texture.setDimensions(width, height);
+
+    return true;
+}
+
+bool LayerBlur::drawMaskLayer(sp<Layer>& maskLayer, const sp<const DisplayDevice>& hw,
+        FBO& fbo, int width, int height, int sampling, Texture& texture) {
+    // Draw maskLayer into fbo
+    ATRACE_CALL();
+
+    int maskWidth = width/sampling;
+    int maskHeight = height/sampling;
+
+    ensureFbo(fbo, maskWidth, maskHeight, texture.getTextureName());
+    if(fbo.fbo == 0) {
+        ALOGE("drawMaskLayer(). fbo.fbo == 0");
+        return false;
+    }
+
+    GLint savedFramebuffer = 0;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &savedFramebuffer);
+    glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)fbo.fbo);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+            texture.getTextureTarget(),
+            texture.getTextureName(), 0);
+
+    mFlinger->getRenderEngine().setViewportAndProjection(
+            maskWidth, maskHeight,
+            Rect(0,0,width,height),
+            height,
+            false,
+            Transform::ROT_0
+            );
+    setupMesh(mMesh, width, height, height);
+    mFlinger->getRenderEngine().clearWithColor(0.0f, 0.0f, 0.0f, 0.0f); // alpha must be ZERO
+    maskLayer->draw(hw);
+    glBindFramebuffer(GL_FRAMEBUFFER, savedFramebuffer);
+
+    texture.setDimensions(maskWidth, maskHeight);
+
+    return true;
+}
+
+/*
+ * draw final texture into outer framebuffer
+ */
+void LayerBlur::doDrawFinal(const sp<const DisplayDevice>& hw,
+        int savedViewportWidth, int savedViewportHeight,
+        Rect savedProjectionSourceCrop,
+        bool savedProjectionYSwap,
+        Transform::orientation_flags savedRotation,
+        bool useIdentityTransform,
+        Texture* maskTexture
+        ) {
+    ATRACE_CALL();
+
+    int hwWidth = hw->getWidth();
+    int hwHeight = hw->getHeight();
+
+    RenderEngine& engine(mFlinger->getRenderEngine());
+    const Layer::State& s(getDrawingState());
+
+    Transform trToDraw(useIdentityTransform ? hw->getTransform() : hw->getTransform() * s.transform);
+    Transform trToMapTexture(hw->getTransform() * s.transform);
+
+    Rect frameToDraw(trToDraw.transform(Rect(s.active.w, s.active.h)));
+    Rect frameToMapTexture(trToMapTexture.transform(Rect(s.active.w, s.active.h)));
+
+    engine.setViewportAndProjection(
+            savedViewportWidth, savedViewportHeight,
+            savedProjectionSourceCrop,
+            hwHeight,
+            savedProjectionYSwap,
+            savedRotation
+            );
+
+
+    const mat4 identity;
+    float textureMatrix[16];
+    memcpy(textureMatrix, identity.asArray(), sizeof(textureMatrix));
+
+    //mTextureBlur.setDimensions(hwWidth, hwHeight);
+    mTextureBlur.setFiltering(true);
+    mTextureBlur.setMatrix(textureMatrix);
+
+    if (maskTexture != 0) {
+        maskTexture->setFiltering(false);
+        maskTexture->setMatrix(textureMatrix);
+    }
+
+    setupMeshPartial(mMesh, frameToDraw, frameToMapTexture, hwWidth, hwHeight,
+            savedProjectionSourceCrop.height());
+
+    engine.setupLayerTexturing(mTextureBlur);
+    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), s.alpha);
+    if (maskTexture) {
+        engine.setupLayerMasking(*maskTexture, mBlurMaskAlphaThreshold);
+    }
+    engine.drawMesh(mMesh);
+    engine.disableLayerMasking();
+    engine.disableBlending();
+    engine.disableTexturing();
+
+}
+
+bool LayerBlur::isVisible() const {
+    const Layer::State& s(getDrawingState());
+    return !(s.flags & layer_state_t::eLayerHidden) && s.alpha;
+}
+
+bool LayerBlur::setBlurMaskLayer(sp<Layer>& maskLayer) {
+    if (maskLayer == mBlurMaskLayer) {
+        return false;
+    }
+    mBlurMaskLayer = maskLayer;
+    return true;
+}
+
+
+void LayerBlur::initFbo(FBO& fbobj, int width, int height, int textureName) {
+    GLuint fbo=0;
+
+    glGenFramebuffers(1, &fbo);
+    glBindTexture(GL_TEXTURE_2D, textureName);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height,
+            0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+    glBindTexture(GL_TEXTURE_2D, 0);
+
+    GLint savedFramebuffer = 0;
+    glGetIntegerv(GL_FRAMEBUFFER_BINDING, &savedFramebuffer);
+
+    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+            GL_TEXTURE_2D, textureName, 0);
+    glBindFramebuffer(GL_FRAMEBUFFER, savedFramebuffer);
+
+    fbobj.fbo = fbo;
+    fbobj.width = width;
+    fbobj.height = height;
+}
+
+void LayerBlur::releaseFbo(FBO& fbo) {
+    if(fbo.fbo != 0) {
+        glDeleteFramebuffers(1, (GLuint*)&fbo.fbo);
+    }
+    fbo.fbo = 0;
+    fbo.width = 0;
+    fbo.height = 0;
+}
+
+void LayerBlur::ensureFbo(FBO& fbo, int width, int height, int textureName) {
+    if(fbo.fbo != 0) {
+        if(fbo.width != width || fbo.height != height) {
+            releaseFbo(fbo);
+        }
+    }
+    if(fbo.fbo == 0) {
+        initFbo(fbo, width, height, textureName);
+    }
+}
+
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/services/surfaceflinger/LayerBlur.h b/services/surfaceflinger/LayerBlur.h
new file mode 100644 (file)
index 0000000..251423e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2007 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.
+ */
+
+#ifndef ANDROID_LAYER_BLUR_H
+#define ANDROID_LAYER_BLUR_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "Layer.h"
+
+#ifdef UI_BLUR
+#include "Blur.h"           // libuiblur.so
+#endif
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+/**
+ * Blur layer object.
+ * Actual blurring logics are capsulated in libuiblur.so
+ */
+class LayerBlur : public Layer
+{
+public:
+    LayerBlur(SurfaceFlinger* flinger, const sp<Client>& client,
+            const String8& name, uint32_t w, uint32_t h, uint32_t flags);
+    virtual ~LayerBlur();
+
+    virtual const char* getTypeId() const { return "LayerBlur"; }
+    virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
+            bool useIdentityTransform);
+    virtual bool isOpaque(const Layer::State& /*s*/) const { return false; }
+    virtual bool isSecure() const         { return false; }
+    virtual bool isFixedSize() const      { return true; }
+    virtual bool isVisible() const;
+
+    virtual bool isBlurLayer() const      { return true; }
+    virtual bool setBlurMaskLayer(sp<Layer>& maskLayer);
+    virtual bool setBlurMaskSampling(int32_t sampling) { mBlurMaskSampling = sampling; return true; }
+    virtual bool setBlurMaskAlphaThreshold(float alpha) { mBlurMaskAlphaThreshold = alpha; return true; }
+
+private:
+#ifdef UI_BLUR
+    qtiblur::BLUR_TOKEN mBlurToken;
+#endif
+    wp<Layer> mBlurMaskLayer;
+    int32_t mBlurMaskSampling;
+    float mBlurMaskAlphaThreshold;
+    uint32_t mLastFrameSequence;
+
+    class FBO {
+    public:
+        FBO() : fbo(0), width(0), height(0) {}
+        int fbo;
+        int width;
+        int height;
+    };
+
+    void initFbo(FBO& fbo, int width, int height, int textureName);
+    void releaseFbo(FBO& fbo);
+    void ensureFbo(FBO& fbo, int width, int height, int textureName);
+
+
+    FBO mFboCapture;
+    Texture mTextureCapture;
+
+    Texture mTextureBlur;
+
+    FBO mFboMasking;
+    Texture mTextureMasking;
+
+    bool captureScreen(const sp<const DisplayDevice>& hw,
+            FBO& fbo, Texture& texture, int width, int height);
+    void doDrawFinal(const sp<const DisplayDevice>& hw,
+        int savedViewportWidth, int savedViewportHeight,
+        Rect savedProjectionSourceCrop, bool savedProjectionYSwap,
+        Transform::orientation_flags savedRotation, bool useIdentityTransform,
+        Texture* maskTexture);
+    bool drawMaskLayer(sp<Layer>& maskLayer, const sp<const DisplayDevice>& hw,
+        FBO& fbo, int width, int height, int sampling, Texture& texture);
+
+};
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_LAYER_BLUR_H
index b8d549a..5afd291 100644 (file)
@@ -40,7 +40,7 @@ LayerDim::~LayerDim() {
 }
 
 void LayerDim::onDraw(const sp<const DisplayDevice>& hw,
-        const Region& /* clip */, bool useIdentityTransform) const
+        const Region& /* clip */, bool useIdentityTransform)
 {
     const State& s(getDrawingState());
     if (s.alpha>0) {
index b66591b..01f71cc 100644 (file)
@@ -35,7 +35,7 @@ public:
 
     virtual const char* getTypeId() const { return "LayerDim"; }
     virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip,
-            bool useIdentityTransform) const;
+            bool useIdentityTransform);
     virtual bool isOpaque(const Layer::State&) const { return false; }
     virtual bool isSecure() const         { return false; }
     virtual bool isFixedSize() const      { return true; }
index 0dab872..14607ca 100644 (file)
@@ -33,6 +33,8 @@ Description::Description() :
     mOpaque = true;
     mTextureEnabled = false;
     mColorMatrixEnabled = false;
+    mMaskTextureEnabled = false;
+    mMaskAlphaThreshold = 0.0f;
 
     memset(mColor, 0, sizeof(mColor));
 }
@@ -92,5 +94,14 @@ const mat4& Description::getColorMatrix() const {
     return mColorMatrix;
 }
 
+void Description::setMasking(const Texture& maskTexture, float alphaThreshold) {
+    mMaskTexture = maskTexture;
+    mMaskTextureEnabled = true;
+    mMaskAlphaThreshold = alphaThreshold;
+}
+
+void Description::disableMasking() {
+    mMaskTextureEnabled = false;
+}
 
 } /* namespace android */
index 8a3447c..2bfb632 100644 (file)
@@ -53,6 +53,9 @@ class Description {
 
     bool mColorMatrixEnabled;
     mat4 mColorMatrix;
+    Texture mMaskTexture;
+    bool mMaskTextureEnabled;
+    GLclampf mMaskAlphaThreshold;
 
 public:
     Description();
@@ -67,6 +70,8 @@ public:
     void setProjectionMatrix(const mat4& mtx);
     void setColorMatrix(const mat4& mtx);
     const mat4& getColorMatrix() const;
+    void setMasking(const Texture& maskTexture, float alphaThreshold);
+    void disableMasking();
 
 private:
     bool mUniformsDirty;
index 77824ce..cb13ee0 100644 (file)
@@ -60,6 +60,8 @@ protected:
     virtual void setupFillWithColor(float r, float g, float b, float a) ;
     virtual void disableTexturing();
     virtual void disableBlending();
+    virtual void setupLayerMasking(const Texture& /*maskTexture*/, float /*alphaThreshold*/) {}
+    virtual void disableLayerMasking() {}
 
     virtual void drawMesh(const Mesh& mesh);
 
index a35aa78..6333a41 100644 (file)
@@ -40,7 +40,7 @@ namespace android {
 // ---------------------------------------------------------------------------
 
 GLES20RenderEngine::GLES20RenderEngine() :
-        mVpWidth(0), mVpHeight(0) {
+        mVpWidth(0), mVpHeight(0), mProjectionRotation(Transform::ROT_0) {
 
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
@@ -115,6 +115,9 @@ void GLES20RenderEngine::setViewportAndProjection(
     mState.setProjectionMatrix(m);
     mVpWidth = vpw;
     mVpHeight = vph;
+    mProjectionSourceCrop = sourceCrop;
+    mProjectionYSwap = yswap;
+    mProjectionRotation = rotation;
 }
 
 void GLES20RenderEngine::setupLayerBlending(
@@ -264,6 +267,30 @@ void GLES20RenderEngine::dump(String8& result) {
     RenderEngine::dump(result);
 }
 
+void GLES20RenderEngine::setupLayerMasking(const Texture& maskTexture, float alphaThreshold) {
+    glActiveTexture(GL_TEXTURE0 + 1);
+    GLuint target = maskTexture.getTextureTarget();
+    glBindTexture(target, maskTexture.getTextureName());
+    GLenum filter = GL_NEAREST;
+    if (maskTexture.getFiltering()) {
+        filter = GL_LINEAR;
+    }
+    glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter);
+    glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter);
+
+    if (alphaThreshold < 0) alphaThreshold = 0;
+    if (alphaThreshold > 1.0f) alphaThreshold = 1.0f;
+
+    mState.setMasking(maskTexture, alphaThreshold);
+    glActiveTexture(GL_TEXTURE0);
+}
+
+void GLES20RenderEngine::disableLayerMasking() {
+    mState.disableMasking();
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
 // ---------------------------------------------------------------------------
index 6074a3d..414a999 100644 (file)
@@ -42,6 +42,9 @@ class GLES20RenderEngine : public RenderEngine {
     GLint mMaxTextureSize;
     GLuint mVpWidth;
     GLuint mVpHeight;
+    Rect mProjectionSourceCrop;
+    bool mProjectionYSwap;
+    Transform::orientation_flags mProjectionRotation;
 
     struct Group {
         GLuint texture;
@@ -76,11 +79,18 @@ protected:
     virtual mat4 setupColorTransform(const mat4& colorTransform);
     virtual void disableTexturing();
     virtual void disableBlending();
+    virtual void setupLayerMasking(const Texture& maskTexture, float alphaThreshold);
+    virtual void disableLayerMasking();
 
     virtual void drawMesh(const Mesh& mesh);
 
     virtual size_t getMaxTextureSize() const;
     virtual size_t getMaxViewportDims() const;
+    virtual bool getProjectionYSwap() { return mProjectionYSwap; }
+    virtual size_t getViewportWidth() const { return mVpWidth; }
+    virtual size_t getViewportHeight() const { return mVpHeight; }
+    virtual Rect getProjectionSourceCrop() const { return mProjectionSourceCrop; }
+    virtual Transform::orientation_flags getProjectionRotation() const { return mProjectionRotation; }
 };
 
 // ---------------------------------------------------------------------------
index 0424e0c..936cb1b 100644 (file)
@@ -64,6 +64,8 @@ Program::Program(const ProgramCache::Key& /*needs*/, const char* vertex, const c
         mSamplerLoc = glGetUniformLocation(programId, "sampler");
         mColorLoc = glGetUniformLocation(programId, "color");
         mAlphaPlaneLoc = glGetUniformLocation(programId, "alphaPlane");
+        mSamplerMaskLoc = glGetUniformLocation(programId, "samplerMask");
+        mMaskAlphaThresholdLoc = glGetUniformLocation(programId, "maskAlphaThreshold");
 
         // set-up the default values for our uniforms
         glUseProgram(programId);
@@ -143,6 +145,12 @@ void Program::setUniforms(const Description& desc) {
     }
     // these uniforms are always present
     glUniformMatrix4fv(mProjectionMatrixLoc, 1, GL_FALSE, desc.mProjectionMatrix.asArray());
+    if (mSamplerMaskLoc >= 0) {
+        glUniform1i(mSamplerMaskLoc, 1);
+    }
+    if (mMaskAlphaThresholdLoc >= 0) {
+        glUniform1f(mMaskAlphaThresholdLoc, desc.mMaskAlphaThreshold);
+    }
 }
 
 } /* namespace android */
index 36bd120..08dee59 100644 (file)
@@ -84,6 +84,9 @@ private:
 
     /* location of the color uniform */
     GLint mColorLoc;
+
+    GLint mSamplerMaskLoc;
+    GLint mMaskAlphaThresholdLoc;
 };
 
 
index ba11259..33ff7d0 100644 (file)
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
@@ -110,9 +112,27 @@ void ProgramCache::primeCache() {
             shaderCount++;
         }
     }
+
+    // Keys that are actually used by blurring.
+    // This is obtained by log msg from useProgram()
+    uint32_t blurringKeys[] = {
+        0x01000015,
+        0x01000011,
+    };
+    for (size_t i=0; i<sizeof(blurringKeys)/sizeof(blurringKeys[0]); ++i) {
+        Key shaderKey;
+        shaderKey.set(blurringKeys[i], blurringKeys[i]);
+        Program* program = mCache.valueFor(shaderKey);
+        if (program == NULL) {
+            program = generateProgram(shaderKey);
+            mCache.add(shaderKey, program);
+            shaderCount++;
+        }
+    }
+
     nsecs_t timeAfter = systemTime();
     float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
-    ALOGD("shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs);
+    ALOGD("SF. shader cache generated - %u shaders in %f ms\n", shaderCount, compileTimeMs);
 }
 
 ProgramCache::Key ProgramCache::computeKey(const Description& description) {
@@ -129,15 +149,20 @@ ProgramCache::Key ProgramCache::computeKey(const Description& description) {
     .set(Key::OPACITY_MASK,
             description.mOpaque ? Key::OPACITY_OPAQUE : Key::OPACITY_TRANSLUCENT)
     .set(Key::COLOR_MATRIX_MASK,
-            description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON :  Key::COLOR_MATRIX_OFF);
+            description.mColorMatrixEnabled ? Key::COLOR_MATRIX_ON :  Key::COLOR_MATRIX_OFF)
+    .set(Key::TEXTURE_MASKING_MASK,
+            !description.mMaskTextureEnabled ? Key::TEXTURE_MASKING_OFF :
+            description.mMaskTexture.getTextureTarget() == GL_TEXTURE_EXTERNAL_OES ? Key::TEXTURE_MASKING_EXT :
+            description.mMaskTexture.getTextureTarget() == GL_TEXTURE_2D           ? Key::TEXTURE_MASKING_2D :
+            Key::TEXTURE_MASKING_OFF);
     return needs;
 }
 
 String8 ProgramCache::generateVertexShader(const Key& needs) {
     Formatter vs;
     if (needs.isTexturing()) {
-        vs  << "attribute vec4 texCoords;"
-            << "varying vec2 outTexCoords;";
+        vs << "attribute vec4 texCoords;"
+           << "varying vec2 outTexCoords;";
     }
     vs << "attribute vec4 position;"
        << "uniform mat4 projection;"
@@ -145,7 +170,7 @@ String8 ProgramCache::generateVertexShader(const Key& needs) {
        << "void main(void) {" << indent
        << "gl_Position = projection * position;";
     if (needs.isTexturing()) {
-        vs << "outTexCoords = (texture * texCoords).st;";
+       vs << "outTexCoords = (texture * texCoords).st;";
     }
     vs << dedent << "}";
     return vs.getString();
@@ -169,6 +194,14 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) {
     } else if (needs.getTextureTarget() == Key::TEXTURE_OFF) {
         fs << "uniform vec4 color;";
     }
+    if (needs.getTextureMaskingTarget() == Key::TEXTURE_MASKING_EXT) {
+        fs << "uniform samplerExternalOES samplerMask;";
+    } else if (needs.getTextureMaskingTarget() == Key::TEXTURE_MASKING_2D) {
+        fs << "uniform sampler2D samplerMask;";
+    }
+    if (needs.getTextureMaskingTarget() != Key::TEXTURE_MASKING_OFF) {
+        fs << "uniform float maskAlphaThreshold;";
+    }
     if (needs.hasPlaneAlpha()) {
         fs << "uniform float alphaPlane;";
     }
@@ -177,7 +210,12 @@ String8 ProgramCache::generateFragmentShader(const Key& needs) {
     }
     fs << "void main(void) {" << indent;
     if (needs.isTexturing()) {
-        fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
+        if (needs.getTextureMaskingTarget() != Key::TEXTURE_MASKING_OFF) {
+            fs << "if (texture2D(samplerMask, outTexCoords).a <= maskAlphaThreshold) discard;"
+               << "gl_FragColor = texture2D(sampler, outTexCoords);";
+        } else {
+            fs << "gl_FragColor = texture2D(sampler, outTexCoords);";
+        }
     } else {
         fs << "gl_FragColor = color;";
     }
@@ -235,9 +273,6 @@ void ProgramCache::useProgram(const Description& description) {
         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
index 1fa53d3..3824e73 100644 (file)
@@ -69,6 +69,11 @@ public:
             COLOR_MATRIX_OFF        =       0x00000000,
             COLOR_MATRIX_ON         =       0x00000020,
             COLOR_MATRIX_MASK       =       0x00000020,
+
+            TEXTURE_MASKING_OFF     =       0x00000000,
+            TEXTURE_MASKING_EXT     =       0x00800000,
+            TEXTURE_MASKING_2D      =       0x01000000,
+            TEXTURE_MASKING_MASK    =       0x01800000,
         };
 
         inline Key() : mKey(0) { }
@@ -97,6 +102,12 @@ public:
         inline bool hasColorMatrix() const {
             return (mKey & COLOR_MATRIX_MASK) == COLOR_MATRIX_ON;
         }
+        inline bool isTextureMasking() const {
+            return (mKey & TEXTURE_MASKING_MASK) != TEXTURE_MASKING_OFF;
+        }
+        inline int getTextureMaskingTarget() const {
+            return (mKey & TEXTURE_MASKING_MASK);
+        }
 
         // this is the definition of a friend function -- not a method of class Needs
         friend inline int strictly_order_type(const Key& lhs, const Key& rhs) {
index c9a043a..a669fdd 100644 (file)
@@ -110,6 +110,8 @@ public:
 
     virtual void disableTexturing() = 0;
     virtual void disableBlending() = 0;
+    virtual void setupLayerMasking(const Texture& maskTexture, float alphaThreshold) = 0;
+    virtual void disableLayerMasking() = 0;
 
     // drawing
     virtual void drawMesh(const Mesh& mesh) = 0;
@@ -117,6 +119,11 @@ public:
     // queries
     virtual size_t getMaxTextureSize() const = 0;
     virtual size_t getMaxViewportDims() const = 0;
+    virtual bool getProjectionYSwap() { return 0; }
+    virtual size_t getViewportWidth() const { return 1; }
+    virtual size_t getViewportHeight() const { return 1; }
+    virtual Rect getProjectionSourceCrop() const { return Rect(0, 0, 1, 1); }
+    virtual Transform::orientation_flags getProjectionRotation() const { return Transform::ROT_0; }
 
     EGLConfig getEGLConfig() const;
     EGLContext getEGLContext() const;
index fc99fa0..cea463a 100644 (file)
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <stdint.h>
@@ -68,6 +69,7 @@
 #include "EventThread.h"
 #include "Layer.h"
 #include "LayerDim.h"
+#include "LayerBlur.h"
 #include "SurfaceFlinger.h"
 
 #include "DisplayHardware/FramebufferSurface.h"
@@ -157,7 +159,8 @@ SurfaceFlinger::SurfaceFlinger()
         mHasPoweredOff(false),
         mFrameBuckets(),
         mTotalTime(0),
-        mLastSwapTime(0)
+        mLastSwapTime(0),
+        mActiveFrameSequence(0)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -1249,6 +1252,8 @@ void SurfaceFlinger::doComposition() {
             // repaint the framebuffer (if needed)
             doDisplayComposition(hw, dirtyRegion);
 
+            ++mActiveFrameSequence;
+
             hw->dirtyRegion.clear();
             hw->flip(hw->swapRegion);
             hw->swapRegion.clear();
@@ -1309,6 +1314,7 @@ void SurfaceFlinger::postFramebuffer()
     if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
         logFrameStats();
     }
+    ALOGV_IF(mFrameRateHelper.update(), "FPS: %d", mFrameRateHelper.get());
 }
 
 void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
@@ -2277,6 +2283,41 @@ uint32_t SurfaceFlinger::setClientStateLocked(
                 flags |= eTransactionNeeded|eTraversalNeeded;
             }
         }
+        if (what & layer_state_t::eBlurChanged) {
+            ALOGV("eBlurChanged");
+            if (layer->setBlur(uint8_t(255.0f*s.blur+0.5f))) {
+                flags |= eTraversalNeeded;
+            }
+        }
+        if (what & layer_state_t::eBlurMaskSurfaceChanged) {
+            ALOGV("eBlurMaskSurfaceChanged");
+            sp<Layer> maskLayer = 0;
+            if (s.blurMaskSurface != 0) {
+                maskLayer = client->getLayerUser(s.blurMaskSurface);
+            }
+            if (maskLayer == 0) {
+                ALOGV("eBlurMaskSurfaceChanged. maskLayer == 0");
+            } else {
+                ALOGV("eBlurMaskSurfaceChagned. maskLayer.z == %d", maskLayer->getCurrentState().z);
+                if (maskLayer->isBlurLayer()) {
+                    ALOGE("Blur layer can not be used as blur mask surface");
+                    maskLayer = 0;
+                }
+            }
+            if (layer->setBlurMaskLayer(maskLayer)) {
+                flags |= eTraversalNeeded;
+            }
+        }
+        if (what & layer_state_t::eBlurMaskSamplingChanged) {
+            if (layer->setBlurMaskSampling(s.blurMaskSampling)) {
+                flags |= eTraversalNeeded;
+            }
+        }
+        if (what & layer_state_t::eBlurMaskAlphaThresholdChanged) {
+            if (layer->setBlurMaskAlphaThreshold(s.blurMaskAlphaThreshold)) {
+                flags |= eTraversalNeeded;
+            }
+        }
         if (what & layer_state_t::eSizeChanged) {
             if (layer->setSize(s.w, s.h)) {
                 flags |= eTraversalNeeded;
@@ -2345,6 +2386,11 @@ status_t SurfaceFlinger::createLayer(
                     name, w, h, flags,
                     handle, gbp, &layer);
             break;
+        case ISurfaceComposerClient::eFXSurfaceBlur:
+            result = createBlurLayer(client,
+                    name, w, h, flags,
+                    handle, gbp, &layer);
+            break;
         default:
             result = BAD_VALUE;
             break;
@@ -2399,6 +2445,16 @@ status_t SurfaceFlinger::createDimLayer(const sp<Client>& client,
     return NO_ERROR;
 }
 
+status_t SurfaceFlinger::createBlurLayer(const sp<Client>& client,
+        const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+        sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
+{
+    *outLayer = new LayerBlur(this, client, name, w, h, flags);
+    *handle = (*outLayer)->getHandle();
+    *gbp = (*outLayer)->getProducer();
+    return NO_ERROR;
+}
+
 status_t SurfaceFlinger::onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle)
 {
     // called by the window manager when it wants to remove a Layer
@@ -3407,6 +3463,8 @@ status_t SurfaceFlinger::captureScreenImplLocked(
         return BAD_VALUE;
     }
 
+    ++mActiveFrameSequence;
+
     reqWidth  = (!reqWidth)  ? hw_w : reqWidth;
     reqHeight = (!reqHeight) ? hw_h : reqHeight;
 
index 4bbb1f4..2028d67 100644 (file)
@@ -56,6 +56,8 @@
 #include "DisplayHardware/HWComposer.h"
 #include "Effects/Daltonizer.h"
 
+#include "FrameRateHelper.h"
+
 namespace android {
 
 // ---------------------------------------------------------------------------
@@ -66,6 +68,7 @@ class EventThread;
 class IGraphicBufferAlloc;
 class Layer;
 class LayerDim;
+class LayerBlur;
 class Surface;
 class RenderEngine;
 class EventControlThread;
@@ -144,6 +147,7 @@ private:
     friend class Layer;
     friend class LayerDim;
     friend class MonitoredProducer;
+    friend class LayerBlur;
 
     // This value is specified in number of frames.  Log frame stats at most
     // every half hour.
@@ -337,6 +341,10 @@ private:
             uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
             sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
 
+    status_t createBlurLayer(const sp<Client>& client, const String8& name,
+            uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
+            sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
+
     // called in response to the window-manager calling
     // ISurfaceComposerClient::destroySurface()
     status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
@@ -550,6 +558,17 @@ private:
     nsecs_t mFrameBuckets[NUM_BUCKETS];
     nsecs_t mTotalTime;
     nsecs_t mLastSwapTime;
+
+    FrameRateHelper mFrameRateHelper;
+
+    /*
+     * A number that increases on every new frame composition and screen capture.
+     * LayerBlur can speed up it's drawing by caching texture using this variable
+     * if multiple LayerBlur objects draw in one frame composition.
+     * In case of display mirroring, this variable should be increased on every display.
+     */
+    uint32_t mActiveFrameSequence;
+
 };
 
 }; // namespace android