1.Flutter 新一代形渲染器 Impeller
2.Skia 编译及踩坑实践
3.androidå¾çå缩åº-说说å¨Androidä¸å¦ä½å缩å¾ç
4.skia发展历史
5.Android 14 HWUI 源码研究 View Canvas RenderThread ViewRootImpl skia
Flutter 新一代形渲染器 Impeller
Flutter在年的库源库Roadmap中提出需重新考虑着色器使用方式,计划重写图像渲染后端。库源库此计划的库源库初步成果是名为Impeller的渲染后端,本文将探讨Impeller解决的库源库问题、目标、库源库架构和渲染细节。库源库qt示例源码查询
背景部分,库源库 Flutter过去一年解决了不少Jank问题,库源库但着色器编译导致的库源库Jank问题一直没有解决。着色器编译Jank问题源于Flutter底层使用skia做2D图形渲染库,库源库内部定义了SkSL(Skia shading language)。库源库在光栅化阶段,库源库skia生成SkSL着色器,库源库再将其转换为特定后端(GLSL、库源库GLSL ES 或 Metal SL)着色器,库源库并在设备上编译,此过程可能耗时数百毫秒,导致数十帧丢失。通过在Flutter 1.版本中为GL后端实现SkSL预热机制,离线收集并保存应用程序中使用的SkSL着色器,进而提升性能。
Impeller架构部分,Impeller是诱导安装源码专为Flutter设计的渲染器,目前处于早期原型阶段,仅支持iOS和Mac系统,依赖flutter fml和display list,并实现了display list dispatcher接口,便于替换skia。其核心目标是解决着色器编译Jank问题。
Impeller着色器离线编译部分,Impeller compiler模块是关键。在编译阶段,将compiler相关源码编译为host工具impellerc binary,利用impellerc compiler将所有着色器源码(包括顶点和片段着色器)编译为SPIR-V中间语言,再转换为特定后端的高级着色器语言(如Metal SL),并编译为shader library,同时生成C++ shader binding用于快速创建pipeline state objects。这样所有着色器在离线时被编译,运行时不需执行任何编译操作,提升首帧渲染性能。
Impeller渲染流程部分,通过继承IOSContext、IOSSurface和flow Surface实现IOSContextMetalImpeller、IOSSurfaceMetalImpeller和GPUSurfaceMetalImpeller结构,对接flutter flow子系统。delphi ie源码光栅化阶段,通过DisplayListCanvasRecorder合成Layer Tree,将所有layer中的绘图命令转换为DLOps,并存储到DisplayList结构。随后,使用DisplayListDispatcher执行所有Ops,将信息转换为EntityPass结构。接着,使用RenderPass从Root EntityPass开始遍历,将每个Entity转换为Command结构,生成GPU Pipeline,设置顶点和片段着色器的数据,将顶点数据和颜色或纹理数据转换为GPU buffer。最后,开始渲染指令编码阶段,根据MTLCommandBuffer生成MTLRenderCommandEncoder,遍历所有Commands,设置PipelineState、Vertext Buffer和Fragment Buffer,提交command buffer。
总结部分,Impeller通过离线编译着色器、spring 事件 源码优化渲染流程等手段解决着色器编译Jank问题,显著提升渲染性能。Flutter重写图像渲染后端的决心可见一斑,期待Impeller能进一步提升Flutter的渲染性能。
Skia 编译及踩坑实践
了解并入门 Skia、OpenGL 和 Vulkan 的关键点:
Skia 是一个开源2D 图形库,提供跨硬件和软件平台工作的通用 API。OpenGL 是跨平台的图形 API,用于3D 图形处理硬件标准接口。Vulkan 是高性能跨平台 2D 和 3D 图形 API。
Android 支持多版 OpenGL ES 和 Vulkan。Skia 的常用后端包括自身、OpenGL、Vulkan、Metal 和 PDF。
实践涉及获取 Skia 源码,编译集成,使用 Skia 画出三角形。常见问题包括链接 libskia.so 时的 undefined symbol 错误,以及使用 SkData、SkImage、SkFont 时的ssaazz公式源码指针异常导致闪退。最终选择稳定版本 flutter-3.2-candidate.4 分支。
改用 GPU 画图(Vulkan)能显著提升绘制效果,但需调整编译配置,注意 Vulkan 库位置,不同 Android 系统内置的 so 存在增删。初始 Vulkan 配置涉及创建 Vulkan 实例、物理设备、逻辑设备、队列族、队列、回调函数、上下文、Surface 和交换链等。
发现 Vulkan 性能不及预期,验证后发现 OpenGL 在电量、温度和帧率上表现更优。Skia 开启 OpenGL 后端绘制,相比 Vulkan 简化许多。
实际项目构建 Skia 运行出现问题时,不要轻易怀疑自己,可能真是 Skia 的问题。Vulkan 需要一定的图形基础,没有经验者慎用。
学习和实践 Skia、OpenGL 和 Vulkan 的过程需要耐心,遇到问题时不要放弃,可能只是 Skia 的问题。Vulkan 的配置和调优需要投入更多精力,但最终能实现高性能渲染。
androidå¾çå缩åº-说说å¨Androidä¸å¦ä½å缩å¾ç
Androidé»ç§æï¼å¾çç»æå缩
ä¸ãæ¯æèªå®ä¹é ç½®ãä¸å¤±çåæ¹éå¤ç
äºãå¾çä¸ä¼ 为ä»ä¹è¦å缩
1ãå¾çæå¡å¨ç©ºé´éå¶,ç£çæè´µ
2ãç½ç»ä¸ç¨³å®,大æ件éè¦æç¹ç»ä¼
3ãå°½å¯è½é¿å å®åOOMå¼å¸¸
4ãåå°çº¦å®çè§å<KB
5ãéè¦ä¸ä¼ åå¾çåºç¨æå»é¢ä¸´åºé¡¹ç®ãéèé¶è¡
ä¸ãå¾çå缩æµç¨
1ãéå½æ¯å¼ å¾ç
2ã设置å¾çæ ¼å¼
png,jpg,webp
3ãè´¨éå缩(format,quality,baos)
ç±äºpngæ¯æ æå缩,æ以设置qualityæ æ(ä¸éåä½ä¸ºç¼©ç¥å¾)
éæ ·çå缩
缩å°å¾çå辨ç,åå°æå ç¨ç£ç空é´åå å大å°
缩æ¾å缩(bitmap,null,rectF,null)
åå°å¾ççåç´ ,éä½æå ç¨ç£ç空é´å¤§å°åå å大å°,å¯ç¨äºç¼å缩ç¥å¾
JNIè°ç¨JPEGåº
Androidçå¾çå¼æ使ç¨çæ¯éå²ççskiaå¼æ,å»æäºå¾çå缩ä¸çå夫æ¼ç®æ³
4ãåç´ ä¿®å¤
5ãè¿åå缩
6ãå®æå缩
demo:
åè:
Lubanæ¡æ¶
缺ç¹
1ãå½æ²¡æ设å®å缩路å¾æ¶,æå¼å¸¸æ éªé
2ãæºç ä¸,å缩æ¯çåºå®å¼,æ æ³ä¿®æ¹
3ãå缩é ç½®,åæ°ä¸å¤ªéåºçå®é¡¹ç®éæ±
4ãä¸è½æå®å缩大å°,æ¯å¦KB以å
说说å¨Androidä¸å¦ä½å缩å¾çç®ååå¨ä¸¤ç§å缩å¾çæ¹å¼:
èå¾çæä¸ç§åå¨å½¢å¼:
bigmapå¨å åä¸ç大å°æ¯æåç´ è®¡ç®ç,ä¹å°±æ¯width*height,æ以å¦æéè¦å¨Androidä¸æ¾ç¤ºç §ç,é£ä¹å°±å¿ é¡»è¿è¡ææ¯ä¾å缩,é¿å å 为å åæ¶èè¿å¤§,导è´APPéåºã
æ¯ä¸æ¯å¾ç®ååO(â©_â©)Oåå~
Androidå¾çå缩-大å°ä¸è´¨éå缩以åå¾çä¿åä¸ãåè¨:
2.è´¨éå缩
注æ:
第äºæ¬¡å缩ä¹åé½è¦å æ¸ ç©º();åè¿è¡å缩(,quality,baos);
ææ¶åæ们éç¨è´¨éå缩没æææ,æå¯è½æ¯æ¯æ¬¡å缩çè´¨éè¿å°,æ以æ们å¯ä»¥å°è¯ä¿®æ¹å缩质é(quality)æ¯;
qualityå缩æºæ示,0-ã0表示å缩
å°å°ºå¯¸,æå³çæ大质éçå缩ãä¸äº
æ ¼å¼,å¦æ æçPNG,å°å¿½ç¥è´¨é设å®;
3.æ··åæ¹å¼å缩
é¾æ¥:
skia发展历史
自年Google购入Skia以来,这个项目一直保持着相对低调的姿态。转折点发生在年初,Skia的GL相关源代码首次公开,它成为了Google Android平台的关键图形引擎。随后,Google Chrome浏览器也接纳了Skia的技术,使其在浏览器渲染中发挥重要作用。随着Android和Chrome开源计划(Android的开源版本称为Chromium)的展开,Skia的原始源代码也随之公开,采用的是Apache License v2的许可协议,这与GPLv2有所不同。在Android和Chrome的源代码库中,都包含了对Skia的定制版本,如Chrome项目下的"chrome/trunk/src/skia",这些定制主要针对各自平台的需求,如Android通过Linux Framebuffer接口与系统集成,而Chrome在开发中的Linux版本则使用Gtk+。
值得注意的是,Skia本身并不直接处理底层环境的细节,如Linux Framebuffer或Gtk+的衔接,这就导致了Android和Chrome需要针对其各自的环境需求进行相应的代码修改,以确保系统的兼容性和流畅运行。这些定制版的Skia在各自的项目中扮演了不可或缺的角色,但原始的Skia项目本身并未涉及这些底层整合工作。[1]
Android HWUI 源码研究 View Canvas RenderThread ViewRootImpl skia
HUWUI是Android系统中负责应用可视化元素绘制的核心组件,其架构主要在C++层实现,从Java层接收View绘制信息,通过唯一的渲染线程使用skia技术完成渲染任务。整体上,从应用程序到UI线程,再到渲染线程,形成了清晰的层级关系。
HUWUI的构建主要包括三个核心类,它们分别是:RecordingCanvas、Canvas、RenderNode、RenderProxy、RenderThread、CanvasContext、IRenderPipeline。在Java层,主要涉及两类Canvas,RecordingCanvas用于记录绘制指令,Canvas则是直接用于渲染。RecordingCanvas在构造时创建,而Canvas在调用时创建。这两个类在C++层分别对应SkiaRecordingCanvas和SkiaCanvas,后者直接引用SkCanvas。
在全局循环中,UI线程与渲染线程之间的协同操作至关重要。具体流程包括:新创建Activity后,附着到对应的PhoneWindow,然后调用PhoneWindow的setContentView方法,将View添加到DecorView作为子节点。接着,DecorView与ViewRootImpl对接,完成View的更新与渲染。整个过程包含了measure、layout和draw等复杂子流程。
渲染线程创建与核心对象紧密关联,主要包括RenderProxy、RenderThread和DrawFrameTask。RenderProxy负责Java层信息的衔接,RenderThread作为进程唯一的渲染线程,持有DrawFrameTask和CanvasContext,完成一帧的绘制任务。指令记录流程的核心在于使用C++层的RecordingCanvas将View属性和绘制信息记录到DisplayList中,进而完成指令的渲染。
Surface、ANativeWindow、EGLSurface的创建流程在ViewRootImpl的performTraversals函数中初始化。ReliableSurface的封装和EGL与Skia环境的创建主要在RenderThread的requireGlContext函数中实现。从源码分析,这一过程通常在三个地方调用。
View树与RenderNode树之间的协作关系明确,一个Application进程对应多个Activity,每个Activity与一个PhoneWindow绑定,PhoneWindow持有DecorView,DecorView对应一个ViewRootImpl,而ViewRootImpl与ThreadedRender模块对接。ThreadedRender与C++层的RenderProxy一一对应,RenderProxy持有关键对象,如RenderThread、CanvasContext、DrawFrameTask等。RenderThread是单例模式,进程唯一,负责一帧绘制的逻辑。
在RenderPipeline模块中,关键操作包括makeCurrent、draw和swapBuffers。Native Canvas在这一过程中扮演了桥梁角色,接收Java API调用,而RecordingCanvas完成Op记录,最终DisplayListData存储这些Op。
skia的核心资源主要在三个使用场景中发挥作用,具体细节需深入分析,这些资源对于实现高效、稳定的渲染效果至关重要。