标准系统xts认证HatszHdfDisplayComposerUtTest用例测试失败分析
## 标准系统xts认证HatszHdfDisplayComposerUtTest用例测试失败分析### 关键字 xts;hats; display### 问题描述 系统版本:OpenHarmony 4.1 Release代码版本:OpenHarmony v4.1 Release问题现象:xts 在执行HatszHdfDisplayCompo
标准系统xts认证HatszHdfDisplayComposerUtTest用例测试失败分析
关键字
xts;hats; display
问题描述
系统版本:OpenHarmony 4.1 Release
代码版本:OpenHarmony v4.1 Release
问题现象:xts 在执行HatszHdfDisplayComposerUtTest测试套件中有2个用例不过 SUB_Driver_Display_HDI_6600 SUB_Driver_Display_HDI_6500
问题原因
用例函数调用关系如图:
正常机制
用例的核心流程如上图,当执行commit 提交操作前会先判断是否有图层刷新,当有图层刷新时会将clientLayer置为黑色,同时将clientLayer设置为合成后数据保存的layer
异常机制
部分合成方式比如DPU直接在drm驱动中合成送显示,不会产生中间合成buffer。
解决方案
用例前添加注释,测试前注意Display HDI 适配图层的合成方式,例如展锐DPU合成无clientLayer 接受数据,可忽略此用例
定位过程
如下代码示例这两个用例失败地方都是在送显Buffer与合成后的Buffer进行像素点颜色异常比较异常导致
int32_t HdiCompositionCheck::Check(const std::vector<LayerSettings> &layers,
const BufferHandle& clientBuffer, uint32_t checkType) const
{
int ret = DISPLAY_SUCCESS;
const int MID_POS = 2;
// get the all check point
std::vector<Point> points;
for (auto layer : layers) {
const IRect& RECT = layer.displayRect;
if (checkType == CHECK_VERTEX) {
GetCheckPoints({RECT.x, RECT.y}, points);
GetCheckPoints({RECT.x, RECT.y + RECT.h}, points);
GetCheckPoints({RECT.x + RECT.w, RECT.y}, points);
GetCheckPoints({RECT.x + RECT.w, RECT.y + RECT.h}, points);
} else {
GetCheckPoints({RECT.x + RECT.w / MID_POS, RECT.y + RECT.h / MID_POS}, points); // center point
}
}
// get all the check color
std::vector<uint32_t> colors = GetCheckColors(layers, points);
DISPLAY_TEST_CHK_RETURN((colors.size() != points.size()), DISPLAY_FAILURE,
DISPLAY_TEST_LOGE("Points and colors don't match"));
for (uint32_t i = 0; i < points.size(); i++) {
if ((points[i].x >= clientBuffer.width) || (points[i].x < 0) || (points[i].y < 0) ||
(points[i].y >= clientBuffer.height)) {
continue;
}
ret = CheckPixel(clientBuffer, points[i].x, points[i].y, colors[i]);
if (ret != DISPLAY_SUCCESS) {
DISPLAY_TEST_LOGE("check failed");
break;
}
}
return ret;
}
猜测可能出现的情况:
- 绘制异常导致
- 比较异常导致
- 合成异常导致
下面我们来逐一分析
- 绘制异常导致: 分析代码可以看出在生成Layer图层时进行了颜色的填充,没有进行GPU绘制动作,可以通过保存layer 数据来检查绘制是否正常。
static std::shared_ptr<HdiTestLayer> CreateTestLayer(LayerSettings setting, uint32_t zorder)
{
int ret;
HdiTestDevice::GetInstance();
DISPLAY_TEST_LOGD("color 0x%x", setting.color);
std::shared_ptr<HdiTestDisplay> display = HdiTestDevice::GetInstance().GetFirstDisplay();
DISPLAY_TEST_CHK_RETURN((display == nullptr), nullptr, DISPLAY_TEST_LOGE("can not get display"));
std::shared_ptr<HdiTestLayer> layer = display->CreateHdiTestLayer(setting.bufferSize.w, setting.bufferSize.h);
DISPLAY_TEST_CHK_RETURN((layer == nullptr), nullptr, DISPLAY_TEST_LOGE("can not create hdi test layer"));
............
............
HdiGrallocBuffer* handle = layer->GetFrontBuffer();
DISPLAY_TEST_CHK_RETURN((handle == nullptr), nullptr, DISPLAY_TEST_LOGE("can not get front buffer"));
ClearColor(*(handle->Get()), setting.color);
ret = layer->SwapFrontToBackQ();
DISPLAY_TEST_CHK_RETURN((ret != DISPLAY_SUCCESS), nullptr, DISPLAY_TEST_LOGE("SwapFrontToBackQ failed"));
layer->SetZorder(zorder);
layer->SetBlendType(setting.blendType);
layer->SetTransform(setting.rotate);
return layer;
}
送显前需要刷新layer列表可以在此处遍历layers 保存合成前layer 的数据信息
int32_t HdiTestLayer::PreparePresent()
{
............
............
HdiGrallocBuffer* buffer = AcquireBackBuffer();
DISPLAY_TEST_CHK_RETURN((buffer == nullptr), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("can not get back buffer"));
BufferHandle* handle = buffer->Get();
DISPLAY_TEST_CHK_RETURN((handle == nullptr), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("BufferHandle is null"));
// 将要合成的layer 数据保存到文件中
SaveFile("/data/PreparePresent", static_cast<uint8_t *>(handle.virAddr), handle.size);
IRect tmp {0, 0, handle->width, handle->height};
std::vector<IRect> vRects;
vRects.push_back(tmp);
ret = HdiTestDevice::GetInstance().GetDeviceInterface()->SetLayerVisibleRegion(displayID_, id_, vRects);
DISPLAY_TEST_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE,
DISPLAY_TEST_LOGE("SetLayerVisibleRegion failed"));
............
............
return DISPLAY_SUCCESS;
}
使用yuvplayer.exe 工具查看 /data/PreparePresent 文件,发现图片与预想的图层相同,绘制图层没有问题
- 比较异常导致
分析像素点颜色比较代码,打印合成后颜色与预设颜色
uint32_t CheckPixel(const BufferHandle &handle, int x, int y, uint32_t color)
{
const int32_t PIXEL_BYTES = 4;
............
............
uint32_t *pixel = reinterpret_cast<uint32_t *>(handle.virAddr) + position;
DISPLAY_TEST_CHK_RETURN((pixel == nullptr), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("get pixel failed"));
uint32_t checkColor = ConverToRGBA(static_cast<Composer::V1_0::PixelFormat>(handle.format), GetUint32(*pixel));
if (checkColor != color) {
// 添加打印 打印预设颜色和合成后的颜色
DISPLAY_TEST_LOGD("x:%{public}d y:%{public}d width:%{public}d checkColor:%{public}d color:%{public}d", x, y, handle.width,checkColor,color);
SaveFile("/data/display_test_bitmap_", static_cast<uint8_t *>(handle.virAddr), handle.size);
return DISPLAY_FAILURE;
}
............
............
return DISPLAY_SUCCESS;
}
通过日志分析打印获取的合成后的颜色都为黑色,用yuvplayer.exe 查看 /data/display_test_bitmap_ 为黑色,由此可以说明大概率时合成问题
- 合成异常导致 分析合成送显代码,保存显示后的合成数据,打印送显后handle 地址
int32_t HdiTestDisplay::Commit()
{
int32_t fenceFd;
int ret;
HdiGrallocBuffer* buffer = nullptr;
if (needFlushFb_) {
ret = clientLayer_->SwapFrontToBackQ();
DISPLAY_TEST_CHK_RETURN((ret != DISPLAY_SUCCESS), DISPLAY_FAILURE,
DISPLAY_TEST_LOGE("has no front buffer display id %{public}u", id_));
buffer = clientLayer_->GetBackBuffer();
DISPLAY_TEST_CHK_RETURN((buffer == nullptr), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("can not get back buffer"));
BufferHandle* handle = buffer->Get();
DISPLAY_TEST_CHK_RETURN((handle == nullptr), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("BufferHandle is null"));
ClearColor(*handle, 0); // need clear the fb first
ret = buffer->SetGraphicBuffer([&](const BufferHandle* buffer, uint32_t seqNo) -> int32_t {
int32_t result = device_->SetDisplayClientBuffer(id_, buffer, seqNo, -1);
DISPLAY_TEST_CHK_RETURN(
(result != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("set client buffer handle failed"));
return DISPLAY_SUCCESS;
});
currentFb_ = handle;
DISPLAY_TEST_CHK_RETURN(
(ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("set client buffer handle failed"));
}
ret = device_->Commit(id_, fenceFd);
DISPLAY_TEST_CHK_RETURN(
(ret != DISPLAY_SUCCESS), DISPLAY_FAILURE, DISPLAY_TEST_LOGE("commit failed display id %{public}u", id_));
// 保存送显后buffer 的内容
SaveFile("/data/Commit", static_cast<uint8_t *>(handle->virAddr), handle->size);
............
............
return DISPLAY_SUCCESS;
}
通过日志分析,送显前后handle 地址没有发生变化,送显后的 buffer 数据依然为黑色,通过观察手机界面发现界面颜色为红色说明送显成功了,此时需要调查为什么buffer 数据依然为黑色,调查适配层代码
RK3568 合成策略如下:
如上流程图,RK3568 默认采用RGA的合成方式,图层合成后会将合成结果保存在mClientLayer 中送显。
本产品合成策略如下:
默认优先使用DPU合成,DPU只支持4个图层,如果总图层有6个,那前面3个将使用GSP合成结果到clientLayer,再与后面的3个图层一起,共4个layer给DPU合成送显。 DPU 的合成方式没有使用ClientBuffer 保存合成数据,调查一下DPU的合成,只需要将layer 与Plane 绑定,厂商对DPU合成集成在DRM 驱动中,所以不会使用clientLayer 接收合成数据
分析用例可以发现用例图层不超过4层,参照上述流程图,本产品和RK3568 在合成方式和合成结果上存在差异,用例失败的根本原因时本产品DPU合成方式不会将结果保存到clientLayer,会导致display xts 没办法获取到合成后的信息与预想图层比较,从而导致用例失败
知识分享
查看图像数据软件 yuvplayer.exe
更多推荐
所有评论(0)