こんにちは、ファンと友達!
前回のブログでは、ウィンドウのガウスぼかし関連効果を実現するためのシステム内の関連インターフェイスについて詳しく説明しました。詳細については、ここをクリックしてください
https://blog.csdn.net/learnframework/article/details/130767893
1. 補足的なアプリレベルの実装
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 を設定します。次に、アプリ レベルに入り、setBackgroundBlurRadius を呼び出します。SurfaceFlinger はどのように処理しますか
?それ?
2. SurfaceFlingerのソースコード原理解析の一部
まずアプリの 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 メソッドであることがわかります。
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. レイヤーを横断するとき、一番下のレイヤーが最初に開始されますが、これには注意が必要ですが、
これはなぜでしょうか? これは、surfaceflinger が各レイヤーを新しい画面キャンバスにレンダリングするのと同じだと考えてください。もちろん、一番下のレイヤーが最初に描画されます。
2. ぼかしのあるレイヤーが認識された場合、以前にレンダリングされたレイヤーの全体的なイメージをぼかし、その後、前のレイヤーのイメージを描画し続けます。