Android HWUI

Android HWUI(Hardware Accelerated Rendering Engine for UI)是Android系统中用于处理UI渲染的硬件加速引擎。它的主要作用是利用GPU(图形处理单元)来加速UI的渲染过程,从而提高渲染效率和流畅度。以下是Android HWUI工作的主要方式和步骤:

 

一、基本工作原理

传统软件的UI绘制是依靠CPU来完成的,硬件加速就是将绘制任务交由GPU来执行。

HWUI基于GPU加速,通过Skia Backend与GPU进行交互,将UI绘制任务从CPU转移到GPU上执行。这种方式可以显著提高绘制性能,特别是在高分辨率屏幕和复杂UI场景下。

  • GPU相比CPU更加适合完成光栅化、动画变换等耗时任务,在移动设备上比起使用CPU来完成这些任务,GPU会更加省电,带来的用户体验也会更佳。
  • 现代移动GPU支持可编程管线,可以高效地开发应用界面的一些特效(吸入、渐变、模糊、阴影)


Skia Backend有两种:SkiaGl和SkiaVk,分别对应后端OpenGLES和Vulkan

二、核心组件

  1. Skia图形库:
    • Skia是HWUI的核心图形库,提供了基础的绘制功能,如图形、文本、位图等。
    • 它支持硬件加速渲染,能够充分利用GPU进行并发计算,加快UI界面的渲染速度。
    • 代码示例
      // 创建画布
      Canvas canvas = new Canvas(bitmap);
      // 绘制矩形
      Paint paint = new Paint();
      final int color = Color.BLUE;
      paint.setColor(color);
      RectF rect = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
      canvas.drawRoundRect(rect, 32, 32, paint);
  2. OpenGL ES/Vulkan:
    • OpenGL ES/Vulkan是HWUI与GPU之间的桥梁,负责将Skia生成的绘制命令转化为GPU能够执行的指令序列。
    • OpenGL ES 3.0是HWUI的默认版本,具有更好的功能和性能表现。未来HWUI的Backend默认会切换到Vulkan。
  3. DisplayList:
    • DisplayList是HWUI的渲染列表,用于记录绘制操作以及它们的位置、大小等信息。
    • 这些操作被显式地缓存起来,以便后续可以更快速地进行处理,并允许视图树中相同的部分在多个帧之间重复使用,从而节约内存和带宽。
    • 代码示例
      // 创建DisplayList
      DisplayList displayList = new DisplayList("MyList");
      displayList.start(512, 512); //设置宽高
      // 添加绘制操作
      Paint paint = new Paint();
      paint.setColor(Color.RED);
      paint.setStyle(Paint.Style.FILL);
      displayList.drawRect(64, 64, 256, 256, paint);
      // 结束DisplayList
      displayList.end();
  4. RenderNode:
    • RenderNode是HWUI的渲染节点,对应于视图层次结构中的一个节点。
    • 每个View持有一个RenderNode,这些RenderNode组成树形结构,用于管理和组织渲染任务。
    • RenderNode负责保存和管理View绘制过程中使用的各种属性,如透明度和边框等。
    • 代码示例
      // 创建RenderNode
      RenderNode renderNode = new RenderNode("MyNode");
      // 更新RenderNode属性
      View view = findViewById(R.id.myView);
      renderNode.setPosition(view.getLeft(), view.getTop());
      renderNode.setElevation(view.getElevation());
      Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.icon);
      renderNode.setBitmapCache(bitmap);
      // 添加子节点
      RenderNode child = new RenderNode("MyChild");
      //更新child属性
      renderNode.addChild(child);
  5. Layers
    • Layer是HWUI的另一个重要概念,用于实现UI的专业效果和动画效果。
    • 在Android 10及以前的系统中,所有视图都隶属于共享的系统组层级。但是在Android 11及以后的系统中,每个窗口/活动/碎片都将拥有自己的独立图层级别,从而增强了性能和隐私管理。
    • 代码示例
      // 创建Layer
      Layer layer = mSurface.getLayer();
      layer.setX(100);
      layer.setY(100);
      layer.setAlpha(0.5f);
      // 在Layer上绘制图像和文字
      Canvas canvas = layer.lockCanvas();
      canvas.drawBitmap(bitmap, 0, 0, paint);
      canvas.drawText(text, 30, 100, paint);
      layer.unlockCanvasAndPost(canvas);
  6. HardwareComposer
    • HardwareComposer是Android系统中的硬件合成器,作为HWUI的主要接口之一。
    • 它的作用是在GPU输出图像到屏幕之前,对多个应用程序的渲染结果进行混合和组合,从而形成最终的显示内容。
    • 在硬件合成情况下,不需要将应用程序的UI渲染成一个帧缓存(FrameBuffer)并上传到系统RAM,从而减少内存和总线带宽的负担。
    • 代码示例
      RoutingTable routingTable = hwcomposer.createRoutingTable();
      routingTable.setOutputConfig(new OutputConfiguration(mDisplayToken, Display.DEFAULT_DISPLAY));
      Destination destination = routingTable.createDestination();
      destination.setColorMode(ColorMode.SRGB);
      destination.setBufferStream(bufferStream);
      surfaceFlinger.setTransactionState(routingTable.getTransaction());
      surfaceFlinger.applyTransaction();
  7. Threaded Rendering(多线程渲染):
    • 为了最大化利用CPU性能,HWUI采用了多线程渲染模式。
    • 通常包括UI线程和RenderThread(RT线程)。UI线程负责View的绘制逻辑和将绘制命令打包成Skia的绘制命令存储到DisplayList;RT线程则负责取出这些绘制命令并执行实际的渲染操作。

三、工作流程

  1. UI线程绘制:
    • 当View需要被绘制时,UI线程会调用相应的绘制方法(如onDraw())。
    • 这些绘制方法通过Canvas类提供的接口进行绘制操作,Canvas的绘制命令会被转化为Skia的绘制命令并存储到DisplayList中。
  2. RenderThread渲染:
    • RenderThread从DisplayList中取出绘制命令,并通过OpenGL ES接口将这些命令发送给GPU执行。
    • GPU完成绘制后,将渲染结果输出到屏幕上。
  3. 性能优化:
    • HWUI还采用了多种性能优化技术,如延时渲染列表(Deferred Display List)、绘制命令合并(Draw Op Batching)等。
    • 这些技术通过减少GPU的调用次数、优化渲染状态切换等方式来提高渲染效率。

四、Debug Commands

开关HWUI
强制开HWUI(by default HWUI is enabled):
$ adb shell setprop persist.sys.ui.hw true
$ adb shell setprop debug.viewroot.disableHW false
$ adb shell stop
$ adb shell start

强制关HWUI:
$ adb shell setprop persist.sys.ui.hw false
$ adb shell setprop debug.viewroot.disableHW true
$ adb shell stop
$ adb shell start

改变HWUI Skia backend
$ adb shell setprop debug.hwui.renderer skiagl
$ adb shell stop
$ adb shell start

可选的skia backend选项有skiagl skiavk opengl

其他Commands
$ adb shell setprop debug.hwui.show_dirty_regions true
启用后每隔一帧绘制一次dirty_regions。true为enable, false为disable.

$ adb shell setprop debug.hwui.skip_empty_damage true
设置此属性将启用或禁用丢弃empty damage的帧。true为enable, false为disable.

$ adb shell setprop debug.hwui.use_buffer_age true
控制 HWUI 是否使用 EGL_EXT_buffer_age 扩展来做partial invalidate. true为enable, false为恢复使用 BUFFER_PRESERVED.

$adb shell setprop debug.hwui.use_partial_updates true
将其设置为“false”将强制 HWUI 始终对表面进行完全重绘。
这将禁用 EGL_EXT_buffer_age 和 BUFFER_PRESERVED 的使用

$ adb shell setprop debug.hwui.use_gpu_pixel_buffers true
指示 PBO 是否可用于支持像素缓冲区。
可接受的值为“true”和“false”。默认为 true。

$ adb shell service call SurfaceFlinger 1008 i32 1

强制使用GLES进行layer合成,不用HardwareComposer

五、总结

Android HWUI通过利用GPU进行硬件加速渲染,显著提高了Android系统的UI渲染性能和流畅度。它通过Skia图形库、OpenGL ES接口、DisplayList、RenderNode以及多线程渲染等技术手段实现了高效的UI渲染过程。同时,HWUI还不断引入新的性能优化技术来进一步提升渲染效率。

posted @ 2024-08-14 18:20  青山牧云人  阅读(174)  评论(0编辑  收藏  举报