? 优质资源分享 ?
学习路线指引(点击解锁) | 知识定位 | 人群定位 |
---|---|---|
? 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;
结构体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;
};
按照结构体定义的理解,我们可以认为三个类型,具有如下继承关系
本文作者@二的次方 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,如下其定义
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>
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;
}折叠
回到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删除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
}
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数据给他
小结
以上内容,主要讲述分析的是开机阶段,DRM HWC的初始化的一些流程。大概就是获取DRM的资源,创建并初始化必要模块。