当前位置: 首页 > news >正文

副驾屏高斯模糊/Kawase方案---无wallpaper,透明区域如何实现高斯模糊/Kawase效果(卷2: 副驾屏Kawase 模糊实现方案)

副驾屏高斯模糊/Kawase方案—无wallpaper,透明区域如何实现高斯模糊/Kawase效果(卷2: 副驾屏Kawase 模糊实现方案)

一、问题描述
**项目背景:**整个30寸的屏幕,以及主驾屏(左半屏)是display0,wallpaper是全屏壁纸,显示在display0上;副驾屏(右半屏)是display5,display5是一块虚拟屏,没有壁纸。

当副驾屏未设置壁纸且运行透明背景 App 时,Android 原生高斯模糊算法会导致透明区域呈现全黑现象,具体表现为(入下图所示):

  1. 透明背景区域失去通透感,显示为纯黑色块
  2. 多任务界面视觉断层,影响车载系统交互体验。

在这里插入图片描述

采用了副驾屏Kawase 模糊实现方案之后,效果如下图所示:
在这里插入图片描述

出现透明区域黑块的原因是:
参考:副驾屏高斯模糊/Kawase方案—无wallpaper,透明区域如何实现高斯模糊/Kawase效果(卷1: Kawase 模糊的相关概念,以及在android中的流程)

Kawase模糊方案计算的是一块Display的所有layer的合成情况,而不是获取肉眼看到的区域下的所有layer,当副驾屏没有wallpaper的时候(虽然肉眼能够看到底下有wallpaper,其实是虚拟屏副驾屏display5透的下面主驾屏display0的壁纸),那么就会出现,透明区域之下的layer不存在,就是一块黑的buffer,通过Kawase模糊算法计算之后的结果,就是黑块。

如果要解决上面的Kawase模糊的黑屏问题,必须将display0的layer加入到Kawase模糊的计算过程中。我们的解决方案,就是在计算副驾屏display5 Kawase模糊之前,先截取主驾屏(全屏),然后将截取的图片在一块buffer上绘制出来,然后将其送给display5的kawase模糊计算中去。

二、详细实现方案

根据卷1我们知道,Kawase模糊的流程如下:

在这里插入图片描述

根据前面解释的Kawase模糊的流程,我们设计新的Kawase模糊的流程图如下,

在这里插入图片描述
根据上面的流程图,我们知道,当SurfaceFlinger合成的时候,会调用Output::composeSurfaces方法,接着会将Output对应的display中的使用gpu合成的layers,传给RenderEngine::drawLayers方法,紧接着就会通过SkiaGLRenderEngine::drawLayersInternal方法进行Kawase模糊计算。那么我们就必须在display5 合成之前,将display0的合成的图保存起来,然后在display5合成的时候,传过来参与合成。

(1)Output::composeSurfaces的修改

    if (renderengine::RenderEngine::virtualDisplayId > 10000) {bool isMainDisplay = false;bool isVirtualDisplay = false;std::optional<DisplayId> displayIdOpt = getDisplayId();if (displayIdOpt.has_value()) {DisplayId displayId = displayIdOpt.value();clientCompositionDisplay.displayId = displayId.value;//ALOGW("Kawase, present2222 DisplayId is: %" PRIu64, displayId.value);isMainDisplay = (displayId.value == static_cast<uint64_t>(129));isVirtualDisplay = (displayId.value == renderengine::RenderEngine::virtualDisplayId);if (isMainDisplay && !Output::hasBlurLayer) {//ALOGW("Kawase, -------present222 DisplayId is: %" PRIu64, displayId.value);renderengine::RenderEngine::mainDisplayBuffer = tex;renderengine::RenderEngine::mainDisplayBufferUpdate = true;} /*else if (isVirtualDisplay) {ALOGW("Kawase, -------present222 DisplayId is: %" PRIu64, displayId.value);}*/}if (isVirtualDisplay) {Output::hasBlurLayer = false;for (const auto& layer : clientRenderEngineLayers) {if (layer.backgroundBlurRadius > 0.0f || !layer.blurRegions.empty()) {Output::hasBlurLayer = true;//ALOGW("Kawase, -------present222 has blur layer");break;}}/*if (!Output::hasBlurLayer) {ALOGW("Kawase, -------present222 no blur layer");}if (renderengine::RenderEngine::mainDisplayBuffer) {ALOGW("Kawase, -------present222 mainDisplayBuffer=%p", renderengine::RenderEngine::mainDisplayBuffer.get());}*/}}

(2)SkiaGLRenderEngine::drawLayersInternal的修改

                // --- handle main display ExternalTexture,extract right part snapshot ---if (display.displayId == RenderEngine::virtualDisplayId && RenderEngine::mainDisplayBuffer != nullptr) {if (RenderEngine::mainDisplayBuffer->getWidth() >= 5120) {if (reusedScreenshotImage()) {//ALOGW("Kawase reusedScreenshotImage-222 ok");blurInput = SkiaGLRenderEngine::mainDisplayBufferImage;} else {ALOGW("Kawase reusedScreenshotImage-222 no");sk_sp<SkImage> mainImage  = nullptr;auto grContext = getActiveGrContext();if (grContext) {// create AutoBackendTexture::LocalRef,manager AHardwareBuffer texture resourcestd::shared_ptr<AutoBackendTexture::LocalRef> texRef = std::make_shared<AutoBackendTexture::LocalRef>(grContext,RenderEngine::mainDisplayBuffer->getBuffer()->toAHardwareBuffer(),true,  // isRenderablemTextureCleanupMgr);if (texRef) {// get surface,and then get snapshotsk_sp<SkSurface> surface = texRef->getOrCreateSurface(ui::Dataspace::V0_SRGB_LINEAR, grContext);if (surface) {mainImage = surface->makeImageSnapshot();}}}if (mainImage) {sk_sp<SkImage> blurInputRight = extractRightHalf(mainImage, grContext);if (blurInputRight != nullptr) {blurInput = blurInputRight;//right part} else {blurInput = mainImage;//full part}}}}if (blurInput == nullptr) {blurInput = activeSurface->makeImageSnapshot();//fix null pointer exception}} else {blurInput = activeSurface->makeImageSnapshot();}

(3)CustomizedRenderEngine::drawLayersInternal的修改

bool CustomizedRenderEngine::reusedScreenshotImage() {/*ALOGW("Kawase reusedScreenshotImage RenderEngine::mainDisplayBuffer =  %p, SkiaGLRenderEngine::mainDisplayBufferImage = %p,""RenderEngine::mainDisplayBufferUpdate = %d", RenderEngine::mainDisplayBuffer.get(),SkiaGLRenderEngine::mainDisplayBufferImage.get(), RenderEngine::mainDisplayBufferUpdate);*/if (!RenderEngine::mainDisplayBufferUpdate && SkiaGLRenderEngine::mainDisplayBufferImage) {return true;}return false;}sk_sp<SkImage> CustomizedRenderEngine::extractRightHalf(sk_sp<SkImage> blurInput, GrRecordingContext* grCtx) {if (!blurInput) return nullptr;int width = blurInput->width();int height = blurInput->height();if (width <= 1 || height <= 1) return nullptr;int halfWidth = width / 2;SkImageInfo info = SkImageInfo::Make(halfWidth, height, kRGBA_8888_SkColorType,kPremul_SkAlphaType, blurInput->refColorSpace());sk_sp<SkSurface> surface = SkSurface::MakeRenderTarget(grCtx, SkBudgeted::kYes, info);if (!surface) {ALOGE("Failed to create SkSurface");return nullptr;}SkCanvas* canvas = surface->getCanvas();SkRect srcRect = SkRect::MakeXYWH(halfWidth, 0, halfWidth, height); // extract right partSkRect dstRect = SkRect::MakeWH(halfWidth, height);ALOGW("Kawase blurInput size: %d x %d", width, height);ALOGW("Kawase srcRect: [%f, %f, %f, %f]", srcRect.left(), srcRect.top(), srcRect.right(), srcRect.bottom());SkSamplingOptions sampling;SkPaint paint;canvas->drawImageRect(blurInput.get(), srcRect, dstRect, sampling, &paint, SkCanvas::kFast_SrcRectConstraint);//kStrict_SrcRectConstraintsk_sp<SkImage> result = surface->makeImageSnapshot();SkiaGLRenderEngine::mainDisplayBufferImage = result;RenderEngine::mainDisplayBufferUpdate = false;return result;
}
http://www.lqws.cn/news/490789.html

相关文章:

  • BUUCTF [UTCTF2020]File Carving 1
  • JVM线上调试
  • 免费生成 吉卜力 风格头像
  • libwebsockets编译
  • Firewalld服务
  • 虚拟 DOM 与 Diff 算法:现代前端框架的核心机制
  • 2025 年前端框架的深度解析与展望
  • Vue实现选中多张图片一起拖拽功能
  • 时序数据库IoTDB数据导入与查询功能详解
  • 实战 + 原理全解析:用 Qwen-Agent 构建图文生成智能体!
  • 笔试强训:Day8
  • EukDetect:基因标记基因的真核微生物注释
  • Java 期末考试题
  • 阿里云MCP:开启AI应用新时代
  • 突破中文知识处理瓶颈:基于 ChatGLM-6B + LangChain 的本地化智能问答系统实战
  • 什么是Sentinel? 以及优点
  • 云原生 CAD 让制造业设计协同更便捷
  • vue3实现markdown文档转HTML并可更换样式
  • VR看房:房地产数字化转型的核心引擎
  • mysql replace into学习
  • 创惟GL3224|抖胆DD3118完美替代GL3224|国产3.0读卡方案
  • Spark基于Bloom Filter算法的Runtime Filter Join优化机制
  • 用 GitHub Issues 做任务管理和任务 List,简单好用!
  • ADIOS2 介绍与使用指南
  • dify应用实践教程5
  • C++哈希表:高效数据存储与检索的利器
  • 自定义U8G2 中文字体
  • 牛津大学开源视频中的开放世界目标计数!
  • Jupyter-notebook-mcp Quickstart
  • 融合LSTM与自注意力机制的多步光伏功率预测新模型解析