[关闭]
@ltlovezh 2020-05-30T19:50:52.000000Z 字数 10841 阅读 2717

Android图形系统系统篇之HWC

图形系统 系统篇 HWC


HWC概述

HWC(hwcomposer)是Android中进行窗口(Layer)合成和显示的HAL层模块,其实现是特定于设备的,而且通常由显示设备制造商 (OEM)完成,为SurfaceFlinger服务提供硬件支持。

SurfaceFlinger可以使用OpenGL ES合成Layer,这需要占用并消耗GPU资源。大多数GPU都没有针对图层合成进行优化,当SurfaceFlinger通过GPU合成图层时,应用程序无法使用GPU进行自己的渲染。而HWC通过硬件设备进行图层合成,可以减轻GPU的合成压力。

显示设备的能力千差万别,很难直接用API表示硬件设备支持合成的Layer数量,Layer是否可以进行旋转和混合模式操作,以及对图层定位和硬件合成的限制等。因此HWC描述上述信息的流程是这样的:

  1. SurfaceFlingerHWC提供所有Layer的完整列表,让HWC根据其硬件能力,决定如何处理这些Layer
  2. HWC会为每个Layer标注合成方式,是通过GPU还是通过HWC合成。
  3. SurfaceFlinger负责先把所有注明GPU合成的Layer合成到一个输出Buffer,然后把这个输出Buffer和其他Layer(注明HWC合成的Layer)一起交给HWC,让HWC完成剩余Layer的合成和显示。

虽然每个显示设备的能力不同,但是官方要求每个HWC硬件模块都应该支持以下能力:

  1. 至少支持4个叠加层:状态栏、系统栏、应用本身和壁纸或者背景。
  2. 叠加层可以大于显示屏,例如:壁纸
  3. 同时支持预乘每像素(per-pixel)Alpha混合和每平面(per-plane)Alpha混合。
  4. 为了支持受保护的内容,必须提供受保护视频播放的硬件路径。
  5. RGBA packing order, YUV formats, and tiling, swizzling, and stride properties

Tiling:可以把Image切割成MxN个小块,最后渲染时,再将这些小块拼接起来,就像铺瓷砖一样。
Swizzling:一种拌和技术,表示向量单元可以被任意地重排或重复。

但是并非所有情况下HWC都比GPU更高效,例如:当屏幕上没有任何变化时,尤其是叠加层有透明像素并且需要进行图层透明像素混合时。在这种情况下,HWC可以要求部分或者全部叠加层都进行GPU合成,然后HWC持有合成的结果Buffer,如果SurfaceFlinger要求合成相同的叠加图层列表,HWC可以直接显示之前合成的结果Buffer,这有助于提高待机设备的电池寿命。

HWC也提供了VSync事件,用于管理渲染和图层合成时机,后续文章会进行介绍。

HWC2实现

Android7.0提供了HWC和HWC2两个版本,默认使用HWC,但是手机厂商也可以选择HWC2,如下所示:

  1. // frameworks\native\services\surfaceflinger\Android.mk
  2. USE_HWC2 := false
  3. ifeq ($(USE_HWC2),true)
  4. LOCAL_CFLAGS += -DUSE_HWC2
  5. LOCAL_SRC_FILES += \
  6. SurfaceFlinger.cpp \
  7. DisplayHardware/HWComposer.cpp
  8. else
  9. LOCAL_SRC_FILES += \
  10. SurfaceFlinger_hwc1.cpp \
  11. DisplayHardware/HWComposer_hwc1.cpp
  12. endif

SurfaceFlinger通过HWComposer使用HWC硬件能力,HWComposer构造函数通过loadHwcModule方法加载HWC模块,并封装成HWC2::Device结构,如下所示:

  1. // Load and prepare the hardware composer module,HWComposer构造函数中通过此方法加载HWC模块
  2. void HWComposer::loadHwcModule()
  3. {
  4. // 定义在hardware.h中,表示一个硬件模块,是HAL层的灵魂
  5. hw_module_t const* module;
  6. // 加载硬件厂商提供的hwcomposer模块,HWC_HARDWARE_MODULE_ID定义在hwcomposer_defs.h中,表示"hwcomposer"
  7. if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
  8. ALOGE("%s module not found, aborting", HWC_HARDWARE_MODULE_ID);
  9. abort();
  10. }
  11. hw_device_t* device = nullptr;
  12. // 通过硬件厂商提供的open函数打开一个"composer"硬件设备,HWC_HARDWARE_COMPOSER也定义在hwcomposer_defs.h中,表示"composer"
  13. int error = module->methods->open(module, HWC_HARDWARE_COMPOSER, &device);
  14. if (error != 0) {
  15. ALOGE("Failed to open HWC device (%s), aborting", strerror(-error));
  16. abort();
  17. }
  18. uint32_t majorVersion = (device->version >> 24) & 0xF;
  19. // mHwcDevice是HWC2.h中定义的HWC2::Device,所有与HWC的交互都通过mHwcDevice
  20. if (majorVersion == 2) { // HWC2,hwc2_device_t是hwcomposer2.h中的结构体,表示HWC2对基础hw_device_t结构的扩展,该结构体的第一个字段必须是hw_device_t
  21. mHwcDevice = std::make_unique<HWC2::Device>(
  22. reinterpret_cast<hwc2_device_t*>(device));
  23. } else { // 设备是基于HWC1,这里用HWC2去适配,Android7.0及以前默认都是HWC1,hwc_composer_device_1_t是hwcomposer.h中的结构体,表示HWC1对基础hw_device_t结构的扩展,该结构体的第一个字段必须是hw_device_t
  24. mAdapter = std::make_unique<HWC2On1Adapter>(
  25. reinterpret_cast<hwc_composer_device_1_t*>(device));
  26. mHwcDevice = std::make_unique<HWC2::Device>(
  27. static_cast<hwc2_device_t*>(mAdapter.get()));
  28. }
  29. // 获取硬件支持的最大虚拟屏幕数量,VirtualDisplay可用于录屏
  30. mRemainingHwcVirtualDisplays = mHwcDevice->getMaxVirtualDisplayCount();
  31. }

先加载hwcomposer模块得到hw_module_t,再打开composer设备得到hw_device_thw_module_thw_device_t定义在hardware\libhardware\include\hardware\hardware.h,表示一个HAL层模块和属于该模块的一个实现设备。注意这里是先有HAL模块,再有实现此模块的硬件设备。

上述通过hw_get_module方法(hardware\libhardware\hardware.c)加载hwcomposer模块,此模块由硬件厂商提供实现,例如:hardware\libhardware\modules\hwcomposer\hwcomposer.cpp是hwcomposer模块基于HWC1的default实现,对应的共享库是hwcomposer.default.so;hardware\qcom\display\msm8994\libhwcomposer\hwc.cpp是高通MSM8994基于HWC1的实现,对应的共享库是hwcomposer.msm8994.so
如果是基于HWC2协议实现,则需要实现hwcomposer2.h中定义的hwc2_device_t接口,例如:class VendorComposer : public hwc2_device_t。Android7.0的hwcomposer模块默认都是基于HWC1协议实现的。
每个HAL层模块实现都要定义一个HAL_MODULE_INFO_SYM数据结构,并且该结构的第一个字段必须是hw_module_t,下面是高通MSM8994hwcomposer模块的定义:

  1. // 高通MSM8994
  2. hwc_module_t HAL_MODULE_INFO_SYM = {
  3. // common表示hw_module_t模块
  4. common: {
  5. tag: HARDWARE_MODULE_TAG,
  6. version_major: 2,
  7. version_minor: 0,
  8. id: HWC_HARDWARE_MODULE_ID, // hwcomposer
  9. name: "Qualcomm Hardware Composer Module",
  10. author: "CodeAurora Forum",
  11. methods: &hwc_module_methods,
  12. dso: 0,
  13. reserved: {0},
  14. }
  15. };
  1. hw_module_t是HAL层的灵魂,每个硬件模块都要在HAL_MODULE_INFO_SYM中为hw_module_t结构体的指定数据,其中包含了打开hw_device_t的函数指针。
  2. 针对HWC模块,如果是基于HWC1协议实现,则提供了hwc_composer_device_1结构体标识硬件设备;如果是基于HWC2协议实现,则提供了hwc2_device_t结构体标识硬件设备。这两个结构体的第一个字段必须是hw_device_t,这样上述代码中才能把hw_device_t转换成hwc_composer_device_1hw_device_t
  3. 最重要的一点:HWComposer::loadHwcModule方法最终把HWC模块封装成了HWC2::Device

frameworks\native\services\surfaceflinger\DisplayHardware\HWC2.h主要定义了以下三个结构体:

  1. HWC2::Device:表示硬件合成显示设备
  2. HWC2::Display:表示一个显示屏幕,可以是物理显示屏(可以热插拔接入或者移除),也可以是虚拟显示屏,现在的游戏录屏一般都是基于虚拟屏幕实现的。
  3. HWC2::Layer:表示一个叠加图层,与应用侧的Surface相对应。

    一个HWC2::Device可以包含多个HWC2::Display
    一个HWC2::Display可以包含多个HWC2::Layer


HWCHWC2::Devicehwc2_device_thwcomposer2.h
HWC2::DeviceDevice::loadFunctionPointersloadFunctionPointer(FunctionDescriptor desc, PFN& outPFN)hwc2_device_t::getFunction

  1. // 模板函数,用于向硬件设备查询具体的函数指针实现
  2. template <typename PFN>
  3. [[clang::warn_unused_result]] bool loadFunctionPointer(
  4. FunctionDescriptor desc, PFN& outPFN) {
  5. // desc表示一个枚举类型值
  6. auto intDesc = static_cast<int32_t>(desc);
  7. // mHwcDevice表示hwc2_device_t,是硬件驱动提供的实现
  8. auto pfn = mHwcDevice->getFunction(mHwcDevice, intDesc);
  9. if (pfn != nullptr) {
  10. // 强转函数指针
  11. outPFN = reinterpret_cast<PFN>(pfn);
  12. return true;
  13. } else {
  14. ALOGE("Failed to load function %s", to_string(desc).c_str());
  15. return false;
  16. }
  17. }
  1. 硬件设备(Device)相关的函数指针
  2. 显示屏幕(Display)相关的函数指针
  3. 叠加图层(Layer)相关的函数指针

通过上述函数指针可以与hwc2_device_t表示的硬件合成模块进行交互。三类指针分别选取了一个示例:

  1. // Device方法:获得设备支持的最大虚拟屏幕个数
  2. uint32_t Device::getMaxVirtualDisplayCount() const
  3. {
  4. return mGetMaxVirtualDisplayCount(mHwcDevice);
  5. }
  6. // Display方法:为指定Device的指定Display创建一个Layer
  7. Error Display::createLayer(std::shared_ptr<Layer>* outLayer)
  8. {
  9. // 表示创建的layer的唯一标识符
  10. hwc2_layer_t layerId = 0;
  11. // mDevice.mHwcDevice表示hwc2_device_t,即真正的硬件设备,mId表示当前Display的唯一标识符,即为指定Device的指定Display创建一个Layer
  12. int32_t intError = mDevice.mCreateLayer(mDevice.mHwcDevice, mId, &layerId);
  13. auto error = static_cast<Error>(intError);
  14. if (error != Error::None) {
  15. return error;
  16. }
  17. // 基于layerId创建HWC2::Layer
  18. auto layer = std::make_shared<Layer>(shared_from_this(), layerId);
  19. // 保存当前Display所有的Layer
  20. mLayers.emplace(layerId, layer);
  21. // 返回创建的HWC2::Layer
  22. *outLayer = std::move(layer);
  23. return Error::None;
  24. }
  25. // Layer方法:为指定Device的指定Display的指定Layer指定合成方式
  26. Error Layer::setCompositionType(Composition type)
  27. {
  28. auto intType = static_cast<int32_t>(type);
  29. // 为指定Device的指定Display的指定Layer指定合成方式
  30. int32_t intError = mDevice.mSetLayerCompositionType(mDevice.mHwcDevice,
  31. mDisplayId, mId, intType);
  32. return static_cast<Error>(intError);
  33. }

可以通过类图,直观感受下引用关系。
HWC类图

HWC2::Device构造函数除了完成获取函数指针实现以外,还会通过Device::registerCallbacks向硬件设备注册三个Display的回调:热插拔,刷新和VSync信号,如下所示:

  1. // HWC硬件的几种回调描述符
  2. // hardware\libhardware\include\hardware\hwcomposer2.h
  3. enum class Callback : int32_t {
  4. Invalid = HWC2_CALLBACK_INVALID,
  5. // 显示屏幕(Display)的热插拔
  6. Hotplug = HWC2_CALLBACK_HOTPLUG,
  7. // 显示屏幕(Display)的刷新
  8. Refresh = HWC2_CALLBACK_REFRESH,
  9. // 显示屏幕(Display)的VSync信号
  10. Vsync = HWC2_CALLBACK_VSYNC,
  11. };
  12. // 注册热插拔/刷新/VSync回调
  13. void Device::registerCallbacks()
  14. { // Callback枚举类型如上所示
  15. registerCallback<HWC2_PFN_HOTPLUG>(Callback::Hotplug, hotplug_hook);
  16. registerCallback<HWC2_PFN_REFRESH>(Callback::Refresh, refresh_hook);
  17. registerCallback<HWC2_PFN_VSYNC>(Callback::Vsync, vsync_hook);
  18. }
  19. // 模板函数,用于向硬件设备(hwc2_device_t)注册函数回调
  20. template <typename PFN, typename HOOK>
  21. void registerCallback(Callback callback, HOOK hook) {
  22. // Callback枚举类型如上所示
  23. auto intCallback = static_cast<int32_t>(callback);
  24. // this表示HWC2::Device, hwc2_callback_data_t表示void指针类型
  25. auto callbackData = static_cast<hwc2_callback_data_t>(this);
  26. // 把函数指针强转成统一的void (*)() 函数指针类型
  27. auto pfn = reinterpret_cast<hwc2_function_pointer_t>(hook);
  28. // 向hwc2_device_t注册函数回调,callbackData表示透传的资源
  29. mRegisterCallback(mHwcDevice, intCallback, callbackData, pfn);
  30. }
  31. // 以VSync的静态函数为例
  32. static void vsync_hook(hwc2_callback_data_t callbackData,
  33. hwc2_display_t displayId, int64_t timestamp) {
  34. // callbackData表示透传的void指针,实际指HWC2::Device
  35. auto device = static_cast<HWC2::Device*>(callbackData);
  36. // 通过displayId获取对应的HWC2::Display
  37. auto display = device->getDisplayById(displayId);
  38. if (display) {
  39. // 向外回调
  40. device->callVsync(std::move(display), timestamp);
  41. } else {
  42. ALOGE("Vsync callback called with unknown display %" PRIu64, displayId);
  43. }
  44. }
  45. void Device::callVsync(std::shared_ptr<Display> display, nsecs_t timestamp)
  46. {
  47. // 通过std::function可调用对象mVsync向外回调,该可调用对象实际是HWComposer通过Device::registerVsyncCallback方法注册的
  48. if (mVsync) {
  49. mVsync(std::move(display), timestamp);
  50. } else {
  51. mPendingVsyncs.emplace_back(std::move(display), timestamp);
  52. }
  53. }

总结一下,HWC2::Device构造函数向硬件设备注册三个Display回调:热插拔,刷新和VSync信号。当HWC2::Device收到这些回调时,会通过监听器向外回调到对应的HWComposer函数:HWComposer::hotplug/HWComposer::invalidate/HWComposer::vsync。HWComposer再通过这些信息驱动对应工作,后续文章进行介绍。

HWC Layer合成方式

上文提到HWC2::Device中的函数指针是hardware\libhardware\include\hardware\hwcomposer2.h中定义的,除此之外,该头文件还定义了一些重要的结构体,这里介绍两个比较重要的:

  1. // 显示屏类型
  2. enum class DisplayType : int32_t {
  3. Invalid = HWC2_DISPLAY_TYPE_INVALID,
  4. // 物理显示屏,显示设备有一个主屏幕,然后可以通过热插拔添加或者删除外接显示屏
  5. Physical = HWC2_DISPLAY_TYPE_PHYSICAL,
  6. // 虚拟显示屏,内容会渲染到离屏缓冲区,Android录屏功能就是基于虚拟屏实现的
  7. Virtual = HWC2_DISPLAY_TYPE_VIRTUAL,
  8. };
  9. // Layer合成类型,HWC2_COMPOSITION_XX取自hwc2_composition_t枚举
  10. enum class Composition : int32_t {
  11. Invalid = HWC2_COMPOSITION_INVALID,
  12. Client = HWC2_COMPOSITION_CLIENT,
  13. Device = HWC2_COMPOSITION_DEVICE,
  14. SolidColor = HWC2_COMPOSITION_SOLID_COLOR,
  15. Cursor = HWC2_COMPOSITION_CURSOR,
  16. Sideband = HWC2_COMPOSITION_SIDEBAND,
  17. };

DisplayType表示显示屏类型,上面注释已经介绍,重点看下Layer合成类型:

  1. Client:这里的Client是相对于HWC硬件设备来说的,即不通过HWC来合成图层,而是通过GPU先把所有的这类图层合成到client target buffer(一个离屏的图形缓冲区,buffer_handle_t表示指向这块显存的指针,显存由Gralloc模块分配),然后再通过Display::setClientTarget把这块图形Buffer的地址传递给HWC设备,最后由HWC设备把其他Layer和这个图形Buffer进一步合成,并最终展示在Display上。
  2. Device:通过HWC硬件来合成图层,默认情况下,SurfaceFlinger会配置每个Layer都通过Device方式合成,但是HWC设备会根据硬件设备的性能改变某些图层的合成方式。
  3. SolidColor:HWC设备将通过Layer::setColor设置的颜色渲染这个图层,如果HWC设备不支持这种合成方式,那么将会请求SurfaceFlinger改变合成方式为Client。
  4. Cursor:与Device类似,但是这个图层的位置可以通过setCursorPosition异步设置。如果HWC设备不支持这种合成方式,那么将会请求SurfaceFlinger改变合成方式为Client或者Device。
  5. Sideband:HWC硬件会处理该类图层的合成,以及它的缓冲区更新和内容同步,但是只有拥有HWC2_CAPABILITY_SIDEBAND_STREAM能力的设备才支持这种图层,若设备不支持,那么将会请求SurfaceFlinger改变合成方式为Client或者Device。

那么一个Layer的合成方式是怎么确定的那?大致流程如下所示:
Layer合成方式

  1. 当VSync信号到来时,SurfaceFlinger被唤醒,处理Layer的新建,销毁和更新,并且为相应Layer设置期望的合成方式。
  2. 所有Layer更新后,SurfaceFlinger调用validateDisplay,让HWC决定每个Layer的合成方式。
  3. SurfaceFlinger调用getChangedCompositionTypes检查HWC是否对任何Layer的合成方式做出了改变,若是,那么SurfaceFlinger则调整对应Layer的合成方式,并且调用acceptDisplayChanges通知HWC。
  4. SurfaceFlinger把所有Client类型的Layer合成到Target图形缓冲区,然后调用setClientTarget把Target Buffer设置给HWC。(如果没有Client类型的Layer,则可以跳过该方法)
  5. 最后,SurfaceFlinger调用presentDisplay,让HWC完成剩余Layer的合成,并且在显示屏上展示出最终的合成结果。

总结

本篇文章只是简单介绍了HWC模块的相关类:HWComposerHWC2::DeviceHWC2::DisplayHWC2::Layer,以及它们的关系。此外,还着重介绍了Layer的合成方式和合成流程。后续文章会更加全面的介绍SurfaceFlinger是如何通过HWC模块完成Layer合成和上屏的(虚拟屏幕是到离屏缓冲区)。

相关源码

  1. hardware\libhardware\include\hardware\hardware.h
  2. hardware\libhardware\hardware.c
  3. hardware\libhardware\include\hardware\hwcomposer_defs.h
  4. hardware\libhardware\include\hardware\hwcomposer.h
  5. hardware\libhardware\include\hardware\hwcomposer2.h
  6. frameworks\native\services\surfaceflinger\DisplayHardware\HWC2.h
  7. frameworks\native\services\surfaceflinger\DisplayHardware\HWC2.cpp
  8. frameworks\native\services\surfaceflinger\DisplayHardware\HWComposer.h
  9. frameworks\native\services\surfaceflinger\DisplayHardware\HWComposer.cpp
  10. frameworks\native\services\surfaceflinger\SurfaceFlinger.h
  11. frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注