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的画面