aosp11/12/13 壁纸高斯模糊,毛玻璃SurfaceFlinger层面原理-第二节千里马framework实战

hi,粉丝朋友们!
上一个blog已经详细讲解了系统中自带相关接口实现窗口的高斯模糊相关效果,具体点击这里
https://blog.csdn.net/learnframework/article/details/130767893

1、补充app层面实现方式

更多framework干货知识手把手教学

Log.i("qq群",“422901085);

这里额外也补充一下另一种实现方式其实也可以实现:

                if (getWindow().getRootSurfaceControl() != null &&
                        getWindow().getRootSurfaceControl() instanceof ViewRootImpl) {
    
    
                    SurfaceControl surfaceControl = ((ViewRootImpl)getWindow().getRootSurfaceControl()).getSurfaceControl();
                    SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
                    transaction.setBackgroundBlurRadius(surfaceControl,100);
                    transaction.apply();
                    android.util.Log.i("lsm"," setBackgroundBlurRadius");
                }

在这里插入图片描述

其实也就说明关键就是要对这个图层的surfacecontrol进行设置对应的BackgroundBlurRadius即可以,上一节分析的Dim图层也设置了对应的BackgroundBlurRadius
下面开始进入app层面调用了setBackgroundBlurRadius后,SurfaceFlinger是怎么处理的

2、SurfaceFlinger部分源码原理分析

先看看app的setBackgroundBlurRadius接口

      /**
         * Sets the background blur radius of the {@link SurfaceControl}.
         *
         * @param sc SurfaceControl.
         * @param radius Blur radius in pixels.
         * @return itself.
         * @hide
         */
        public Transaction setBackgroundBlurRadius(SurfaceControl sc, int radius) {
    
    
            checkPreconditions(sc);
            nativeSetBackgroundBlurRadius(mNativeObject, sc.mNativeObject, radius);
            return this;
        }

可以看到调用是nativeSetBackgroundBlurRadius方法,是个native的方法:

static void nativeSetBackgroundBlurRadius(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject, jint blurRadius) {
    
    
    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);

    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
    transaction->setBackgroundBlurRadius(ctrl, blurRadius);
}

这里调用的是SurfaceComposerClient::Transaction的setBackgroundBlurRadius

SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius(
        const sp<SurfaceControl>& sc, int backgroundBlurRadius) {
    
    
    layer_state_t* s = getLayerState(sc);
    if (!s) {
    
    
        mStatus = BAD_INDEX;
        return *this;
    }
    s->what |= layer_state_t::eBackgroundBlurRadiusChanged;
    s->backgroundBlurRadius = backgroundBlurRadius;
    return *this;
}

这里其实也比较简单就是针对的layer_state_t结构体的backgroundBlurRadius进行了设置

这里一般会跨进程最后调用到surfaceflinger服务端的Layer.cpp

bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) {
    
    
    if (mDrawingState.backgroundBlurRadius == backgroundBlurRadius) return false;
    // If we start or stop drawing blur then the layer's visibility state may change so increment
    // the magic sequence number.
    if (mDrawingState.backgroundBlurRadius == 0 || backgroundBlurRadius == 0) {
    
    
        mDrawingState.sequence++;
    }
    mDrawingState.backgroundBlurRadius = backgroundBlurRadius;
    mDrawingState.modified = true;
    setTransactionFlags(eTransactionNeeded);
    return true;
}

主要就是把这个backgroundBlurRadius赋值给mDrawingState.backgroundBlurRadius

下面就看看SurfaceFlinger里面是怎么使用这个的backgroundBlurRadius属性的
最后发现其实是在./libs/renderengine/gl/GLESRenderEngine.cpp中进行渲染时候进行的使用
其实这里也非常好理解,因为高斯模糊,这属于图像处理,当然不能让cpu来干,应该让GPU干,所以自然很容易想到opengl渲染部分进行的高斯模糊处理

void GLESRenderEngine::drawLayersInternal(
        const std::shared_ptr<std::promise<RenderEngineResult>>&& resultPromise,
        const DisplaySettings& display, const std::vector<LayerSettings>& layers,
        const std::shared_ptr<ExternalTexture>& buffer, const bool useFramebufferCache,
        base::unique_fd&& bufferFence) {
    
    
    ATRACE_CALL();
    //省略
    std::deque<const LayerSettings> blurLayers;
    if (CC_LIKELY(mBlurFilter != nullptr)) {
    
    
        for (const auto& layer : layers) {
    
    
            if (layer.backgroundBlurRadius > 0) {
    
     //遍历出这个backgroundBlurRadius的layer
                blurLayers.push_back(layer);
            }
        }
    }
    const auto blurLayersSize = blurLayers.size();
//省略

    for (const auto& layer : layers) {
    
     //遍历所有图层layer进行相关的渲染,注意这里是从底到顶的顺序
        if (blurLayers.size() > 0 && blurLayers.front() == layer) {
    
    //如果遍历到了设置了blurebehind的layer
            blurLayers.pop_front();

            auto status = mBlurFilter->prepare(); //准备相关的模糊参数
          
            if (blurLayers.size() == 0) {
    
    //假设已经没有了那么就开始设置好相关的buffer
                //这里很关键,会把已经绘制的FrameBuffer进行获取,后面把这个数据进行对应的blur
                // Done blurring, time to bind the native FBO and render our blur onto it.
                fbo = std::make_unique<BindNativeBufferAsFramebuffer>(*this,
                                                                      buffer.get()
                                                                              ->getBuffer()
                                                                              ->getNativeBuffer(),
                                                                      useFramebufferCache);
                status = fbo->getStatus();
                setViewportAndProjection(display.physicalDisplay, display.clip);
            } else {
    
    
             //省略这种情况
            }
           
					//进行真的模糊
            status = mBlurFilter->render(blurLayersSize > 1);
        }
				//省略
        if (layer.source.buffer.buffer != nullptr) {
    
    //这里正常的layer渲染
          //省略
        }
//省略
    return;
}

代码相对较多,这里只需要理解以下几个关键点:

1、遍历layers时候是底部layer先开始,这个需要注意
为啥这样呢?想想这里是相当于surfaceflinger要把各个图层渲染到一个新的屏幕画布,当然是底部的layer先画

2、识别到有blurbehind的layer时候,要把之前的已经渲染好了的layer的整体画面进行blur模糊,然后再继续绘制的前的layer的画面
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/learnframework/article/details/130778897