123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488 |
- /*
- * 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 <dlfcn.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)
- {
- 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() {
- 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();
- if (mBlurImpl.blur(s.blur,
- mTextureCapture.getTextureName(),
- mTextureCapture.getWidth(),
- mTextureCapture.getHeight(),
- mTextureBlur.getTextureName(),
- &outTexWidth,
- &outTexHeight) != OK) {
- return;
- }
- // 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());
- Transform::orientation_flags rotation = Transform::ROT_0;
- 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);
- rotation = (Transform::orientation_flags)(rotation ^ hw->getPanelMountFlip());
- mFlinger->renderScreenImplLocked(
- hw,
- Rect(0,0,width,height),
- width, height,
- 0, getDrawingState().z-1,
- false,
- false,
- rotation);
- 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);
- }
- }
- // ---------------------------------------------------------------------------
- void* LayerBlur::BlurImpl::sLibHandle = NULL;
- bool LayerBlur::BlurImpl::sUnsupported = false;
- LayerBlur::BlurImpl::initBlurTokenFn LayerBlur::BlurImpl::initBlurToken = NULL;
- LayerBlur::BlurImpl::releaseBlurTokenFn LayerBlur::BlurImpl::releaseBlurToken = NULL;
- LayerBlur::BlurImpl::blurFn LayerBlur::BlurImpl::doBlur = NULL;
- Mutex LayerBlur::BlurImpl::sLock;
- void LayerBlur::BlurImpl::closeBlurImpl() {
- if (sLibHandle != NULL) {
- dlclose(sLibHandle);
- sLibHandle = NULL;
- }
- }
- status_t LayerBlur::BlurImpl::initBlurImpl() {
- if (sLibHandle != NULL) {
- return OK;
- }
- if (sUnsupported) {
- return NO_INIT;
- }
- sLibHandle = dlopen("libuiblur.so", RTLD_NOW);
- if (sLibHandle == NULL) {
- sUnsupported = true;
- return NO_INIT;
- }
- // happy happy joy joy!
- initBlurToken = (initBlurTokenFn)dlsym(sLibHandle,
- "_ZN7qtiblur13initBlurTokenEv");
- releaseBlurToken = (releaseBlurTokenFn)dlsym(sLibHandle,
- "_ZN7qtiblur16releaseBlurTokenEPv");
- if (sizeof(size_t) == 4) {
- doBlur = (blurFn)dlsym(sLibHandle,
- "_ZN7qtiblur4blurEPvijjjjPjS1_");
- } else if (sizeof(size_t) == 8) {
- doBlur = (blurFn)dlsym(sLibHandle,
- "_ZN7qtiblur4blurEPvijmmjPmS1_");
- }
- if (!initBlurToken || !releaseBlurToken || !doBlur) {
- ALOGE("dlsym failed for blur impl!: %s", dlerror());
- closeBlurImpl();
- sUnsupported = true;
- return NO_INIT;
- }
- return OK;
- }
- LayerBlur::BlurImpl::BlurImpl() : mToken(NULL) {
- Mutex::Autolock _l(sLock);
- if (initBlurImpl() == OK) {
- mToken = initBlurToken();
- }
- }
- LayerBlur::BlurImpl::~BlurImpl() {
- Mutex::Autolock _l(sLock);
- if (mToken != NULL) {
- releaseBlurToken(mToken);
- }
- }
- status_t LayerBlur::BlurImpl::blur(int level, uint32_t inId, size_t inWidth, size_t inHeight,
- uint32_t outId, size_t* outWidth, size_t* outHeight) {
- Mutex::Autolock _l(sLock);
- if (mToken == NULL) {
- return NO_INIT;
- }
- return doBlur(mToken, level, inId, inWidth, inHeight,
- outId, outWidth, outHeight) ? OK : NO_INIT;
- }
- // ---------------------------------------------------------------------------
- }; // namespace android
|