Android 12(S) 图像显示系统 – drm_hwcomposer 简析(上)


必读:

Android 12(S) 图像显示系统 - 开篇


 

前言

Android源码中有包含drm_hwcomposer:/external/drm_hwcomposer/

drm_hwcomposer 这个过程下的代码架构变化还是很频繁的,我这里分析直接去 drm_hwcomposer 的官方地址抓取最新的code来做分析了

 

解析

这个工程编译后会产生 shared library :/vendor/lib/hw/hwcomposer.drm.so

drm_hwcomposer作为一个HAL module,其写作实现还是遵循了旧有的Android HAL Module的接口实现规则。

 

看看一些结构体的定义以及他们之间的关系:

结构体hw_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_t的定义

[/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;

结构体DrmHwc2Device的定义

[drm-hwcomposer/hwc2_device/hwc2_device.cpp]  struct Drmhwc2Device : hwc2_device {     DrmHwcTwo drmhwctwo; };

按照结构体定义的理解,我们可以认为三个类型,具有如下继承关系

Android 12(S) 图像显示系统 - 	drm_hwcomposer 简析(上)

本文作者@二的次方  2022-07-05 发布于博客园

看一个关键的static方法 HookDevOpen,该方法中会去实例化一个Drmhwc2Device对象,其中去创建了一个DrmHwcTwo对象

[drm-hwcomposer/hwc2_device/hwc2_device.cpp] static int HookDevOpen(const struct hw_module_t *module, const char *name,                        struct hw_device_t **dev) {   ...   auto ctx = std::make_unique<Drmhwc2Device>();   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;    *dev = &ctx.release()->common;    return 0; }

在HWC HAL Service启动时,初始化阶段openDeviceWithAdapter中去调用了open函数,就是call到了HookDevOpen可以参见:

/hardware/interfaces/graphics/composer/2.1/utils/passthrough/include/composer-passthrough/2.1/HwcLoader.h

 

DrmHwcTwo构造时做了什么工作?

[drm-hwcomposer/hwc2_device/DrmHwcTwo.cpp] DrmHwcTwo::DrmHwcTwo() : resource_manager_(this){}; // DrmHwcTwo的构造函数定义  [drm-hwcomposer/hwc2_device/DrmHwcTwo.h] ResourceManager resource_manager_; // DrmHwcTwo类中的成员

很简单,就是去实例化一个ResourceManager对象,其构造函数中处理初始化了uevent_listener等成员,也没啥了
frontend_interface_指向DrmHwcTwo对象

[drm-hwcomposer/drm/ResourceManager.cpp] ResourceManager::ResourceManager(     PipelineToFrontendBindingInterface *p2f_bind_interface)     : frontend_interface_(p2f_bind_interface) {   if (uevent_listener_.Init() != 0) {     ALOGE("Can't initialize event listener");   } }

 

到这里,我大概可以看到ResourceManager是个非常重要的核心类,他应该管理着DRM的资源。
他的定义中也定义了void Init();函数,那这个初始化函数是什么时候调用的呢? 

 

 在这篇博文中:Android 12(S) 图像显示系统 - SurfaceFlinger的启动和消息队列处理机制(四)
讲解SurfaceFlinger的初始化过程时,设置callback给HWC,层层传递后就会调用到DrmHwcTwo::RegisterCallback
进而调用到了 resource_manager_.Init();

 

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

 本文作者@二的次方  2022-07-05 发布于博客园

 

[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));   } else {     path_pattern[path_len - 1] = '';     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();   });   UpdateFrontendDisplays();//这里会Send Hotplug Event To Client,SF会收到一次onComposerHalHotplug                                                   // attached_pipelines_的初始化、更新   initialized_ = true; // 设置标记,表明已经初始化过了 }

重点看几个函数

 

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_这个vector中     return ret; }

一个重要的角色登场:DrmDevice,如下其定义

Android 12(S) 图像显示系统 - 	drm_hwcomposer 简析(上)

 

DrmDevice的构造函数中创建一个 DrmFbImporter 对象

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

 

DrmDevice::Init
完成了获取DRM资源的初始化,CRTC、Encoder、Connector、Plane这些资源都获取到了 

 

[drm-hwcomposer/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;     }     // 设置开启 writeback #ifdef DRM_CLIENT_CAP_WRITEBACK_CONNECTORS     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     // 设置master mode     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;         }         // wirteback如何理解?         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; }

 

 回到ResourceManager::Init()中,最后调用了一次UpdateFrontendDisplays()

 

[drm-hwcomposer/drm/ResourceManager.cpp] void ResourceManager::UpdateFrontendDisplays() {     // internal displays放前面,external放后面的排序connectors     auto ordered_connectors = GetOrderedConnectors();     for (auto *conn : ordered_connectors) {         conn->UpdateModes();         bool connected = conn->IsConnected();         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,绑定资源                 auto pipeline = DrmDisplayPipeline::CreatePipeline(*conn);                 if (pipeline) {                     //frontend_interface_指向DrmHwcTwo对象                     frontend_interface_->BindDisplay(pipeline.get());                     attached_pipelines_[conn] = std::move(pipeline);//存入map                 }             } else { // connected==false and attached == true,解绑资源                 auto &pipeline = attached_pipelines_[conn];                 frontend_interface_->UnbindDisplay(pipeline.get());                 attached_pipelines_.erase(conn);// map中删除             }         }     }     frontend_interface_->FinalizeDisplayBinding(); }

 


DrmHwcTwo中的两个成员: 

[drm-hwcomposer/hwc2_device/DrmHwcTwo.h]    std::map<hwc2_display_t, std::unique_ptr<HwcDisplay>> displays_; std::map<DrmDisplayPipeline *, hwc2_display_t> display_handles_;

 

出现了三个函数:
DrmHwcTwo::BindDisplay
主要是创建HwcDisplay,
DrmHwcTwo::UnbindDisplay
删除HwcDisplay
DrmHwcTwo::FinalizeDisplayBinding
完成显示绑定,大概看是Creating null-display for headless mode , send hotplug events to the client,displays_for_removal_list_

本文作者@二的次方  2022-07-05 发布于博客园

重点看一看创建HwcDisplay和SetPipeline做了啥子吧

HwcDisplay的构造函数很简单,就是初始化一些成员

[drm-hwcomposer/hwc2_device/HwcDisplay.cpp] 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) {   // clang-format off   color_transform_matrix_ = {1.0, 0.0, 0.0, 0.0,                              0.0, 1.0, 0.0, 0.0,                              0.0, 0.0, 1.0, 0.0,                              0.0, 0.0, 0.0, 1.0};   // clang-format on }

HwcDisplay::SetPipeline

[drm-hwcomposer/hwc2_device/HwcDisplay.cpp] void HwcDisplay::SetPipeline(DrmDisplayPipeline *pipeline) {     Deinit();      pipeline_ = pipeline;     if (pipeline != nullptr || handle_ == kPrimaryDisplay) {         Init(); // 初始化         hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ true);     } else {         hwc2_->ScheduleHotplugEvent(handle_, /*connected = */ false);     } }

 

再看HwcDisplay::Init

[drm-hwcomposer/hwc2_device/HwcDisplay.cpp] HWC2::Error HwcDisplay::Init() {     ChosePreferredConfig(); //选择一个最佳的config,然后SetActiveConfig     // VSYNC相关的代码省略不看      if (!IsInHeadlessMode()) {//设置后端 backend         ret = BackendManager::GetInstance().SetBackendForDisplay(this);         if (ret) {             ALOGE("Failed to set backend for d=%d %dn", int(handle_), ret);             return HWC2::Error::BadDisplay;         }     }      client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);      return HWC2::Error::None; }

 

又出现了新的名词: Backend

谁是 front end ? 谁是back end ?  扮演的角色功能分别是什么? 

初步看起来貌似是:
front end 对外提供调用的接口,外部使用者呼叫 front end 暴漏出的接口来呼叫某一功能;
back end 内部的实现逻辑,是前端接口功能的内部实现,是真正做事的地方;

本文作者@二的次方  2022-07-05 发布于博客园

HwcDisplay类中有成员  == HwcLayer client_layer_,有个疑问 这个client layer 是如何与SF中的GPU合成的图层关联起来的?

他是一个特例,特殊的专门的的layer,转用于处理显示 CLIENT -- GPU 合成的 buffer,  SetClientTarget传递buffer数据给他

Android 12(S) 图像显示系统 - 	drm_hwcomposer 简析(上)

 

小结


以上内容,主要讲述分析的是开机阶段,DRM HWC的初始化的一些流程。大概就是获取DRM的资源,创建并初始化必要模块。

 

发表评论

评论已关闭。

相关文章