From 987034b5633d0eb7fca806acfe00ddbe3305b159 Mon Sep 17 00:00:00 2001 From: Byunghun Jeon Date: Fri, 5 Dec 2014 18:28:32 -0800 Subject: [PATCH] SurfaceFlinger: Native changes to add blur effect 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 --- include/gui/ISurfaceComposerClient.h | 1 + include/gui/SurfaceComposerClient.h | 5 + include/gui/SurfaceControl.h | 5 + include/private/gui/LayerState.h | 12 +- libs/gui/LayerState.cpp | 8 + libs/gui/SurfaceComposerClient.cpp | 68 +++ libs/gui/SurfaceControl.cpp | 20 + services/surfaceflinger/Android.mk | 7 + services/surfaceflinger/FrameRateHelper.h | 69 +++ services/surfaceflinger/Layer.cpp | 21 +- services/surfaceflinger/Layer.h | 21 +- services/surfaceflinger/LayerBlur.cpp | 415 ++++++++++++++++++ services/surfaceflinger/LayerBlur.h | 106 +++++ services/surfaceflinger/LayerDim.cpp | 2 +- services/surfaceflinger/LayerDim.h | 2 +- .../RenderEngine/Description.cpp | 11 + .../surfaceflinger/RenderEngine/Description.h | 5 + .../RenderEngine/GLES11RenderEngine.h | 2 + .../RenderEngine/GLES20RenderEngine.cpp | 29 +- .../RenderEngine/GLES20RenderEngine.h | 10 + .../surfaceflinger/RenderEngine/Program.cpp | 8 + .../surfaceflinger/RenderEngine/Program.h | 3 + .../RenderEngine/ProgramCache.cpp | 53 ++- .../RenderEngine/ProgramCache.h | 11 + .../RenderEngine/RenderEngine.h | 7 + services/surfaceflinger/SurfaceFlinger.cpp | 60 ++- services/surfaceflinger/SurfaceFlinger.h | 19 + 27 files changed, 955 insertions(+), 25 deletions(-) create mode 100644 services/surfaceflinger/FrameRateHelper.h create mode 100644 services/surfaceflinger/LayerBlur.cpp create mode 100644 services/surfaceflinger/LayerBlur.h diff --git a/include/gui/ISurfaceComposerClient.h b/include/gui/ISurfaceComposerClient.h index bb79bd02b..d3e8b8ba1 100644 --- a/include/gui/ISurfaceComposerClient.h +++ b/include/gui/ISurfaceComposerClient.h @@ -50,6 +50,7 @@ public: eCursorWindow = 0x00002000, eFXSurfaceNormal = 0x00000000, + eFXSurfaceBlur = 0x00010000, eFXSurfaceDim = 0x00020000, eFXSurfaceMask = 0x000F0000, }; diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h index 37d953e18..9ec3f2349 100644 --- a/include/gui/SurfaceComposerClient.h +++ b/include/gui/SurfaceComposerClient.h @@ -163,6 +163,11 @@ public: const Rect& layerStackRect, const Rect& displayRect); + status_t setBlur(const sp& id, float blur); + status_t setBlurMaskSurface(const sp& id, const sp& maskSurfaceId); + status_t setBlurMaskSampling(const sp& id, uint32_t blurMaskSampling); + status_t setBlurMaskAlphaThreshold(const sp& id, float alpha); + private: virtual void onFirstRef(); Composer& getComposer(); diff --git a/include/gui/SurfaceControl.h b/include/gui/SurfaceControl.h index 9f62f7c72..5fa45d166 100644 --- a/include/gui/SurfaceControl.h +++ b/include/gui/SurfaceControl.h @@ -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& maskSurface); + status_t setBlurMaskSampling(uint32_t blurMaskSampling); + status_t setBlurMaskAlphaThreshold(float alpha); + private: // can't be copied SurfaceControl& operator = (SurfaceControl& rhs); diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h index cbe87330e..9ff840991 100644 --- a/include/private/gui/LayerState.h +++ b/include/private/gui/LayerState.h @@ -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 blurMaskSurface; + uint32_t blurMaskSampling; + float blurMaskAlphaThreshold; float alpha; uint8_t flags; uint8_t mask; diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 00323dc4f..85452e668 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -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(input.readUint32()); mask = static_cast(input.readUint32()); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 9955faf26..82bdd6b12 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -144,6 +144,14 @@ public: uint32_t w, uint32_t h); status_t setLayer(const sp& client, const sp& id, uint32_t z); + status_t setBlur(const sp& client, const sp& id, + float blur); + status_t setBlurMaskSurface(const sp& client, const sp& id, + const sp& maskSurfaceId); + status_t setBlurMaskSampling(const sp& client, const sp& id, + uint32_t blurMaskSampling); + status_t setBlurMaskAlphaThreshold(const sp& client, const sp& id, + float alpha); status_t setFlags(const sp& client, const sp& id, uint32_t flags, uint32_t mask); status_t setTransparentRegionHint( @@ -303,6 +311,50 @@ status_t Composer::setLayer(const sp& client, return NO_ERROR; } +status_t Composer::setBlur(const sp& client, + const sp& 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& client, + const sp& id, const sp& 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& client, + const sp& 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& client, + const sp& 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& client, const sp& id, uint32_t flags, uint32_t mask) { @@ -574,6 +626,22 @@ status_t SurfaceComposerClient::setLayer(const sp& id, uint32_t z) { return getComposer().setLayer(this, id, z); } +status_t SurfaceComposerClient::setBlur(const sp& id, float blur) { + return getComposer().setBlur(this, id, blur); +} + +status_t SurfaceComposerClient::setBlurMaskSurface(const sp& id, const sp& maskSurfaceId) { + return getComposer().setBlurMaskSurface(this, id, maskSurfaceId); +} + +status_t SurfaceComposerClient::setBlurMaskSampling(const sp& id, uint32_t blurMaskSampling) { + return getComposer().setBlurMaskSampling(this, id, blurMaskSampling); +} + +status_t SurfaceComposerClient::setBlurMaskAlphaThreshold(const sp& id, float alpha) { + return getComposer().setBlurMaskAlphaThreshold(this, id, alpha); +} + status_t SurfaceComposerClient::hide(const sp& id) { return getComposer().setFlags(this, id, layer_state_t::eLayerHidden, diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 198302780..8212b9095 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -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& 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; diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index 276a242a3..c9213293b 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -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 index 000000000..1a69fed18 --- /dev/null +++ b/services/surfaceflinger/FrameRateHelper.h @@ -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 + +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 diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index bcd591523..1ee7242c4 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -108,6 +108,7 @@ Layer::Layer(SurfaceFlinger* flinger, const sp& 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& hw, const Region& clip) const { +void Layer::draw(const sp& hw, const Region& clip) { onDraw(hw, clip, false); } void Layer::draw(const sp& hw, - bool useIdentityTransform) const { + bool useIdentityTransform) { onDraw(hw, Region(hw->bounds()), useIdentityTransform); } -void Layer::draw(const sp& hw) const { +void Layer::draw(const sp& hw) { onDraw(hw, Region(hw->bounds()), false); } void Layer::onDraw(const sp& 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()); diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index c0c8bf525..e2cb791ea 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -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& /*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& 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& hw, const Region& clip) const; - void draw(const sp& hw, bool useIdentityTransform) const; - void draw(const sp& hw) const; + void draw(const sp& hw, const Region& clip); + void draw(const sp& hw, bool useIdentityTransform); + void draw(const sp& 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 index 000000000..5c9e8ace7 --- /dev/null +++ b/services/surfaceflinger/LayerBlur.cpp @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#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 position(mesh.getPositionArray()); + 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 texCoords(mesh.getTexCoordArray()); + 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 position(mesh.getPositionArray()); + 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 texCoords(mesh.getTexCoordArray()); + 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, + 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& 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 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& 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& maskLayer, const sp& 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& 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& 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 index 000000000..251423e81 --- /dev/null +++ b/services/surfaceflinger/LayerBlur.h @@ -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 +#include + +#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, + 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& 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& 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 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& hw, + FBO& fbo, Texture& texture, int width, int height); + void doDrawFinal(const sp& hw, + int savedViewportWidth, int savedViewportHeight, + Rect savedProjectionSourceCrop, bool savedProjectionYSwap, + Transform::orientation_flags savedRotation, bool useIdentityTransform, + Texture* maskTexture); + bool drawMaskLayer(sp& maskLayer, const sp& hw, + FBO& fbo, int width, int height, int sampling, Texture& texture); + +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_LAYER_BLUR_H diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp index b8d549a78..5afd291e7 100644 --- a/services/surfaceflinger/LayerDim.cpp +++ b/services/surfaceflinger/LayerDim.cpp @@ -40,7 +40,7 @@ LayerDim::~LayerDim() { } void LayerDim::onDraw(const sp& hw, - const Region& /* clip */, bool useIdentityTransform) const + const Region& /* clip */, bool useIdentityTransform) { const State& s(getDrawingState()); if (s.alpha>0) { diff --git a/services/surfaceflinger/LayerDim.h b/services/surfaceflinger/LayerDim.h index b66591be5..01f71cc47 100644 --- a/services/surfaceflinger/LayerDim.h +++ b/services/surfaceflinger/LayerDim.h @@ -35,7 +35,7 @@ public: virtual const char* getTypeId() const { return "LayerDim"; } virtual void onDraw(const sp& 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; } diff --git a/services/surfaceflinger/RenderEngine/Description.cpp b/services/surfaceflinger/RenderEngine/Description.cpp index 0dab87268..14607cad5 100644 --- a/services/surfaceflinger/RenderEngine/Description.cpp +++ b/services/surfaceflinger/RenderEngine/Description.cpp @@ -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 */ diff --git a/services/surfaceflinger/RenderEngine/Description.h b/services/surfaceflinger/RenderEngine/Description.h index 8a3447c5a..2bfb6327f 100644 --- a/services/surfaceflinger/RenderEngine/Description.h +++ b/services/surfaceflinger/RenderEngine/Description.h @@ -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; diff --git a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h index 77824ce4d..cb13ee044 100644 --- a/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES11RenderEngine.h @@ -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); diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp index a35aa7863..6333a4184 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp @@ -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 // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h index 6074a3d0b..414a99902 100644 --- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.h @@ -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; } }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/RenderEngine/Program.cpp b/services/surfaceflinger/RenderEngine/Program.cpp index 0424e0cca..936cb1b3e 100644 --- a/services/surfaceflinger/RenderEngine/Program.cpp +++ b/services/surfaceflinger/RenderEngine/Program.cpp @@ -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 */ diff --git a/services/surfaceflinger/RenderEngine/Program.h b/services/surfaceflinger/RenderEngine/Program.h index 36bd120e3..08dee5942 100644 --- a/services/surfaceflinger/RenderEngine/Program.h +++ b/services/surfaceflinger/RenderEngine/Program.h @@ -84,6 +84,9 @@ private: /* location of the color uniform */ GLint mColorLoc; + + GLint mSamplerMaskLoc; + GLint mMaskAlphaThresholdLoc; }; diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.cpp b/services/surfaceflinger/RenderEngine/ProgramCache.cpp index ba11259ac..33ff7d0c9 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.cpp +++ b/services/surfaceflinger/RenderEngine/ProgramCache.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 + #include #include @@ -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(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 diff --git a/services/surfaceflinger/RenderEngine/ProgramCache.h b/services/surfaceflinger/RenderEngine/ProgramCache.h index 1fa53d337..3824e73ce 100644 --- a/services/surfaceflinger/RenderEngine/ProgramCache.h +++ b/services/surfaceflinger/RenderEngine/ProgramCache.h @@ -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) { diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h index c9a043a62..a669fdd83 100644 --- a/services/surfaceflinger/RenderEngine/RenderEngine.h +++ b/services/surfaceflinger/RenderEngine/RenderEngine.h @@ -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; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index fc99fa01f..cea463ad8 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +//#define LOG_NDEBUG 0 #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include @@ -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 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, return NO_ERROR; } +status_t SurfaceFlinger::createBlurLayer(const sp& client, + const String8& name, uint32_t w, uint32_t h, uint32_t flags, + sp* handle, sp* gbp, sp* 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, const sp& 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; diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 4bbb1f408..2028d6743 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -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* outHandle, sp* outGbp, sp* outLayer); + status_t createBlurLayer(const sp& client, const String8& name, + uint32_t w, uint32_t h, uint32_t flags, sp* outHandle, + sp* outGbp, sp* outLayer); + // called in response to the window-manager calling // ISurfaceComposerClient::destroySurface() status_t onLayerRemoved(const sp& client, const sp& 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