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


    🚀 优质资源分享 🚀

    学习路线指引(点击解锁)知识定位人群定位
    🧡 Python实战微信订餐小程序 🧡进阶级本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
    💛Python量化交易实战💛入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

    必读:

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结构体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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    结构体DrmHwc2Device的定义

    [drm-hwcomposer/hwc2_device/hwc2_device.cpp]
    
    struct Drmhwc2Device : hwc2\_device {
        DrmHwcTwo drmhwctwo;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    本文作者@二的次方  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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在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类中的成员
    
    • 1
    • 2
    • 3
    • 4
    • 5

    很简单,就是去实例化一个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");
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    **到这里,我大概可以看到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] = '\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();
      });
      UpdateFrontendDisplays();//这里会Send Hotplug Event To Client,SF会收到一次onComposerHalHotplug
                                                      // attached\_pipelines\_的初始化、更新
      initialized_ = true; // 设置标记,表明已经初始化过了
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    重点看几个函数

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

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

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

    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>
        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> 
        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>
           // 或放入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> 
        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;
    }折叠 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98

    回到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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27


    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_;
    
    • 1
    • 2
    • 3
    • 4

    **出现了三个函数:**DrmHwcTwo::BindDisplay主要是创建HwcDisplay,DrmHwcTwo::UnbindDisplay删除HwcDisplayDrmHwcTwo::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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    再看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 %d\n", int(handle_), ret);
                return HWC2::Error::BadDisplay;
            }
        }
    
        client_layer_.SetLayerBlendMode(HWC2_BLEND_MODE_PREMULTIPLIED);
    
        return HWC2::Error::None;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    又出现了新的名词: 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数据给他

    小结


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

  • 相关阅读:
    Servlet入门
    虹科示波器 | 汽车免拆检修 | 2012 款上汽大众帕萨特车 发动机偶尔无法起动
    在不安全的集群上启用 Elasticsearch Xpack 安全性
    HBase集群部署与基础命令
    WPF 如何让xmal的属性换行显示 格式化
    【正点原子STM32连载】第十章 STM32CubeMX简介 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1
    PyTorch基础知识学习
    在家中访问一个网站的思考
    Python中prettytable库
    ARM & Linux 基础学习 / Ubuntu 下的包管理 / apt工具
  • 原文地址:https://blog.csdn.net/pythonxxoo/article/details/125631550