本文档主要讲解在OpenHarmony中,硬件合成适配的方法及原理说明。
环境说明:
? 要理解什么是合成,合成做了什么?我们先通过分解设置界面来回答这个问题:
在设置界面中,一帧完整的图像是由4个部分构成的,每一个部分我们称之为一个layer。
layer(图层)是图形合成中最重要的单元,一个layer对应一个buffer及显示参数。一帧图像由一个或多个layer组成,每个layer单独负责一块区域的内容刷新,大大提升了渲染及显示效率。比如:我们把鼠标的显示单独设置成一个Layer,鼠标的移动,只需要更改layer的显示坐标,不需要重复渲染背景显示区域的数据等。
在设置界面中,4个layer分别是背景层、应用层、状态栏和工具栏。合成就是把这些layer组合在一起,最终变成一帧完整的图像。
我们可以通过如下命令获取当前界面的layers信息:
hidumper -s 10 -a surface
对当前界面截屏
snapshot_display -f /data/snapshot_display.jpeg
我们可以看到,layer2和layer3背景显示为黑色,与实际效果有较大区别。要理解这个差异的原因,我们需要要知道合成做了什么。
从前面的介绍我们知道,合成就是把多个layer合成了一帧图像。那这个合成的过程中,主要处理了哪些事?总结如下:
颜色混合。包含透明度处理、背景填充、阴影处理等。
编码格式转换。支持RGB565、RGB888、ARGB888、YUV420_2P等
缩放处理。支持1/16~24倍率缩放
输入/输出旋转。
不同的硬件支持的能力有差别,最基本的能力需要支持透明度处理及编码转换。
上面layer背景显示黑色的原因,是因为背景的RGBA值都是0,RGB 值为0,显示黑色。Alpha值为0,为全透明。如果给他们添加一个背景图层,那图层就会显示成背景的颜色值。
理解了合成,我们再看看合成模块在OpenHarmony系统进程中的位置。
图像合成在OpenHarmony进程示意图,以便了解合成模块的生命周期及运行逻辑:
如上图所示,合成模块代码由虚框标记,运行在render_service进程中。硬件适配主要是适配display_device及display_gfx模块。
display_device: 为composer提供接口及适配
display_gfx:包含具体硬件sensor的功能实现。
重启render_service服务,Dispaly HDI服务就会重启。
OpenHarmony中合成方式有以下几种:
以上合成方式在相同layers数量下,xx平台性能对比如下:
类型 | CPU | GPU | GFX | DRM |
---|---|---|---|---|
合成时间(ms) | >80ms | 12.07ms | 11.38ms | 7.5ms |
从合成性能看,drm性能最佳,减少了内存复制开销。GFX与GPU性能相差不多,但能完成一些drm无法完成的合成场景。CPU最差,只有适配早期,其它硬件没有调试好时,临时使用。
适配硬件合成前,我们先要理清代码的运行逻辑,并且知道适配需要做什么,去哪里修改。以下通过流程图来展示代码的运行逻辑和位置。
当Layers准备好后,进入composer模块的repaint()处理。流程如下:
Layer合成方式选择示例:
当前合成方式并没有使用GPU合成,是否使用,可根据其它硬件能力来选择。一般情况下,为了减轻GPU负担,尽量使用其它硬件来完成合成操作。
每个硬件支持能力不同,比如:支持的layer数量,是否支持缩放时旋转,缩放倍率等。
合成方式的选择要结合具体的硬件来调整。硬件详细能力请查阅相关芯片手册。
注意事项:
如果GSP列表非空,那clientLayer作为GSP的合成结果,会占用DPU的plane0.
由于Layer图层是有顺序的,所以连续的图层会选择同一种硬件合成。
比如:DPU只支持4个图层,如果总图层有6个,那前面3个将使用GSP合成结果到clientLayer,再与后面的3个图层一起,共4个layer给DPU合成送显。
代码示例:
int32_t HdiGfxComposition::SetLayers(std::vector<HdiLayer *> &layers, HdiLayer &clientLayer)
{
……
HdiLayer *layer;
uint32_t dpuSize = 0;
for (uint32_t i = 0; i < layers.size(); i++) {
layer = layers[i];
if (CanHandle(*layer)) {
if ((layer->GetCompositionType() != COMPOSITION_VIDEO) &&
(layer->GetCompositionType() != COMPOSITION_CURSOR)) {
if((mask == 0) && (layers.size() < 4)) {//直接给DPU处理
layer->SetAcceleratorType(ACCELERATOR_DPU);
……
} else {
//GSP+DPU
int32_t tempMask = CheckLayers(layers, i);// 判断剩下的layers DPU是否支持
uint32_t tempSize = layers.size() - i;
if(tempMask) {//复杂场景交给GSP
layer->SetAcceleratorType(ACCELERATOR_GSP);
……
} else {
if((dpuSize + tempSize) < 5) {//dpu支持6个layer,先只使用4个
layer->SetAcceleratorType(ACCELERATOR_DPU);
……
} else {
layer->SetAcceleratorType(ACCELERATOR_GSP);
……
}
}
}
} else {
layer->SetDeviceSelect(layer->GetCompositionType());
}
mCompLayers.push_back(layer);
} else { //GPU
layer->SetDeviceSelect(COMPOSITION_CLIENT);
……
}
}
……
}
hello_composer在3.2-Release中默认没有参与编译,修改如下:
foundation/graphic/graphic_2d/bundle.json
--- a/bundle.json
+++ b/bundle.json
@@ -61,6 +61,7 @@
"//foundation/graphic/graphic_2d/rosen/modules/2d_graphics:2d_graphics",
"//foundation/graphic/graphic_2d/rosen/samples/2d_graphics:drawing_sample_rs",
+ "//foundation/graphic/graphic_2d/rosen/samples/composer:hello_composer",
"//foundation/graphic/graphic_2d/rosen/samples/2d_graphics:drawing_engine_sample",
在第一次运行hello_composer前,需要先把render_service服务停止。
service_control stop render_service
执行hello_composer
cd /system/bin
./hello_composer
测试分以下几个点进行:
void HelloComposer::InitLayers(uint32_t screenId)
{
……
// status bar
drawLayers.emplace_back(std::make_unique<LayerContext>(
IRect { 0, 0, displayWidth, statusHeight },
IRect { 0, 0, displayWidth, statusHeight },
3, LayerType::LAYER_STATUS));
……
}
默认是4个图层,可以根据实际测试情况,添加、删除layers的信息。
drawLayers.emplace_back(std::make_unique<LayerContext>(
IRect { layerPositionX, layerPositionY, 200, 400},
IRect { 0, 0, 100, 200},
1, LayerType::LAYER_EXTRA));
修改为true后,LayerType::LAYER_EXTRA 图层会周期旋转。
bool testYUV_ = true;
通过修改目的图层的大小,来达到缩放测试的目的
bool testYUV_ = true;
修改为true后,LayerType::LAYER_EXTRA图层会以yuv格式合成。
const std::vector<uint32_t> colors_ = {0xff0000ff, 0xffff00ff, 0xaa00ff00, 0xff00ffaa, 0xff0f0f00};
修改colors_最高8位值,可以测试透明度。0x00:全透明 0xFF:不透明
合成消耗了多少时间,帧率的统计都可以使用抓trace来分析。
trace命令:
hdc shell bytrace -t 5 --overwrite app graphic > mytrace.ftrace
帧率统计:
帧率首先由vsync频率决定,当合成总时间大于vsync间隔时,会影响帧率,并需要进行优化。合成计算帧率就是统计1s内合成帧的个数。
合成时间统计:
以上标记的时间就是实际硬件合成的时间,在commit方法中执行。我们从前面两个图片可看出,他们的合成间隔是有明显区别的,赵成这个现象的原因是同步及异步设置导致。
当我们的操作需要使用其它硬件资源执行时,就涉及到同步的方式问题。总结如下:
同步执行
调用硬件接口后,需要等待硬件所有指令执行完成。libdrm接口中示例如下:
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET | DRM_MODE_ATOMIC_NONBLOCK;//去掉DRM_MODE_ATOMIC_NONBLOCK代表同步执行
ret = drmModeAtomicCommit(drmFd, atomicReqPtr.Get(), flags, nullptr);
异步执行
异步在图形中常用的就是fence机制。fence机制框架由内核提供,当硬件完成时,会修改fence的状态。常用的如AcqureFenceFd、ReleaseFenceFd。
AcqureFenceFd 由GPU提供,标记渲染结果。
ReleaseFenceFd 由drm crtc提供,标记送显结果。
例如 ReleaseFenceFd:
ret = drmModeAtomicAddProperty(atomicReqPtr.Get(), mCrtc->GetId(), mCrtc->GetOutFencePropId(),
(uint64_t)&crtcOutFence);
……
layer->SetReleaseFence(dup(crtcOutFence));
fence机制,让CPU在硬件工作时,释放生产力,继续执行与当前操作无关代码,把流程继续向前推进。当再次需要执行与当前硬件相关的操作时,再检查fence完成状态或等待。在整个周期中,大大增加了代码执行效率。
实际显示效果状态栏和工具栏为黑色。这个一般是透明度没有处理好。修改drm blend_mode可以解决。
drmModeAtomicAddProperty(pset, drmPlane.GetId(), drmPlane.property_blend_mode, 0);//0-2.具体类型可以使用modetest查看
如果硬件没有报错,那大概率是ReleaseFence没有同步。buffer还没有使用完成,又对buffer进行了操作。
layer->SetReleaseFence(dup(crtcOutFence));//step1: 检查ReleaseFence是否设置
currSbuffer_->releaseFence_ = Merge(currSbuffer_->releaseFence_, layerReleaseFence);//step2: 检查ReleaseFece是否有合并
这种一般只有在低端GPU上才会出现。原因是AcqureFence没有同步,使用了未准备好的渲染结果。增加对fence的等待:
if(layer->GetAcquireFenceFd() > 0) {
sync_wait(layer->GetAcquireFenceFd(), 100);
}
主要有以下几种可能。
zorder顺序不对,被其它图层覆盖。
layer内容为空。显示成了背景填充色0
超出硬件支持的图层上限,需要增加循环合成处理
在模块开发过程中,如果我们对layer的数据不确定时,可以把layer的数据dumper出来。
setenforce 0
param set rosen.afbc.enabled 0
//start
touch /data/bq_dump
//end
rm /data/bq_dump
数据生成在/data目录下。文件可以使用yuvplayer.exe工具查看,它支持yuv、rgb等不同的格式类型及分辨率大小。
为了能让大家更好的学习鸿蒙 (Harmony OS) 开发技术,这边特意整理了《鸿蒙 (Harmony OS)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
https://qr21.cn/FV7h05
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……