11

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

 2 years ago
source link: https://www.cnblogs.com/roger-yu/p/16425520.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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;
};

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

979092-20220705172959510-864910706.jpg

本文作者@二的次方  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] = '\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; // 设置标记,表明已经初始化过了
}

重点看几个函数

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,如下其定义

979092-20220705174449994-680699767.png

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 %d\n", 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数据给他

979092-20220705175225786-723381886.png


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


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK