盱眙县住房和城乡建设局网站,淮北濉溪县建网站,wordpress汽车模板,怎么做国外网站从Android 12开始#xff0c;Android的绘制系统有结构性变化#xff0c; 在绘制的生产消费者模式中#xff0c;新增BLASTBufferQueue#xff0c;客户端进程自行进行queue的生产和消费#xff0c;随后通过Transation提交到SurfaceFlinger#xff0c;如此可以使得各进程将缓… 从Android 12开始Android的绘制系统有结构性变化 在绘制的生产消费者模式中新增BLASTBufferQueue客户端进程自行进行queue的生产和消费随后通过Transation提交到SurfaceFlinger如此可以使得各进程将缓存提交到SufrfaceFlinger后合并到同一事务后同步提交在同一帧生效。实际上从Android12到Android14整个绘制系统在各个环节也都有了或大或小的调整比如Android13发布了1.3版本的Vulkan, Android14新增了TextureView等等。本文基于Android14。 Android 绘制系统整体架构 从上到下可以理解为“生产者Producer”到“消费者Consumer”的处理过程。 首先从WindowManagerService的角度每个窗口称为Window一个Window一般是一个APP的页面或者Status Bar或者Navigation Bar或者WallPaper这些都是一个个Window。WindowManagerServiceWMS作为服务端对所有客户端窗口的添加、层级、布局等进行统一管理。在WMS端每个Window对应一个Surface。Surface可以理解为图像数据缓存的持有者以及Canvas的持有者。Canvas是画布提供了绘制各种图形的能力供开发者使用。一个客户端窗口在建立之初会先向WMS去申请一个SurfaceWMS在创建了Surface之后通过binder返回给客户端。客户端拿到Surface后会去创建一个BLASTBufferQueue来管理图像内存的申请。每次要使用Surface的Canvas进行绘制前需要先向BLASTBufferQueue申请一块内存dequeue我们这里称为Buffer然后再将生成的图像数据写入Buffer。这个向BLASTBufferQueue申请Buffer并写入图像数据的过程可以认为是“生产”阶段。随后enqueue这个buffer将其提交给SurfaceFlinger去合成。这个阶段可以理解为图像Buffer的“消费”阶段。 SurfaceFlingerSF是负责与Hardware层沟通维护着设备挂载、VSync信号收发、Layer合成等工作。WMS的每个Surface在SurfaceFlinger中都对应生成一个Layer对象。客户端将某个Surface上的Buffer提交给SurfaceFlinger实际上就是更新了对应Layer的Buffer数据。SurfaceFlinger调用HWComposer将这些Layer进行合成并显示在屏幕。 Android在HAL层提供称为一个Hardware Composer的组件用于隔离与具体硬件的交互。Hardware Composer简称HWComposer或HWC2之所以是2是早期已有一个HWC版本只支持软件合成。SurfaceFlinger把Layer数据交给HWComposer各厂商来负责HWComposer合成接口的具体实现。在合成完毕后将数据提交到屏幕设备的缓存一般称为Frame Buffer屏幕就显示出画面来了。 上面的过程可以拆解为几部分 Surface的创建与管理。客户端EndPoint绘制Draw和渲染Render图像。第三部分是硬件Composition合成工作Vsync由硬件产生的信号用于同步framebuffer的生产和消费。SurfaceFlinger对Vsync进行了使用和管理并向上分发给APP。Vsync是不断绘制的驱动力也是图像缓存有序投送到屏幕的重要机制。 现在分别讨论下四部分 Surface的创建与管理 在Surface的创建过程中有几个角色贯穿其中 PhoneWindow一个Activity对应一个PhoneWindow代表一个应用窗口。在AMS创建Activity之初PhoneWindow在服务端的对应的window对象ActivityRecord已经添加到WMS。 ViewRootImpl其主要作用是与服务端通信承接外部触发的绘制调用从而从上往下对整个View树进行绘制。可以把ViewRootImp理解为View的调度者。ViewRootImp在逻辑上是View Hierarchy的最顶层但其并不是一个真正的View。他持有一个字View--DecorViewDecorView才是真正的View是View树的最上层包含着Activity的画面内容。在Activity的resume阶段ViewRootImpl的relayout方法会将DecorView添加到WMS中这样Activity的内容就显示了出来。逻辑上我们可以把DecorView也理解为一个Window。Activity对应一个PhoneWindow再通过ViewRootImpl将DecorView在WMS端添加为PhoneWindow的子Window。 WMS的Session客户端一个进程对应WMS里的一个Session客户端持有Session的binder客户端在窗口添加等事务上客户端都是通过这个Session来与WMS通信的。 WindowContainerWMS端管理系统整体的Window体系包括其位置、层级关系。它是通过WindowContainer这个类来表达一个Window的。DisplayContent代表一个屏幕级别的WindowDisplayArea代表一块屏幕上的一块区域比如平板等大屏幕设备上可能一块屏幕上同时显示多个应用区域此时就用DisplayArea表达。WindowToken简单理解为对应一个客户端Window比如一个应用的Activity这里需要注意的是Activity的WindowToken是作为ActivityRecord存在的也就是说ActivityRecord是WindowToken的子类。而Activity的具体内容的承载者DecorView对应WindowState。上面所有的DisplayContent、DisplayArea、WindowToken、WindowState等都是WindowContainer的子类这些Window在WMS内是以window树的形式组织起来的。事实上在DisplayContent下面还有一个层级称为Feature具体的层级结构见Android12 - WMS之WindowContainer树DisplayArea_android windowcontainer-CSDN博客。当客户端通过Session接口调用添加DecorView时WMS端会生成一个对应的WindowState对象并将其作为Activity对应的ActivityRecord也就是WindowToken的子window。 SurfaceControl在WMS端每个WindowContainer对应一个SurfaceControl。SurfaceControl是WMS端管理Surface的具体对象在WMS端可以理解一个SurfaceControl就代表一个Surface。SurfaceControl在SurfaceFlinge端对应一个Layer持有一个layer的句柄handle。所有的绘制动作最后都会提交到SurfaceFinger作为Layer去合成。SurfaceControl的作用或者Surface的作用主要是将客户端的窗口与SurfaceFlinger的Layer关联起来。在客户端Add一个DecorView时 在WMS端对应创建的WindowState会同时创建一个SurfaceControl、Layer随后将SurfaceControl返回给客户端。客户端拿到SurfaceControl之后转换成Surface。后续的绘制就在这个Surface上进行。 SurfaceComposerClient是一个Binder主要作用是SurfaceControl调用SurfaceFlinger过程中作为一个通道的角色。由于SurfaceControl在WMS、客户端都持有所以客户端、WMS都可以通过这个通道调用SF。比如Layer的创建、Graphihc Buffer的提交等。 1. 客户端绘制和渲染 客户端通过Surface中提供的Canvas进行绘制Canvas是基于Skia的SKCanvas。Skiahttps://skia.org/是由Google管理的开源2D也可以支持3D图像库目前Android、Google Chrome、ChromeOS、Mozilla FireFox、FireFoxOS上都使用Skia作为绘制引擎。Skia可以集成OPEN GL和Vulkan进行3D绘制。Android Q以后Skia作用被加强即使硬件加速场景中绘制也会先封装成Skia的GrOpList再提交给GPU。在Android 14中 Skia包的目录为external/skia。 渲染的过程是将画好的图像进行栅格化Rasterizer变成一个个像素这是一个非常耗时的过程。Android 3以前只支持软件渲染即Software Render。过程如下 APP在View的onDraw阶段使用Canvas绘制后通过Skia进行软件的栅格化即通过CPU计算将绘制内容转化成一个个像素信息随后投送给屏幕进行显示。由于软件渲染效率低当下软件渲染只是作为兼容方案得以保留默认使用硬件加速。 硬件加速的流程简单表述如下 Android将硬件加速相关能力封装在hwui组件中hwui地址platform/frameworks/base/libs/hwui 在硬件加速模式下APP在onDraw中通过Canvas绘制的内容将最终被封装成DisplayList的一个个GrOp绘制命令然后通过OpenGL或者Vulkan交由GPU进行渲染随后将结果投送给屏幕显示。而具体是使用OpenGL还是Vulkan是可选择的。早期Android只使用OpenGL由于Vulkan支持多线程渲染等性能方面的优势Android逐渐倾向使用Vulkan进行渲染。另外在哪些维度上进行硬件加速也是可选的 即在整体使用硬件加速的情况下如果某个View的绘制暂时不支持硬件加速或者在某些位移动画上为了减少渲染成本可以动过设置View的layerType LAYER_TYPE_SOFTWARE来单纯在某个特定View上使用Software Render。 硬件加速除了利用GPU来加速渲染效率外 本身在计算渲染范围时相较软件渲染也更加高效即软件渲染每次更新一个View局部将使得整个View hierarchy都重新渲染。而硬件加速如只标注有变化的部分所谓damage area将绘制指令保存在DisplayList中如此大大提高渲染速度。 OpenGL ES VS Vulkan 以下为OpenGL ES和Vulkan在Android上发布的版本历史。 Vulkan作为一个面向更低级别规范、跨平台的API可以提供更细粒度的内存管理和资源管理 以下为Vulkan与OpenGL ES的使用率from GDC 2023 https://www.youtube.com/watch?vC7OjI7CpjLwt1188s 对于未来计划OpenGL ES将不会再有功能更新新的功能将只会在Vulkan上支持。因此Vulkan是未来Android主推的渲染引擎。 无论是OpenGL还是Vulkan都需要GPU的支持。例如常见的车载高端芯片高通8155明确标明了支持: OpenGL ES 3.x、Vulkanhttps://www.qualcomm.com/content/dam/qcomm-martech/dm-assets/documents/qul7413_sa8155_productbrief_r4.pdf 2. HW ComposerHWC2图像合成 前面提到过每个window对应一个SF中的Layer合成Composition工作就是将这些Layer进程合并成一个完整的屏幕内容提交给硬件屏幕显示出来。大概过程如下 这个页面有三个LayerStatusBar、NavigationBar和中间的APP内容页面其中可能会有重叠的部分称为Overlay。Composition的工作就是将这三个Layer合并成一个画面计算重叠部分的颜色提交给屏幕显示出来。 合成的工作发生在渲染后的内容提交给SurfaceFlinger之后。大致流程如下 合成有硬件合成的部分和软件合成的部分。硬件合成除了更高效的同时可以将合成工作从GPU解放出来提高GPU效率节省能耗。嵌入式设备的SOC中硬件的合成一般由独立的DPUDisplay Processing完成。 比如高通SA8155这款SOC的布局如下 其中GPU的部分负责渲染“Dispay Processing”的部分用来处理合成工作。 由于硬件对合成Layer数量是有限制的例如高通QCS2290支持4个Layer、AMD有的芯片支持7个等以及Layer的PixelFormat比如支持PIXEL_FORMAT_RGBA_8888不支持YUV是有限制的因此在硬件合成之前如果合成Layer过多或者Format不满足要求会需要使用GPU先进行一轮软件合成合并或转换一些Layer的格式。 软件合成过程。Google I/O 18 4. VSYNC VSync简介 首先关注两个重要概念 refresh rate - 60Hz 代表每秒钟屏幕可以更新多少次这一值早期是固定的依赖于硬件。现代旗舰设备的屏幕都支持多个刷新率从60Hz~165Hz不等而且是可以由App层定制刷新率。 frame rate每秒钟GPU可以绘制多少帧值越大越好 VSync是一个通用概念在Linux、PC、移动设备上都有所实现。 想象一下绘制过程是这样的GPU绘制数据将绘制结果投掷给屏幕显示出来。 问题是refresh rate和Frame Rate并不保证是一致的频率也就是是说GPU渲染的时间并不能保证就正好是16ms60Hz内完成的。如果只有一块内存Frame Buffer用来交换数据假如Refresh Rate大于Frame Rate由于GPU是从上到下写这块内存的在当屏幕来取数据的时候GPU刚刚在旧帧基础上写了一半的新帧此时就会出现图片撕裂问题如 解决方法是双缓存方案 提供Back Buffer和Frame Buffer两个缓存屏幕始终从Frame Buffer取数据显示GPU往Back Buffer里写当GPU完全将数据写好后再将Back Buffer整个拷贝到Frame Buffer。这样就能保证屏幕每次都取到完整的帧。 此时仍有一个问题如果GPU的Frame Rate大于屏幕的Refresh Rate那么屏幕再取到下一帧前可能GPU都写完好几帧了就会出现丢帧现象。此时就需要VSync 屏幕根据自己的刷新频率去给上层发送一个VSync信号GPU在拿到这个VSync信号后才去绘制。这样就能同步屏幕与上层绘制的节奏了。 如果屏幕的Refresh Rate大于GPU的Frame Rate怎么办 屏幕将会仍然显示旧帧。比如中间方框的两次刷新屏幕仍然显示前一次的帧内容。 Android的VSYNC 实际上Android的VSync要复杂得多主要由SurfaceFlinger负责实现。通过之前的介绍我们知道一帧的绘制过程有APP绘制渲染、SurfaceFlinger合成、Display硬件读取帧缓存显示图片三个阶段如果每一个阶段都依赖VSync信号来执行那可能会出现这种情况 也就是说VSync1的时候APP正在绘制渲染SF还没有可以合成的东西所以什么都不做等到VSync2的时候Render1的工作已经完成可以做合成了VSync3的时候合成做完了才可以显示到屏幕上。从绘制渲染到显示经历了3个VSync。面对这种情况Android对VSync的设计如下 即有三种信号 HW_VSYNC_[ID]由底层硬件按Refresh Rate的频率发出一般为60Hz、90Hz、120H等等随后会通过HWC通知给SurfaceFlinger。 VSYNC-appSurfaceFlinger通知给上层应用的VSYNC用于控制和驱动应用的绘制渲染。 VSYNC-sf:通知给SurfaceFlinger自身的用于合成Layer的信号。 VSYNC-app和VSYNC-sf相对于HW_VSYNC_[ID]并不是同步发送的而是有一定的延迟称为相位差。从HW_VSYNC_[ID]到VSYNC-app发出的时间差称为app phaseHW_VSYNC_[ID]到VSYNC-sf发出的时间差称为sf phase。这种设计的好处是如果在同一个VSync周期内经sf phase后在执行合成时恰好前一步的Render完成了就可在一个周期完成两步而不用非得等下一个VSync。 另外Android并非直接把硬件的HW_VSYNC_[ID]信号直接分发给应用和SurfaceFlinger而是通过先收集HW_VSYNC_[ID]样本再根据屏幕Refresh Rate、预先配置的相位差等信息经过计算后模拟出来的VSYNC-app和VSYNC-sf。 由于只需要一定的硬件VSync样本后便可以模拟出预期的VSYNC-app和VSYNC-sf因此并不需要一直接收HW_VSYNC_[ID]信号在收到足够的样本数后在Android 14中为6个就可以关闭硬件VSync的接收。在每次将合成数据提交给屏幕后会返回一个硬件VSync时间戳PresentFence此时SF会对比当前模拟VSync与硬件VSync是否误差过大如果过大会重新打开硬件VSync收集样本重新计算。另外每次终端应用主动请求VSync时也会判断前后两次模拟的VSync时间差是否超过750ms如果是则重新请求打开硬件VSync。在systrace上硬件VSync打开的TAG是HW_VSYNC_ON_[ID]。 参考资料https://source.android.com/docs/core/graphics/implement-vsync 可变刷新率 现代旗舰机屏幕的刷新率是可变的比如Pixel 5 可以看到该屏幕是支持60Hz、90Hz两种刷新率的。 而且应用层也可以在应用级别、窗口级别指定具体的刷新率。在经过应用层指定后最终的刷新率并不一定是指定的值而是经过SurfaceFlinger综合计算后得出。具体见https://developer.android.com/media/optimize/performance/frame-rate