Android下HWC以及drm_hwcomposer普法((上)

news2024/11/17 5:32:21

Android下HWC以及drm_hwcomposer普法((上)



引言

按摩得全套,错了,做事情得全套,普法分析也是如此。drm_hwcomposer如果对Android图形栈有一定研究的童鞋们应该知道它是Android提供的一个的图形后端合成处理HAL模块的实现。但是在分析这个之前我们非常有必要了解一下Android的HWC前世今生,然后再来看drm_hwcomposer是如何配合HWC框架的



一.普法HWC

这里我们对HWC的普法主要从如下接方面展开进行:

  • HWC的概述
  • HWC的进化
  • HWC中重要概念和实现逻辑

1.1 HWC概述

我们知道SurfaceFlinger可以使用OpenGLES合成Layer,但是这需要占用并消耗大量的GPU资源。大多数GPU都没有针对图层合成进行优化,当SurfaceFlinger通过GPU合成图层时,应用程序无法使用GPU进行自己的渲染。为了解放GPU的绘制能力,很多芯片厂家会提供硬件叠加合成,如果硬件叠加器支持的场景都可以走硬件叠加,解放GPU的绘制能力专心绘制,提升的渲染性能同时还能大幅度的降低功耗(GPU强绘制,叠加搬移并不擅长,高功耗)这个时候我们的HWC就登场了,HWC(hwcomposer)是Android中进行窗口(Layer)合成和显示的HAL层模块,其实现是特定于设备的,而且通常由显示设备制造商(OEM)完成,为SurfaceFlinger服务提供硬件支持。而HWC通过硬件设备进行图层合成,可以减轻GPU的合成压力。应用把要显示的layers交给SurfaceFlinger,SurfaceFlinger直接把这些layers交给hwc,hwc就可以在自己能力范围内做好合成,再把合成好的结果拿去显示。如果芯片显示硬件模块功能较弱,不支持某些合成场景,就会用CPU(纯软件合成)或者GPU去做。

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/9a3f7e78b54d428e9774210da401ffda.png)

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

  • SurfaceFlinger向HWC提供所有Layer的完整列表,让HWC根据其硬件能力,决定如何处理这些Layer。

  • HWC会为每个Layer标注合成方式,是通过GPU还是通过HWC合成。

  • SurfaceFlinger负责先把所有注明GPU合成的Layer合成到一个输出Buffer,然后把这个输出Buffer和其他Layer(注明HWC合成的Layer)一起交给HWC,让HWC完成剩余Layer的合成和显示。
    虽然每个显示设备的能力不同,但是官方要求每个HWC硬件模块都应该支持以下能力:

  • 至少支持4个叠加层:状态栏、系统栏、应用本身和壁纸或者背景。

  • 叠加层可以大于显示屏,例如:壁纸

  • 同时支持预乘每像素(per-pixel)Alpha混合和每平面(per-plane)Alpha混合。

  • 为了支持受保护的内容,必须提供受保护视频播放的硬件路径。
    RGBA packing order, YUV formats, and tiling, swizzling, and stride properties

虽然上述官网要求如此,但是,但是很多hwc是没有达到上述要求的,有的叠加只支持一层的primary plane,也不支持各种混合,各种特性,毕竟建议还是建议。
Tiling:可以把Image切割成MxN个小块,最后渲染时,再将这些小块拼接起来,就像铺瓷砖一样。
Swizzling:一种拌和技术,表示向量单元可以被任意地重排或重复。 但是并非所有情况下HWC都比GPU更高效,例如:当屏幕上没有任何变化时,尤其是叠加层有透明像素并且需要进行图层透明像素混合时。在这种情况下,HWC可以要求部分或者全部叠加层都进行GPU合成,然后HWC持有合成的结果Buffer,如果SurfaceFlinger要求合成相同的叠加图层列表,HWC可以直接显示之前合成的结果Buffer,这有助于提高待机设备的电池寿命。

HWC也提供了VSync事件,用于管理渲染和图层合成时机。


1.2 HWC的进化

Android的HWC模块经历了HWC和HWC2两个版本,现在高版本默认使用HWC2,然后其加载方式也由原来的的SurfaceFlinger直接通过loader加载HAL模块,变成现在的通过HIDL调用到composer service单独加载HAL模块实现。活是越来越整得复杂了。

无论通过和中方式加载HAL的实现,我们需要知道的一点就是HAL加载的流程是,先加载hwcomposer模块得到hw_module_t,再打开composer设备得到hw_device_t。hw_module_t和hw_device_t定义在hardware/libhardware/include/hardware/hardware.h,表示一个HAL层模块和属于该模块的一个实现设备。注意这里是先有HAL模块,再有实现此模块的硬件设备。

struct hw_module_t;
struct hw_module_methods_t;
struct hw_device_t;


typedef struct hw_module_t {
    uint32_t tag;

    uint16_t module_api_version;
#define version_major module_api_version
#define version_minor hal_api_version

    /** Identifier of module */
    const char *id;

    /** Name of this module */
    const char *name;

    /** Author/owner/implementor of the module */
    const char *author;

    /** Modules methods */
    struct hw_module_methods_t* methods;

    /** module's dso */
    void* dso;

#ifdef __LP64__
    uint64_t reserved[32-7];
#else
    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];
#endif

} hw_module_t;

typedef struct hw_module_methods_t {
    /** Open a specific device */
    int (*open)(const struct hw_module_t* module, const char* id,
            struct hw_device_t** device);

} hw_module_methods_t;


typedef struct hw_device_t {
    /** tag must be initialized to HARDWARE_DEVICE_TAG */
    uint32_t tag;


    uint32_t version;

    /** reference to the module this device belongs to */
    struct hw_module_t* module;

    /** padding reserved for future use */
#ifdef __LP64__
    uint64_t reserved[12];
#else
    uint32_t reserved[12];
#endif

    /** Close this device */
    int (*close)(struct hw_device_t* device);

} hw_device_t;

#ifdef __cplusplus
#define TO_HW_DEVICE_T_OPEN(x) reinterpret_cast<struct hw_device_t**>(x)
#else
#define TO_HW_DEVICE_T_OPEN(x) (struct hw_device_t**)(x)
#endif

/**
 * Name of the hal_module_info
 */
#define HAL_MODULE_INFO_SYM         HMI

/**
 * Name of the hal_module_info as a string
 */
#define HAL_MODULE_INFO_SYM_AS_STR  "HMI"


int hw_get_module(const char *id, const struct hw_module_t **module);


int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module);

__END_DECLS

#endif  /* ANDROID_INCLUDE_HARDWARE_HARDWARE_H */

我们是基于HWC2协议实现,则需要实现hwcomposer2.h中定义的hwc2_device_t接口,而我们后续要分析的drm_hwcomposer就是基于HWC2的实现。每个HAL层模块实现都要定义一个HAL_MODULE_INFO_SYM数据结构,并且该结构的第一个字段必须是hw_module_t。这里关于它们之间的对应关系,和一些数据结构这里暂时不分析,太多了,这里我们不做过多分析。


1.3 HWC中重要的概念和核心调用逻辑

这里我们的重点不是SurfaceFlinger里面HWC相关的代码部分分析,但是该有的概念和一些核心调用逻辑还是必须提前知道:

但是我们如下的几个重要的概念我们必须要有:

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

在进行接下来的分析前,我们先来一个Layer的合成方式是怎么确定的那?大致流程如下所示!

在这里插入图片描述

其基本流程可以归纳总结为如下:

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

  • HWC2::Layer的创建流程
SurfaceFlinger::onMessageReceived
  onMessageRefresh()//Android 13上面是通过andler::handleMessage compositor.composite
    mCompositionEngine->present(refreshArgs)
      output->prepare(args, latchedLayers)
        Output::rebuildLayerStacks
          Output::collectVisibleLayers
            Output::ensureOutputLayerIfVisible
              BaseOutput::createOutputLayer(layerFE)
                Display::createOutputLayer
                  hwc.createLayer
                    mComposer.createLayer
                        HwcDisplay::CreateLayer//drm_hwcomposer
05-26 01:57:17.427  2264  2264 D createOutputLayer: #00 pc 000000000013f994  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::Display::createOutputLayer(android::sp<android::compositionengine::LayerFE> const&) const+84)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #01 pc 0000000000140dfc  /system/lib64/libsurfaceflinger.so (std::__1::shared_ptr<android::compositionengine::impl::Display> android::compositionengine::impl::createOutputTemplated<android::compositionengine::impl::Display, android::compositionengine::CompositionEngine>(android::compositionengine::CompositionEngine const&)::Output::ensureOutputLayer(std::__1::optional<unsigned long>, android::sp<android::compositionengine::LayerFE> const&)+80)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #02 pc 00000000001475e0  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::Output::ensureOutputLayerIfVisible(android::sp<android::compositionengine::LayerFE>&, android::compositionengine::Output::CoverageState&)+1692)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #03 pc 0000000000146e60  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::Output::collectVisibleLayers(android::compositionengine::CompositionRefreshArgs const&, android::compositionengine::Output::CoverageState&)+128)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #04 pc 0000000000146d38  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::Output::rebuildLayerStacks(android::compositionengine::CompositionRefreshArgs const&, std::__1::unordered_set<android::sp<android::compositionengine::LayerFE>, android::compositionengine::LayerFESpHash, std::__1::equal_to<android::sp<android::compositionengine::LayerFE> >, std::__1::allocator<android::sp<android::compositionengine::LayerFE> > >&)+340)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #05 pc 0000000000146a3c  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::Output::prepare(android::compositionengine::CompositionRefreshArgs const&, std::__1::unordered_set<android::sp<android::compositionengine::LayerFE>, android::compositionengine::LayerFESpHash, std::__1::equal_to<android::sp<android::compositionengine::LayerFE> >, std::__1::allocator<android::sp<android::compositionengine::LayerFE> > >&)+56)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #06 pc 000000000013eb3c  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::CompositionEngine::present(android::compositionengine::CompositionRefreshArgs&)+116)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #07 pc 0000000000111c08  /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::onMessageRefresh()+1524)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #08 pc 000000000010ee5c  /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int, long)+88)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #09 pc 0000000000019b8c  /system/lib64/libutils.so (android::Looper::pollInner(int)+372)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #10 pc 00000000000199b0  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #11 pc 00000000000f7850  /system/lib64/libsurfaceflinger.so (android::impl::MessageQueue::waitMessage()+84)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #12 pc 0000000000108594  /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::run()+20)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #13 pc 0000000000002394  /system/bin/surfaceflinger (main+844)
05-26 01:57:17.428  2264  2264 D createOutputLayer: #14 pc 000000000008506c  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108)


  • HWC2::Layer设置buffer的流程
//通过Composer::setLayerBuffer调用堆栈,将buffer\_handle\_t信息传递到hwc2的HAL层实现的
onMessageRefresh()
  mCompositionEngine->present(refreshArgs)
    output->present(args)  //Output.cpp
      Output::updateAndWriteCompositionState(refreshArgs)
        layer->writeStateToHWC
          writeOutputIndependentPerFrameStateToHWC
             OutputLayer.cpp:471 writeBufferStateToHWC
              HwcLayer::SetLayerBuffer //drm_hwcomposer
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #00 pc 00000000000b4028  /system/lib64/libsurfaceflinger.so (android::Hwc2::impl::Composer::setLayerBuffer(unsigned long, unsigned long, unsigned int, android::sp<android::GraphicBuffer> const&, int)+96)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #01 pc 00000000001514c8  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::OutputLayer::writeBufferStateToHWC(android::HWC2::Layer*, android::compositionengine::LayerFECompositionState const&)+344)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #02 pc 0000000000150e74  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::OutputLayer::writeOutputIndependentPerFrameStateToHWC(android::HWC2::Layer*, android::compositionengine::LayerFECompositionState const&)+484) OutputLayer.cpp:471 writeBufferStateToHWC
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #03 pc 00000000001500ac  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::OutputLayer::writeStateToHWC(bool)+180) OutputLayer.cpp:342 writeOutputIndependentPerFrameStateToHWC
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #04 pc 00000000001479a4  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::Output::updateAndWriteCompositionState(android::compositionengine::CompositionRefreshArgs const&)+356) Output.cpp:607 layer->writeStateToHWC
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #05 pc 0000000000146b2c  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::Output::present(android::compositionengine::CompositionRefreshArgs const&)+64) Output.cpp:313  updateAndWriteCompositionState(refreshArgs)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #06 pc 000000000013ebe8  /system/lib64/libsurfaceflinger.so (android::compositionengine::impl::CompositionEngine::present(android::compositionengine::CompositionRefreshArgs&)+220) CompositionEngine.cpp output->present(args)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #07 pc 0000000000111c4c  /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::onMessageRefresh()+1524) mCompositionEngine->present(refreshArgs);
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #08 pc 000000000010eea0  /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::onMessageReceived(int, long)+88)   onMessageRefresh()
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #09 pc 0000000000019b8c  /system/lib64/libutils.so (android::Looper::pollInner(int)+372)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #10 pc 00000000000199b0  /system/lib64/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+112)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #11 pc 00000000000f7894  /system/lib64/libsurfaceflinger.so (android::impl::MessageQueue::waitMessage()+84)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #12 pc 00000000001085d8  /system/lib64/libsurfaceflinger.so (android::SurfaceFlinger::run()+20)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #13 pc 0000000000002394  /system/bin/surfaceflinger (main+844)
05-26 01:57:51.122  2280  2280 D setLayerBuffer: #14 pc 000000000008506c  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108)



二. drm_hwcomposer普法

drm_hwcomposer作为HWC框架的HAL实现,它是怎么承接HWC的接口,并且实现相关逻辑的呢。这就离不开它的设计逻辑了,分为frontend前端和backend后端处理逻辑。

  • frontend 是对外提供调用的接口,,外部使用者呼叫 front end 暴漏出的接口来呼叫某一功能;
  • backend 主要是调用内核的实现逻辑,是前端接口功能的内部实现,是真正做事的地方

其中最最重要的就是后端的设计逻辑,分为三种情况

  • Backend: 一个后端的实现,注册为"generic",主要是定义了ValidateDisplay方法,这个方法用来设置可见的HwcLayer应该采用什么合成方式
  • BackendClient: 一个后端的实现,注册为"client",主要是定义了ValidateDisplay方法,它把所有HwcLayer都设置成立Client合成方式
  • BackendManager:后端的管理器,用来根据Device name从已注册的backend列表中选择一个,设置给HwcDisplay;GetBackendByName就是通过Device name来从available_backends_中选择一个匹配的Backend构造函数来构建后端对象。

接下来我们就从代码触发,看看它是如何使用上述的框架实现的!


2.1 drm_hwcomposer源码初探

这块我们只分析其核心实现,对于具体的一些逻辑我们带过!有些具体代码逻辑,臣妾真的是心有余而力不足啊,分析不了啊。路漫漫啊,不知道能不能走到终点! 在分析源码前,我们来看下drm_hwcomposer的目录,如下:

drm_hwcomposer
├── Android.bp   //编译脚本
├── backend      //hwcomposer后端,是前端接口功能的内部实现,是真正做事的地方
├── bufferinfo  //对应不同vendor的buffer接口
├── build_deploy.sh
├── compositor  //kms处理送显逻辑代码
├── drm         //drm,各个子模块代码
├── hwc2_device //对接Android hwc相关源码
├── include     //头文件
├── MODULE_LICENSE_APACHE2
├── NOTICE
├── presubmit.sh
├── README.md
└── utils


2.2 drm_hwcomposer的HAL模块实现

HAL是个很神秘的东东,经常会看到一些求职网站显示需要招聘会HAL开发的Android工程师,但是绝大部分的Android开发人员只会使用,很少能独立开发一个属于自己的HAL。幸运的是我也是其中的绝大部分,不幸的是我也么有开发过属于自己的HAL实现。

//hwc2_device/hwc2_device.cpp
/**
 * @brief 
 * 
 * @param module 
 * @param name 
 * @param dev 
 * @return int 
 *  HookDevOpen,该方法中会去实例化一个Drmhwc2Device对象,其中去创建了一个DrmHwcTwo对象
 */
static int HookDevOpen(const struct hw_module_t *module, const char *name,
                       struct hw_device_t **dev) {
  if (strcmp(name, HWC_HARDWARE_COMPOSER) != 0) {
    ALOGE("Invalid module name- %s", name);
    return -EINVAL;
  }

  auto ctx = std::make_unique<Drmhwc2Device>();//详见章节5.6
  if (!ctx) {
    ALOGE("Failed to allocate DrmHwcTwo");
    return -ENOMEM;
  }

  ctx->common.tag = HARDWARE_DEVICE_TAG;
  ctx->common.version = HWC_DEVICE_API_VERSION_2_0;
  ctx->common.close = HookDevClose;
  // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
  ctx->common.module = (hw_module_t *)module;
  ctx->getCapabilities = HookDevGetCapabilities;
  ctx->getFunction = HookDevGetFunction;//核心接口,详见5.5

  *dev = &ctx.release()->common;

  return 0;
}

static struct hw_module_methods_t hwc2_module_methods = {
    .open = android::HookDevOpen,
};

/**
 * @brief 
 * HAL标准化实现流程
 */
hw_module_t HAL_MODULE_INFO_SYM = {//注册HAL
    .tag = HARDWARE_MODULE_TAG,
    .module_api_version = HARDWARE_MODULE_API_VERSION(2, 0),
    .id = HWC_HARDWARE_MODULE_ID,//hwcomposer
    .name = "DrmHwcTwo module",
    .author = "The Android Open Source Project",
    .methods = &hwc2_module_methods,
    .dso = nullptr,
    .reserved = {0},
};

这一块的逻辑比较简单,就是上层hwcomposer服务加载HAL模块的时候,通过套路化的HAL编程实现加载HWC HAL的功能,并且上层调用open时候会初始化一个Drmhwc2Device返回给hwcomposer服务。其调用堆栈如下:

01-01 00:00:18.617  2262  2262 D HWC_DRM : #00 pc 000000000002bfd4  /vendor/lib64/hw/hwcomposer.drm.so (android::HookDevOpen(hw_module_t const*, char const*, hw_device_t**)+80)
01-01 00:00:18.617  2262  2262 D HWC_DRM : #01 pc 0000000000006684  /vendor/bin/hw/android.hardware.graphics.composer@2.1-service (android::hardware::graphics::composer::V2_1::passthrough::HwcLoader::openDeviceWithAdapter(hw_module_t const*, bool*)+376)
01-01 00:00:18.617  2262  2262 D HWC_DRM : #02 pc 000000000000639c  /vendor/bin/hw/android.hardware.graphics.composer@2.1-service (android::hardware::graphics::composer::V2_1::passthrough::HwcLoader::createHalWithAdapter(hw_module_t const*)+48)
01-01 00:00:18.617  2262  2262 D HWC_DRM : #03 pc 00000000000062cc  /vendor/bin/hw/android.hardware.graphics.composer@2.1-service (android::hardware::graphics::composer::V2_1::passthrough::HwcLoader::load()+164)
01-01 00:00:18.617  2262  2262 D HWC_DRM : #04 pc 0000000000006138  /vendor/bin/hw/android.hardware.graphics.composer@2.1-service (main+240)
01-01 00:00:18.617  2262  2262 D HWC_DRM : #05 pc 000000000008506c  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108)

其中Drmhwc2Device的层级关系如下:

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c9928be2b2a948b3afc66551e3328676.png)

其代码定义如下:


//hardware/libhardware/include/hardware/hwcomposer2.h
typedef struct hwc2_device {
/* Must be the first member of this struct, since a pointer to this struct
     * will be generated by casting from a hw_device_t* */
    struct hw_device_t common;
    void (*getCapabilities)(struct hwc2_device* device, uint32_t* outCount,
            int32_t* /*hwc2_capability_t*/ outCapabilities);
    hwc2_function_pointer_t (*getFunction)(struct hwc2_device* device,
            int32_t /*hwc2_function_descriptor_t*/ descriptor);
} hwc2_device_t;

//hardware/libhardware/include/hardware/hardware.h
typedef struct hw_device_t {
    tag; /** tag must be initialized to HARDWARE_DEVICE_TAG */
    uint32_t version;
    struct hw_module_t* module;
    uint64_t reserved[12];
    int (*close)(struct hw_device_t* device);
} hw_device_t;


hwc2_device/hwc2_device.cpp
struct Drmhwc2Device : hwc2_device {
  DrmHwcTwo drmhwctwo;
};

这里可以看到hwc2_device在hw_device_t的基础上扩展了,两个函数接口,其中最最核心的就是getFunction,原来在HWC时代,上层调用HAL是直接通过固化的函数硬对接上去的,现在通过getFunction可以进行许多扩展,增强可实用性。


2.3 HookDevGetFunction功能

HookDevGetFunction,我们可以把它理解为是HAL层对上提供的功能函数接口表。这些函数具体可以分为三类:

  • Device functions:其核心功能函数包括:

    • 注册回调事件 registerCallback
    • 创建虚拟通路(非显示通路,如录屏)createVirtualDisplay
    • 热拔插事件onHotplug
  • Display functions:其核心功能函数包括:

    • 输入layer的管理createLayer / destroyLayer
    • 叠加输出buffer设置setClientTarget / setOutputBuffer
    • 显示触发present
    • 设置vsync使能setVsyncEnabled
  • Layer functions:其核心功能函数包括:

    • 设置层的buffer setBuffer:
    • 设置层的属性 setBlendMode/setColor/setDataspace/setDisplayFrame(显示区域)/setPlaneAlpha/setSourceCrop/setZOrder
    • 设置层的sidband流 setSidebandStream
    • 设置叠加方式setCompositionType:Device表示硬件叠加,Client表示GPU叠加
//hwc2_device/hwc2_device.cpp

static hwc2_function_pointer_t HookDevGetFunction(struct hwc2_device * /*dev*/,
                                                  int32_t descriptor) {
  auto func = static_cast<HWC2::FunctionDescriptor>(descriptor);
  switch (func) {
    // Device functions
    ...
    case HWC2::FunctionDescriptor::RegisterCallback://注册回调,热插拔事件就是通过它回调上去的
      return ToHook<HWC2_PFN_REGISTER_CALLBACK>(
          DeviceHook<int32_t, decltype(&DrmHwcTwo::RegisterCallback),
                     &DrmHwcTwo::RegisterCallback, int32_t,
                     hwc2_callback_data_t, hwc2_function_pointer_t>);    
    // Display functions
    case HWC2::FunctionDescriptor::AcceptDisplayChanges:
      return ToHook<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
          DisplayHook<decltype(&HwcDisplay::AcceptDisplayChanges),
                      &HwcDisplay::AcceptDisplayChanges>);
    case HWC2::FunctionDescriptor::CreateLayer:
      return ToHook<HWC2_PFN_CREATE_LAYER>(
          DisplayHook<decltype(&HwcDisplay::CreateLayer),
                      &HwcDisplay::CreateLayer, hwc2_layer_t *>);
    case HWC2::FunctionDescriptor::DestroyLayer:
    ...
    // Layer functions
    case HWC2::FunctionDescriptor::SetCursorPosition:
      return ToHook<HWC2_PFN_SET_CURSOR_POSITION>(
          LayerHook<decltype(&HwcLayer::SetCursorPosition),
                    &HwcLayer::SetCursorPosition, int32_t, int32_t>);
    case HWC2::FunctionDescriptor::SetLayerBlendMode:
      return ToHook<HWC2_PFN_SET_LAYER_BLEND_MODE>(
          LayerHook<decltype(&HwcLayer::SetLayerBlendMode),
                    &HwcLayer::SetLayerBlendMode, int32_t>);
    case HWC2::FunctionDescriptor::SetLayerBuffer:
      return ToHook<HWC2_PFN_SET_LAYER_BUFFER>(
          LayerHook<decltype(&HwcLayer::SetLayerBuffer),
                    &HwcLayer::SetLayerBuffer, buffer_handle_t, int32_t>);
    ...
  }
}

在这里插入图片描述


2.4 DrmHwcTwo的构建和初始化

兄弟你为啥叫DrmHwcTwo而不是叫DrmHwc2呢!你到底是李鬼还是李逵,让人傻傻分不清楚啊!让我们看看DrmHwcTwo的构造究竟干了些啥!

//drm-hwcomposer/hwc2_device/DrmHwcTwo.h
class DrmHwcTwo : public PipelineToFrontendBindingInterface {
 public:
  DrmHwcTwo();
  ~DrmHwcTwo() override = default;

  std::pair<HWC2_PFN_HOTPLUG, hwc2_callback_data_t> hotplug_callback_{};
  std::pair<HWC2_PFN_VSYNC, hwc2_callback_data_t> vsync_callback_{};
#if PLATFORM_SDK_VERSION > 29
  std::pair<HWC2_PFN_VSYNC_2_4, hwc2_callback_data_t> vsync_2_4_callback_{};
  std::pair<HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED, hwc2_callback_data_t>
      period_timing_changed_callback_{};
#endif
  std::pair<HWC2_PFN_REFRESH, hwc2_callback_data_t> refresh_callback_{};

  // Device functions
  HWC2::Error CreateVirtualDisplay(uint32_t width, uint32_t height,
                                   int32_t *format, hwc2_display_t *display);
  HWC2::Error DestroyVirtualDisplay(hwc2_display_t display);
  void Dump(uint32_t *outSize, char *outBuffer);
  uint32_t GetMaxVirtualDisplayCount();
  HWC2::Error RegisterCallback(int32_t descriptor, hwc2_callback_data_t data,
                               hwc2_function_pointer_t function);

  auto GetDisplay(hwc2_display_t display_handle) {
    return displays_.count(display_handle) != 0
               ? displays_[display_handle].get()
               : nullptr;
  }

  auto &GetResMan() {
    return resource_manager_;
  }

  void ScheduleHotplugEvent(hwc2_display_t displayid, bool connected) {
    deferred_hotplug_events_[displayid] = connected;
  }

  // PipelineToFrontendBindingInterface
  bool BindDisplay(DrmDisplayPipeline *pipeline) override;
  bool UnbindDisplay(DrmDisplayPipeline *pipeline) override;
  void FinalizeDisplayBinding() override;

  void SendVsyncEventToClient(hwc2_display_t displayid, int64_t timestamp,
                              uint32_t vsync_period) const;
  void SendVsyncPeriodTimingChangedEventToClient(hwc2_display_t displayid,
                                                 int64_t timestamp) const;

 private:
  void SendHotplugEventToClient(hwc2_display_t displayid, bool connected);

  //ResourceManager是个非常重要的核心类,他应该管理着DRM的资源
  ResourceManager resource_manager_;// DrmHwcTwo类中的成员
  std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
  std::map<DrmDisplayPipeline *, hwc2_display_t> display_handles_;

  std::string mDumpString;

  std::map<hwc2_display_t, bool> deferred_hotplug_events_;
  std::vector<hwc2_display_t> displays_for_removal_list_;

  uint32_t last_display_handle_ = kPrimaryDisplay;
};


//drm-hwcomposer/hwc2_device/DrmHwcTwo.cpp
DrmHwcTwo::DrmHwcTwo() : resource_manager_(this){}; // DrmHwcTwo的构造函数定义

//hwc2_device/hwc2_device.cpp
struct Drmhwc2Device : hwc2_device {
  DrmHwcTwo drmhwctwo;
};

auto ctx = std::make_unique<Drmhwc2Device>();

DrmHwcTwo它是如此的潇洒,非常简单就是实例化了一个ResourceManager对象,然后将自己传递给了ResourceManager。


2.5 ResourceManager构造以及初始化流程

这里我们直接上代码,客官请看:

//drm/ResourceManager.cpp
ResourceManager::ResourceManager(
    PipelineToFrontendBindingInterface *p2f_bind_interface)
    : frontend_interface_(p2f_bind_interface) {
  //p2f_bind_interface指向DrmHwcTwo对象
  if (uevent_listener_.Init() != 0) {
    ALOGE("Can't initialize event listener");
  }
}

很简单,就是去实例化一个ResourceManager对象,其构造函数中处理初始化了uevent_listener等成员,也没啥了frontend_interface_指向DrmHwcTwo对象。到这里,是不是读者感觉到一脸懵逼,Resourceanager感觉啥也木有做啊,其实它是个非常重要的核心类,它管理着DRM的资源(对于libdrm编程熟悉的小伙伴,应该对于Resource肯定很熟悉了)。

那这里的ResourceManager::Init啥时候被调用呢!其实是在SurfaceFlinger的初始化过程时,设置callback给HWC,层层传递后就会调用到DrmHwcTwo::RegisterCallback进而调用到了 resource_manager_.Init();

//hwc2_device/hwc2_device.cpp
    case HWC2::FunctionDescriptor::RegisterCallback:
      return ToHook<HWC2_PFN_REGISTER_CALLBACK>(
          DeviceHook<int32_t, decltype(&DrmHwcTwo::RegisterCallback),
                     &DrmHwcTwo::RegisterCallback, int32_t,
                     hwc2_callback_data_t, hwc2_function_pointer_t>);
                     
//hwc2_device/DrmHwcTwo.cpp                   
HWC2::Error DrmHwcTwo::RegisterCallback(int32_t descriptor,
                                        hwc2_callback_data_t data,
                                        hwc2_function_pointer_t function) {
  switch (static_cast<HWC2::Callback>(descriptor)) {
    case HWC2::Callback::Hotplug: {
      hotplug_callback_ = std::make_pair(HWC2_PFN_HOTPLUG(function), data);
      if (function != nullptr) {
        //  ResourceManager resource_manager_;
        resource_manager_.Init();
      } else {
        resource_manager_.DeInit();
        /* Headless display may still be here, remove it */
        displays_.erase(kPrimaryDisplay);
      }
      break;
    }
    case HWC2::Callback::Refresh: {
      refresh_callback_ = std::make_pair(HWC2_PFN_REFRESH(function), data);
      break;
    }
    case HWC2::Callback::Vsync: {
      vsync_callback_ = std::make_pair(HWC2_PFN_VSYNC(function), data);
      break;
    }
#if PLATFORM_SDK_VERSION > 29
    case HWC2::Callback::Vsync_2_4: {
      vsync_2_4_callback_ = std::make_pair(HWC2_PFN_VSYNC_2_4(function), data);
      break;
    }
    case HWC2::Callback::VsyncPeriodTimingChanged: {
      period_timing_changed_callback_ = std::
          make_pair(HWC2_PFN_VSYNC_PERIOD_TIMING_CHANGED(function), data);
      break;
    }
#endif
    default:
      break;
  }
  return HWC2::Error::None;
}                     

我们看下ResourceManager::Init实现:

ResourceManager 初始化到底初始化了什么呢?

[drm-hwcomposer/drm/ResourceManager.cpp]
void ResourceManager::Init() {
  if (initialized_) {
    ALOGE("Already initialized"); // 已经初始化了,避免重复初始化
    return;
  }
  char path_pattern[PROPERTY_VALUE_MAX];
  // Could be a valid path or it can have at the end of it the wildcard %
  // which means that it will try open all devices until an error is met.
  int path_len = property_get("vendor.hwc.drm.device", path_pattern,
                              "/dev/dri/card%");
  if (path_pattern[path_len - 1] != '%') {
    AddDrmDevice(std::string(path_pattern));//详见章节2.6
  } else {
    path_pattern[path_len - 1] = '\0';
    for (int idx = 0;; ++idx) {
      std::ostringstream path;
      path << path_pattern << idx;
      struct stat buf {};
      if (stat(path.str().c_str(), &buf) != 0)
        break;
      if (DrmDevice::IsKMSDev(path.str().c_str())) {
        AddDrmDevice(path.str());
      }
    }
  }
    /**上面一大坨代码,简单理解就是找到DRM的设备节点,然后打开它,在我的设备上是/dev/dri/card0 */
    /** AddDrmDevice中去初始化DRM各种各样的资源 **/

  char scale_with_gpu[PROPERTY_VALUE_MAX];
  property_get("vendor.hwc.drm.scale_with_gpu", scale_with_gpu, "0");
  scale_with_gpu_ = bool(strncmp(scale_with_gpu, "0", 1));// 使用GPU缩放的标志
  if (BufferInfoGetter::GetInstance() == nullptr) {
    ALOGE("Failed to initialize BufferInfoGetter"); 
       // 初始化BufferInfoGetter,用于从Gralloc Mapper中获取buffer的属性信息
    return;
  }
  uevent_listener_.RegisterHotplugHandler([this] {// 注册热插拔的回调
    const std::lock_guard<std::mutex> lock(GetMainLock());
    UpdateFrontendDisplays();
  });
  //详见章节2.7
  UpdateFrontendDisplays();//这里会Send Hotplug Event To Client,SF会收到一次onComposerHalHotplug
                                                  // attached_pipelines_的初始化、更新
  initialized_ = true; // 设置标记,表明已经初始化过了
}

重点来看下AddDrmDevice:

AddDrmDevice

[drm-hwcomposer/drm/ResourceManager.cpp]
int ResourceManager::AddDrmDevice(const std::string &path) {
  auto drm = std::make_unique<DrmDevice>();//创建DrmDevice对象
  int ret = drm->Init(path.c_str());//初始化DrmDevice,path一般就是/dev/dri/card0
  drms_.push_back(std::move(drm));//保存到drms_中,便于后续的DeleteDrmDevices删除
  return ret;
}


2.6 DrmDevice的实现

一个重要的角色登场DrmDevice,我们可以理解它是对DRM设备进行抽象描述的一个类,用来后续的送显示,如下是其定义:

image

这里我们先看DrmDevice的实现,DrmDevice的构造函数中创建一个 DrmFbImporter 对象

[drm-hwcomposer/drm/DrmDevice.cpp]
DrmDevice::DrmDevice() {
  drm_fb_importer_ = std::make_unique<DrmFbImporter>(*this);
}

这里的DrmFbImporter后面会用到,用于后续DRM/KMS显示流程!

接下来我们继续往下看,看看DrmDevice::Init的实现逻辑,它主要完成了完成了获取DRM资源的初始化,CRTC、Encoder、Connector、Plane这些资源都获取到了!完美抽象出下面的框图!

image

//drm/DrmDevice.cpp
auto DrmDevice::Init(const char *path) -> int {
  /* TODO: Use drmOpenControl here instead */
  fd_ = UniqueFd(open(path, O_RDWR | O_CLOEXEC));//打开设备,一般是/dev/dri/card0
  if (!fd_) {//异常处理
    // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme
    ALOGE("Failed to open dri %s: %s", path, strerror(errno));
    return -ENODEV;
  }
  //通用设置  设置DRM_CLIENT_CAP_UNIVERSAL_PLANES,获取所有支持的Plane资源
  int ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
  if (ret != 0) {
    ALOGE("Failed to set universal plane cap %d", ret);
    return ret;
  }
  //通用设置 设置DRM_CLIENT_CAP_ATOMIC,告知DRM驱动该应用程序支持Atomic操作
  ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_ATOMIC, 1);
  if (ret != 0) {
    ALOGE("Failed to set atomic cap %d", ret);
    return ret;
  }

#ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS
  // 设置开启 writeback
  ret = drmSetClientCap(GetFd(), DRM_CLIENT_CAP_WRITEBACK_CONNECTORS, 1);
  if (ret != 0) {
    ALOGI("Failed to set writeback cap %d", ret);
  }
#endif

  uint64_t cap_value = 0;
  if (drmGetCap(GetFd(), DRM_CAP_ADDFB2_MODIFIERS, &cap_value) != 0) {
    ALOGW("drmGetCap failed. Fallback to no modifier support.");
    cap_value = 0;
  }
  HasAddFb2ModifiersSupport_ = cap_value != 0;//是否支持Add Fb2 Modifiers

  drmSetMaster(GetFd());
  if (drmIsMaster(GetFd()) == 0) {
    ALOGE("DRM/KMS master access required");
    return -EACCES;
  }
  //获取DrmModeRes
  auto res = MakeDrmModeResUnique(GetFd());
  if (!res) {
    ALOGE("Failed to get DrmDevice resources");
    return -ENODEV;
  }
  // 最小和最大的分辨率
  min_resolution_ = std::pair<uint32_t, uint32_t>(res->min_width,
                                                  res->min_height);
  max_resolution_ = std::pair<uint32_t, uint32_t>(res->max_width,
                                                  res->max_height);
 // 获取所有的CRTC,创建DrmCrtc对象,并加入crtcs_这个vector<unique_ptr<DrmCrtc>> 
  for (int i = 0; i < res->count_crtcs; ++i) {
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    auto crtc = DrmCrtc::CreateInstance(*this, res->crtcs[i], i);
    if (crtc) {
      crtcs_.emplace_back(std::move(crtc));
    }
  }
  //获取Encoder 建DrmEncoder对象,并加入encoders_这个vector<unique_ptr<DrmEncoder>>
  for (int i = 0; i < res->count_encoders; ++i) {
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    auto enc = DrmEncoder::CreateInstance(*this, res->encoders[i], i);
    if (enc) {
      encoders_.emplace_back(std::move(enc));
    }
  }
   // 获取所有的Connector,创建DrmConnector对象,并加入connectors_这个vector<unique_ptr<DrmConnector>>
  // 或放入writeback_connectors_这个vector中
  for (int i = 0; i < res->count_connectors; ++i) {
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    auto conn = DrmConnector::CreateInstance(*this, res->connectors[i], i);

    if (!conn) {
      continue;
    }

    if (conn->IsWriteback()) {
      writeback_connectors_.emplace_back(std::move(conn));
    } else {
      connectors_.emplace_back(std::move(conn));
    }
  }
  // 获取drmModePlaneRes
  auto plane_res = MakeDrmModePlaneResUnique(GetFd());
  if (!plane_res) {
    ALOGE("Failed to get plane resources");
    return -ENOENT;
  }
  // 获取所有的Plane,创建DrmPlane对象,并加入planes_这个vector<unique_ptr<DrmPlane>>
  for (uint32_t i = 0; i < plane_res->count_planes; ++i) {
    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
    auto plane = DrmPlane::CreateInstance(*this, plane_res->planes[i]);

    if (plane) {
      planes_.emplace_back(std::move(plane));
    }
  }

  return 0;
}

2.7 UpdateFrontendDisplays

让我们梦回大唐,错了让我们回到ResourceManager::Init()中,在最后的逻辑中调用了UpdateFrontendDisplays方法.

//drm/ResourceManager.cpp

auto ResourceManager::GetOrderedConnectors() -> std::vector<DrmConnector *> {
  /* Put internal displays first then external to
   * ensure Internal will take Primary slot
   */

  std::vector<DrmConnector *> ordered_connectors;

  for (auto &drm : drms_) {
    for (const auto &conn : drm->GetConnectors()) {
      // 判断当前连接器是否为内部连接器
      // 如果是内部连接器,则将其添加到ordered_connectors中
      if (conn->IsInternal()) {
        ordered_connectors.emplace_back(conn.get());
      }
    }
  }

  for (auto &drm : drms_) {
    for (const auto &conn : drm->GetConnectors()) {
      // 判断当前连接器是否为外部连接器
      // 如果是外部连接器,则将其添加到ordered_connectors中
      if (conn->IsExternal()) {
        ordered_connectors.emplace_back(conn.get());
      }
    }
  }

  return ordered_connectors;
}

void ResourceManager::UpdateFrontendDisplays() {
  //获取所有的连接器,并按照连接器的优先级进行排序  internal displays放前面,external放后面的排序connectors
  auto ordered_connectors = GetOrderedConnectors();

  for (auto *conn : ordered_connectors) {
    conn->UpdateModes();
    bool connected = conn->IsConnected();
    // std::map<DrmConnector *, std::unique_ptr<DrmDisplayPipeline>>attached_pipelines_;
    bool attached = attached_pipelines_.count(conn) != 0;// 判断map中是否存在key为conn的元素

    if (connected != attached) {
      ALOGI("%s connector %s", connected ? "Attaching" : "Detaching",
            conn->GetName().c_str());

      if (connected) {// connected==true and attached == false,
        // 说明当前连接器需要被绑定到frontend上
        // 创建一个DrmDisplayPipeline对象,并将其绑定到frontend_interface_上
        // 然后将该对象添加到attached_pipelines_中
        // 最后调用frontend_interface_的BindDisplay方法将该对象绑定到frontend上
        auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);
        //frontend_interface_指向DrmHwcTwo对象
        frontend_interface_->BindDisplay(pipeline.get());
        attached_pipelines_[conn] = std::move(pipeline);
      } else {// connected==false and attached == true,解除
        // 当前连接器与frontend的绑定关系
        // 首先从attached_pipelines_中移除该连接器
        // 然后调用frontend_interface_的UnbindDisplay方法解除绑定
        auto &pipeline = attached_pipelines_[conn];
        frontend_interface_->UnbindDisplay(pipeline.get());
        attached_pipelines_.erase(conn);
      }
    }
  }
  // 最后调用frontend_interface_的FinalizeDisplayBinding方法完成绑定操作
  frontend_interface_->FinalizeDisplayBinding();
}

我们接着继续看下DrmDisplayPipeline::CreatePipeline是如何构建DrmDisplayPipeline的,以及它DrmDisplayPipeline的定义!

//drm/DrmDisplayPipeline.h
/**
 * @brief 
 * 主要用于封装drm相关的组件,包括plane、encoder、crtc等
 * 1. 创建一个DrmDisplayPipeline对象
 * 2. 获取可用的planes
 * 3. 返回一个DrmDisplayPipeline对象
 */
struct DrmDisplayPipeline {
  static auto CreatePipeline(DrmConnector &connector)
      -> std::unique_ptr<DrmDisplayPipeline>;

  auto GetUsablePlanes()
      -> std::vector<std::shared_ptr<BindingOwner<DrmPlane>>>;

  DrmDevice *device;

  std::shared_ptr<BindingOwner<DrmConnector>> connector;
  std::shared_ptr<BindingOwner<DrmEncoder>> encoder;
  std::shared_ptr<BindingOwner<DrmCrtc>> crtc;
  std::shared_ptr<BindingOwner<DrmPlane>> primary_plane;

  std::unique_ptr<DrmAtomicStateManager> atomic_state_manager;
};

//drm/DrmDisplayPipeline.cpp
DrmDisplayPipeline::CreatePipeline
    TryCreatePipelineUsingEncoder
        TryCreatePipeline
   
static auto TryCreatePipeline(DrmDevice &dev, DrmConnector &connector,
                              DrmEncoder &enc, DrmCrtc &crtc)
    -> std::unique_ptr<DrmDisplayPipeline> {
  /* Check if resources are available */

  auto pipe = std::make_unique<DrmDisplayPipeline>();
  pipe->device = &dev;

  pipe->connector = connector.BindPipeline(pipe.get());
  pipe->encoder = enc.BindPipeline(pipe.get());
  pipe->crtc = crtc.BindPipeline(pipe.get());

  if (!pipe->connector || !pipe->encoder || !pipe->crtc) {
    return {};
  }            

这里的DrmDisplayPipeline,就是drm下kms显示通路的一个管道,将crtc,encoder,connector组合起来的一个类!


2.8 DrmHwcTwo如何处理HwcDisplay的构建

我们接着接续看下DrmHwcTwo是如何继续处理HwcDisplay,这其中牵涉到几个重要的成员和方法:

//hwc2_device/DrmHwcTwo.h
inline constexpr uint32_t kPrimaryDisplay = 0;   
  
class HwcDisplay {    
      uint32_t last_display_handle_ = kPrimaryDisplay;
      //typedef uint64_t hwc2_display_t;
      //typedef uint64_t hwc2_display_t;
      std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_;
      std::map<DrmDisplayPipeline *, hwc2_display_t> display_handles_;
    
      // PipelineToFrontendBindingInterface
      //创建HwcDisplay
      bool BindDisplay(DrmDisplayPipeline *pipeline) override;
      //销毁HwcDisplay
      bool UnbindDisplay(DrmDisplayPipeline *pipeline) override;
      //完成显示绑定,发送display插拔事件给SurfaceFlinger,告知SurfaceFlinger当前显示设备的状态
      void FinalizeDisplayBinding() override;
}

我们先看看BindDisplay和UnbindDisplay的实现!

//hwc2_device/DrmHwcTwo.cpp
bool DrmHwcTwo::BindDisplay(DrmDisplayPipeline *pipeline) {
  if (display_handles_.count(pipeline) != 0) {
    ALOGE("%s, pipeline is already used by another display, FIXME!!!: %p",
          __func__, pipeline);
    return false;
  }

  uint32_t disp_handle = kPrimaryDisplay;

  if (displays_.count(kPrimaryDisplay) != 0 &&
      !displays_[kPrimaryDisplay]->IsInHeadlessMode()) {
    disp_handle = ++last_display_handle_;
  }

  if (displays_.count(disp_handle) == 0) {
    /* Create a new HwcDisplay */
    auto disp = std::make_unique<HwcDisplay>(disp_handle,
                                             HWC2::DisplayType::Physical, this);
    //填充displays_容器
    displays_[disp_handle] = std::move(disp);
  }

  ALOGI("Attaching pipeline '%s' to the display #%d%s",
        pipeline->connector->Get()->GetName().c_str(), (int)disp_handle,
        disp_handle == kPrimaryDisplay ? " (Primary)" : "");
  //给HwcDisplay设置pipeline
  displays_[disp_handle]->SetPipeline(pipeline);
  //填充display_handles_容器
  display_handles_[pipeline] = disp_handle;

  return true;
}

bool DrmHwcTwo::UnbindDisplay(DrmDisplayPipeline *pipeline) {
  if (display_handles_.count(pipeline) == 0) {
    ALOGE("%s, can't find the display, pipeline: %p", __func__, pipeline);
    return false;
  }
  auto handle = display_handles_[pipeline];
  display_handles_.erase(pipeline);

  ALOGI("Detaching the pipeline '%s' from the display #%i%s",
        pipeline->connector->Get()->GetName().c_str(), (int)handle,
        handle == kPrimaryDisplay ? " (Primary)" : "");

  if (displays_.count(handle) == 0) {
    ALOGE("%s, can't find the display, handle: %" PRIu64, __func__, handle);
    return false;
  }
  displays_[handle]->SetPipeline(nullptr);

  /* We must defer display disposal and removal, since it may still have pending
   * HWC_API calls scheduled and waiting until ueventlistener thread releases
   * main lock, otherwise transaction may fail and SF may crash
   */
  if (handle != kPrimaryDisplay) {
    displays_for_removal_list_.emplace_back(handle);
  }
  return true;
}

上述的主要逻辑就是通过前面构建出来的DrmDisplayPipeline和新构建的HwcDisplay填充displays_和display_handles_容器。这里我们接着看下HwcDisplay的实现!

//hwc2_device/HwcDisplay.h
/**
 * @brief 
 * 这里的HwcDisplay是HWC2::Display在HAL层的实现,
 * 它负责管理一个Display的配置和状态,
 * 包括创建和销毁Layer,
 * 以及处理Display的配置和状态变化。
 * 
 * 它还负责处理Display的HWC Hooks,
 * 例如AcceptDisplayChanges、CreateLayer、DestroyLayer等。
 * 
 * 它还负责处理Display的VSync事件,
 * 例如处理VSync事件、发送VSync事件等。
 * 
 * 它还负责处理Display的HWC2::Error,
 * 例如处理HWC2::Error等。
 *
 */
class HwcDisplay {
    HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type, DrmHwcTwo *hwc2);
    
    /* SetPipeline should be carefully used only by DrmHwcTwo hotplug handlers */
   void SetPipeline(DrmDisplayPipeline *pipeline);
   
  HWC2::Error CreateComposition(AtomicCommitArgs &a_args);
  std::vector<HwcLayer *> GetOrderLayersByZPos();
  
  // HWC Hooks
  HWC2::Error AcceptDisplayChanges();
  HWC2::Error CreateLayer(hwc2_layer_t *layer);  

  const Backend *backend() const;
  void set_backend(std::unique_ptr<Backend> backend);  
}

这里要怎么理解这个HwcDisplay呢?这里的HwcDisplay是HWC2::Display在HAL层的实现,它的核心功能主要是:

  • 它负责管理一个Display的配置和状态,包括创建和销毁Layer,以及处理Display的配置和状态变化。
  • 它还负责处理Display的HWC Hooks,例如AcceptDisplayChanges、CreateLayer、DestroyLayer等。
  • 它还负责处理Display的VSync事件,例如处理VSync事件、发送VSync事件等。
  • 它还负责处理Display的HWC2::Error,例如处理HWC2::Error等。

我们接着继续看下HwcDisplay的构造,比较简单:

HwcDisplay::HwcDisplay(hwc2_display_t handle, HWC2::DisplayType type,
                       DrmHwcTwo *hwc2)
    : hwc2_(hwc2),//关联的DrmHwcTwo对象
      handle_(handle),//typedef uint64_t hwc2_display_t;   handle本质就是一个uint64_t整数值
      type_(type),// Physical 物理屏幕
      color_transform_hint_(HAL_COLOR_TRANSFORM_IDENTITY) {
    ...
}

接着继续来看下HwcDisplay::SetPipeline

void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {
  pipeline_ = pipeline;

  if (pipeline != nullptr) {//会进入这个分支
    ChosePreferredConfig();
    Init();//调用HwcDisplay::Init()逻辑

    hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);
  } else {
    ...
  }
}


HWC2::Error HwcDisplay::Init() {
  if (!IsInHeadlessMode()) {
    //通过后端管理为HwcDisplay设置后端,这个后端是干什么的呢  
    ret = BackendManager::GetInstance().SetBackendForDisplay(this);
    if (ret) {
      ALOGE("Failed to set backend for d=%d %d\n", int(handle_), ret);
      return HWC2::Error::BadDisplay;
    }
  }
}

这里又是后端管理BackendManager,又是后端Backend!要怎么理解呢?

既然有了backend,那么肯定有frontend,那么谁是backend ,谁是frontend? 扮演的角色功能分别是什么?

初步看起来貌似是:

  • frontend 对外提供调用的接口,外部使用者呼叫 front end 暴漏出的接口来呼叫某一功能;
  • backend 内部的实现逻辑,是前端接口功能的内部实现,是真正做事的地方;

太多了,太多了。完全放在一篇里面不够。今天先这样了,后续drm_hwcomposer另起一篇完成余下的相关分析!


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1713720.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

图像去雾并与其他非物理模型进行对比

matlab clear clc close all imgimread( scene1.jpg);subplot(221),imshow(uint8(img)), title(原始低照度图像”);img(::,1)255-img(::1); img(::,2)255-img(:2); img(:,:3)255-img(: 3); szsize(img); wsZ(2); hsz(1); %计算RGB取最小值后的图像darkl dark l zeros(h,w); for…

2024-2025年跨境电商展览会计划表:共筑未来跨境行业的繁荣

-----------------------------2024年跨境电商展计划如下---------------------------- 2024年&#xff0c;2025年国内跨境电商行业将迎来一系列重大的展会活动&#xff0c;是企业展示品牌、交流趋势、拓展商机的重要平台。全国各地展会排期信息现已出炉&#xff0c;记得收藏哦…

BGP路由策略实验

一、实验拓扑 二、IP分配(骨干) R1&#xff1a; 0/0/0 15.0.0.1 24 0/0/1 18.0.0.2 24 0/0/2 19.0.0.1 24 R2: 0/0/0 16.0.0.1 24 0/0/1 15.0.0.2 24 R3: 0/0/0 17.0.0.2 24 0/0/1 18.0.0.1 24 R4: 0/0/0 16.0…

【Paddle】稀疏计算的使用指南 稀疏ResNet的学习心得 (2) + Paddle3D应用实例稀疏 ResNet代码解读 (1.6w字超详细)

【Paddle】稀疏计算的使用指南 & 稀疏ResNet的学习心得 Paddle3D应用实例稀疏 ResNet代码解读 写在最前面一、稀疏格式简介1. COO&#xff08;Coordinate Format&#xff09;2. CSR&#xff08;Compressed Sparse Row Format&#xff09; 二、Paddle稀疏张量支持1. 创建 C…

34岁嵌入式开发工程师的出路在哪儿?

作为一个从事智能穿戴行业11年的资深从业者&#xff0c;您积累了丰富的技术和经验&#xff0c;IT行业内有很多发展机会和出路可以选择&#xff0c;以下是一些建议供参考&#xff1a;刚好我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「嵌入式的资料从专业入门到…

JUC从实战到源码:CompletableFuture详细学习

【JUC】- CompletableFuture详细学习 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f3c6; 博客首页 怒放吧德德 To记录领地 &#x1f31d;分享学习心得&#xf…

elementUI type=“selection“多选框选中 删除 回显 赋值问题 回显数组改变选中状态未改变

业务需求&#xff1a; 点击查询弹列表框 勾选列表选项保存 可删除可重新查询列表添加 遇到的问题&#xff1a;删除之后查询列表selection回显问题 解决&#xff1a;row-click配合:reserve-selection"true"使用 <el-tableref"refPlanTable":data"…

Java多线程(02)—— 线程等待,线程安全

一、如何终止线程 终止线程就是要让 run 方法尽快执行结束 1. 手动创建标志位 可以通过在代码中手动创建标志位的方式&#xff0c;来作为 run 方法的执行结束条件&#xff1b; public static void main(String[] args) throws InterruptedException {boolean flag true;Thr…

Ableton Live 11 Suite for Mac:音乐创作的全能伙伴

在数字音乐创作的广阔天地中&#xff0c;Ableton Live 11 Suite for Mac无疑是一颗璀璨的明星。作为一款专业的音乐制作软件&#xff0c;它集合了音频录制、编辑、混音、母带制作等全方位功能&#xff0c;为Mac用户提供了无与伦比的音乐创作体验。 Ableton Live 11 Suite拥有直…

这几个素材网站,是B站up主的剪辑素材宝藏库!

1.Videvo 这是一个提供完全免费的视频的网站&#xff0c;主要收集互联网免费的视频片段 网站目前收录了超过2700部高清短片&#xff0c;并且每周都会更新 2.电影预告片资源网——预告片世界 预告片世界是一个个人网站&#xff0c;为粉丝提供最新的高清电影预告片资源的在线观…

(4)医疗图像处理:MRI磁共振成像-成像技术--(杨正汉)

目录 一、特殊成像技术 1.水成像技术 2.化学位移成像技术 二、成像辅助技术 1.脂肪抑制技术 2.磁化转移技术 3.流动补偿技术 4.空间饱和空间标记技术 5.生理门控及导航回波技术 所有的这些技术最终就是为了使得K空间通过傅里叶变化之后得到的图片变的更为清晰。 一、…

全新PSAI设计插件 —— StartAI,让想象触手可及!

告别繁琐的设计过程&#xff0c;StartAI将为你的创作注入新动力&#xff0c;让每一个设计瞬间变得生动而独特。 核心功能介绍&#xff1a; 高清修复 - 每一个设计细节都至关重要&#xff0c;StartAI的高清修复可以细节优化&#xff0c;确保你的设计完美无瑕。 百变生图风格- 从…

linux安装mysql后,配置mysql,并连接navicat软件

Xshell连接登陆服务器 输入全局命令 mysql -u root -p 回车后&#xff0c;输入密码&#xff0c;不显示输入的密码 注意mysql服务状态&#xff0c;是否运行等 修改配置文件my.cnf&#xff0c;这里没找到就找my.ini&#xff0c;指定有一个是对的 find / -name my.cnf 接下…

小心你的小程序被清退!小程序备案全流程攻略

小心你的小程序被清退&#xff01;小程序备案全流程攻略 前言&#xff1a; 接微信官方通知&#xff0c;2023年9月1日后微信小程序必须完成备案才可上架&#xff01;受微信官方调整影响&#xff0c;所有已使用或计划授权微信小程序使用的用户均要求备案后上架产品。 【微信小程…

STM32 OTA需要注意问题

一、OTA设计思路&#xff08;问题&#xff09; 1、根据stm32f405 flash分布&#xff0c;最初将flash划分为四个区域&#xff0c;分别是Bootloader、APP1、APP2、参数区&#xff0c;设备上电后&#xff0c;进入Bootloader程序&#xff0c;判断OTA参数&#xff0c;根据参数来确定…

【YashanDB知识库】自动选举配置错误引发的一系列问题

问题现象 问题出现的步骤/操作&#xff1a; ● 配置自动选举&#xff0c;数据库备库手动发起switch over&#xff0c;命令会报错 ● 主、备库变为只读状态&#xff0c;数据库无法进行读写操作 ● shutdown immediate 停止数据库&#xff0c;此时发现数据库一直没有退出&…

设计以容错:应对失败的12种关键设计思想

"Design for Failure" 这一说法在产品设计、软件开发和系统架构中并不常见&#xff0c;因为它通常与追求成功和可靠性的目标相悖。然而&#xff0c;如果我们从另一个角度来理解它&#xff0c;即“设计以应对失败”或“设计以容错”&#xff0c;那么以下是12种常见的设…

24V_2A_1.2MHZ|PCD0303升压恒频LCD背光源专用电路超小体积封装

概述 PCD0303是一个恒定频率&#xff0c;6针SOT23电流模式升压转换器用于小型低功耗应用。PCD0303 以1.2MHz切换&#xff0c;并且允许使用微小的&#xff0c;低成本电容器和电感器2mm或更小,内部软启动会产生较小的涌入电流延长电池寿命。PCD0303具有自动切换至轻负载下的脉冲…

社交媒体数据恢复:子弹短信

在开始之前&#xff0c;请确保满足以下条件&#xff1a; 您的手机已root。您已知晓备份子弹短信的方法。 以下是子弹短信数据恢复的步骤&#xff1a; 第一步&#xff1a;备份子弹短信 如果您尚未备份子弹短信&#xff0c;请先进行备份。备份方法如下&#xff1a; 进入子弹短…

多用户协作与实时渲染:3D开发工具HOOPS助力汽车行业CAD可视化

在当今汽车行业&#xff0c;计算机辅助设计&#xff08;CAD&#xff09;可视化是产品设计和开发过程中不可或缺的一环。随着汽车设计复杂性的增加&#xff0c;CAD可视化不仅仅是一个设计工具&#xff0c;更是一个沟通和协作的平台。然而&#xff0c;尽管技术不断进步&#xff0…