当前位置: 首页 > news >正文

在OpenHarmony上适配图形显示【2】——调试display hdi的技巧

文章写作环境

openharmony 5.0.0

前提

1.drm内核态驱动ok,modetest atomic测试通过,详细请参考

  • https://ost.51cto.com/posts/36377
  • https://laval.csdn.net/64afc2bb8e3f043cd26d8082.html

2.芯片 gpu 内核态驱动ok

技巧

技巧1:关闭render_service的开机自动执行,手动执行render_service命令拉起render_service服务。

  • 调试display hdi代码过程中,手动执行render_service命令拉起render_service服务。openharmony图像起来之后再回退补丁。这样就不会因为display部分没写好导致机器重启了。

  • 这样也方便编display hdi的库,然后手动推进去,这样就不用重复编固件调试了

--- a/foundation/graphic/graphic_2d/graphic.cfg    2025-05-23 17:54:58.080877485 +0800
+++ b/foundation/graphic/graphic_2d/graphic.cfg    2025-05-23 17:54:42.130878310 +0800
@@ -24,7 +24,7 @@"services" : [{"name" : "render_service","path" : ["/system/bin/render_service"],
-            "critical" : [1, 5, 60],
+            "critical" : [0, 0, 60],"importance" : -20,"uid" : "graphics","gid" : ["system", "tp_host", "data_reserve"],--- a/vendor/xxxx/xxxx/security_config/critical_reboot_process_list.json    2025-08-20 19:38:54.726204891 +0800
+++ b/vendor/xxxx/xxxx/security_config/critical_reboot_process_list.json    2025-08-14 18:07:51.455150508 +0800
@@ -18,7 +18,7 @@},{"name": "render_service",
-            "critical": [1, 5, 60]
+            "critical": [0, 0, 60]},{"name": "storage_daemon",

技巧2:开启无线hdc

由于技巧1中选择了render_service手动执行,有时候会占用一个调试串口。

--- a/vendor/xxxx/xxxx/etc/para/hardware_xxxx.para    2025-08-14 18:45:28.000000000 +0800
+++ b/vendor/xxxx/xxxx/etc/para/hardware_xxxx.para    2025-08-22 11:39:48.650294809 +0800
@@ -17,3 +17,7 @@const.product.manufacturer=xxxxconst.product.software.version=xxxxconst.product.oharm.version=xxxx
+persist.hdc.mode=tcp
+persist.hdc.mode.usb=enable
+persist.hdc.mode.tcp=enable
+persist.hdc.port=55555
\ No newline at end of file

技巧3:设置屏幕常亮

有时候因为屏幕亮屏策略没调好的原因导致调试出现问题,调试display hdi的时候最好在源码里面设置屏幕常亮。

--- a/base/powermgr/power_manager/services/native/include/power_state_machine.h    2024-12-18 17:43:37.223539366 +0800
+++ b/base/powermgr/power_manager/services/native/include/power_state_machine.h    2024-12-24 19:25:31.256451651 +0800
@@ -30,7 +30,7 @@#include "hibernate_controller.h"#endif-#define DEFAULT_DISPLAY_OFF_TIME 30000
+#define DEFAULT_DISPLAY_OFF_TIME -1#define DEFAULT_SLEEP_TIME       5000namespace OHOS {--- a/base/powermgr/power_manager/services/native/profile/power_mode_config.xml    2024-12-18 17:43:37.223539366 +0800
+++ b/base/powermgr/power_manager/services/native/profile/power_mode_config.xml    2024-12-24 19:29:29.116384104 +0800
@@ -32,7 +32,7 @@--><switch_proxy version="1"><proxy id="600">
-        <switch id="101" value="30000" recover_flag="0"/>
+        <switch id="101" value="-1" recover_flag="0"/><switch id="102" value="0" recover_flag="0"/><switch id="103" value="-1" recover_flag="0"/><switch id="107" value="1" recover_flag="0"/>

技巧4:自行编写一个可执行程序来 查看显示器激活状态

display hdi编写一共有两种策略

  • 1.参考rk3568的来写,device/soc/rockchip/rk3568/hardware/display
    • 缺点:实现难度较大。
  • 2.参考模版来写,模版路径drivers/peripheral/display/hal/default_standard
    • 缺点:缺少对双屏的处理逻辑,还有hdmi/dp屏幕的热插拔处理。

笔者建议是,先基于模板来适配,亮屏成功后,参考3568的来增加对多屏的处理,还有热插拔逻辑。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <xf86drm.h>
#include <xf86drmMode.h>// 将连接器类型转换为可读字符串
const char* connector_type_to_string(uint32_t type) {switch (type) {case DRM_MODE_CONNECTOR_Unknown:     return "Unknown";case DRM_MODE_CONNECTOR_VGA:         return "VGA";case DRM_MODE_CONNECTOR_DVII:        return "DVI-I";case DRM_MODE_CONNECTOR_DVID:        return "DVI-D";case DRM_MODE_CONNECTOR_DVIA:        return "DVI-A";case DRM_MODE_CONNECTOR_Composite:   return "Composite";case DRM_MODE_CONNECTOR_SVIDEO:      return "S-Video";case DRM_MODE_CONNECTOR_LVDS:        return "LVDS";case DRM_MODE_CONNECTOR_Component:   return "Component";case DRM_MODE_CONNECTOR_9PinDIN:     return "9-pin DIN";case DRM_MODE_CONNECTOR_DisplayPort: return "DisplayPort";case DRM_MODE_CONNECTOR_HDMIA:       return "HDMI-A";case DRM_MODE_CONNECTOR_HDMIB:       return "HDMI-B";case DRM_MODE_CONNECTOR_TV:          return "TV";case DRM_MODE_CONNECTOR_eDP:         return "eDP";case DRM_MODE_CONNECTOR_VIRTUAL:     return "Virtual";case DRM_MODE_CONNECTOR_DSI:         return "DSI";default:                            return "Unknown";}
}// 将连接状态转换为可读字符串
const char* connection_status_to_string(uint32_t status) {switch (status) {case DRM_MODE_CONNECTED:    return "Connected";case DRM_MODE_DISCONNECTED: return "Disconnected";case DRM_MODE_UNKNOWNCONNECTION: return "Unknown";default:                    return "Invalid";}
}// 扫描已连接的显示器
int scan_connected_displays(int fd) {drmModeResPtr resources;int i;// 获取DRM资源(连接器、CRTC、编码器等)resources = drmModeGetResources(fd);if (!resources) {fprintf(stderr, "Failed to get DRM resources\n");return -1;}printf("Scanning connected displays...\n");printf("Found %d connectors, %d CRTCs, %d encoders\n", resources->count_connectors, resources->count_crtcs, resources->count_encoders);// 遍历所有连接器(通常对应物理显示接口)for (i = 0; i < resources->count_connectors; i++) {drmModeConnectorPtr connector = drmModeGetConnector(fd, resources->connectors[i]);if (!connector) {fprintf(stderr, "Failed to get connector %d\n", resources->connectors[i]);continue;}printf("\nConnector %d: %s, Status: %s\n", connector->connector_id,connector_type_to_string(connector->connector_type),connection_status_to_string(connector->connection));printf("  Encoder ID: %d\n", connector->encoder_id);printf("  Modes available: %d\n", connector->count_modes);// 获取当前活动的编码器和CRTC信息if (connector->encoder_id) {drmModeEncoderPtr encoder = drmModeGetEncoder(fd, connector->encoder_id);if (encoder) {printf("  Encoder CRTC ID: %d\n", encoder->crtc_id);printf("  Encoder type: %d\n", encoder->encoder_type);if (encoder->crtc_id) {printf("  Active CRTC ID: %d\n", encoder->crtc_id);// 获取CRTC(CRT控制器)的详细信息drmModeCrtcPtr crtc = drmModeGetCrtc(fd, encoder->crtc_id);if (crtc) {printf("  CRTC mode: %s\n", crtc->mode_valid ? crtc->mode.name : "Invalid");printf("  CRTC position: %dx%d\n", crtc->x, crtc->y);drmModeFreeCrtc(crtc);}} else {printf("  No active CRTC assigned to encoder\n");}drmModeFreeEncoder(encoder);} else {printf("  Failed to get encoder %d\n", connector->encoder_id);}} else {printf("  No encoder assigned to connector\n");}drmModeFreeConnector(connector);}drmModeFreeResources(resources);return 0;
}int main() {int fd;uint64_t has_dumb;// 打开DRM设备(通常第一个显卡是card0)fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);if (fd < 0) {fprintf(stderr, "Failed to open DRM device\n");return 1;}// 检查是否支持dumb buffer功能(基本图形缓冲区管理)if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || !has_dumb) {fprintf(stderr, "DRM device does not support dumb buffers\n");close(fd);return 1;}// 扫描并显示连接的显示器信息scan_connected_displays(fd);close(fd);return 0;
}
ohos_executable("modeset_crt_info") {cflags_c = ["-Wno-unused-variable",]sources = ["modeset_atomic_crtc/modeset_crt_info.c",]deps = ["//third_party/libdrm:libdrm",]install_images = [ "system" ]install_enable = truepart_name = ""subsystem_name = ""
}

运行效果(rk3568):

详细列出了当前系统检测到的显示连接器和其配置状态,可以查看每个显示器是否被分配了CRTC和Encoder。 在调试display的时候,可以用此程序来查看显示器是否激活

7e852febc807704d7ec8a792e840ee96.png


文章转载自:

http://MM5pwyGy.LfyzL.cn
http://eOhyhygC.LfyzL.cn
http://lbOnLSwn.LfyzL.cn
http://5amqnjeX.LfyzL.cn
http://e9BhhxiL.LfyzL.cn
http://hhz0qgIC.LfyzL.cn
http://5fmmHeCI.LfyzL.cn
http://dKpJeq88.LfyzL.cn
http://8bJHxxDD.LfyzL.cn
http://Hrzv3xAO.LfyzL.cn
http://LVuJPmdq.LfyzL.cn
http://iBjIad9L.LfyzL.cn
http://YWE6pRSe.LfyzL.cn
http://8Uk2wKLr.LfyzL.cn
http://dfZVouvQ.LfyzL.cn
http://YvKqVQWO.LfyzL.cn
http://ecxnyKJN.LfyzL.cn
http://ge5QJ80M.LfyzL.cn
http://mAxW4YZN.LfyzL.cn
http://d4kECMuf.LfyzL.cn
http://laFPGguH.LfyzL.cn
http://L1yPEnrZ.LfyzL.cn
http://3OZoitM7.LfyzL.cn
http://dAbKCxy8.LfyzL.cn
http://f3SmYc5c.LfyzL.cn
http://l5z4TCrG.LfyzL.cn
http://PozoQDZB.LfyzL.cn
http://xTM0lTAd.LfyzL.cn
http://pVW9gOai.LfyzL.cn
http://HhEaKUI6.LfyzL.cn
http://www.dtcms.com/a/374180.html

相关文章:

  • 在 JavaScript 中轻松实现 AES 加密与解密:从原理到实战
  • Mockoon:开源免费的本地Mock服务工具,提升前后端联调效率
  • C/C++圣诞树②
  • segYolo添加界面
  • 初学Transformer核心——注意力机制
  • 第9篇:Freqtrade量化交易之config.json 基础入门与初始化
  • 推荐系统学习笔记(十六)LHUC(PPNet)
  • 前端开发实战 主流前端开发工具对比与最佳实践
  • 淘宝 API 技术架构与实战指南:从实时数据流到 AIGC 融合的电商开发新范式
  • 基于AD9689BBPZ-2600 的高速数字采集 板卡
  • Transformer 模型:Attention is All You Need 的真正含义
  • BUU MISC(看心情写)
  • 第三方网站数据库测评:【源码级SQL注入与数据泄露风险全面测评】
  • 【Linux基础】parted命令详解:从入门到精通的磁盘分区管理完全指南
  • 实践《数字图像处理》之Canny边缘检测、霍夫变换与主动二值化处理在短线段清除应用中的实践
  • sim2real_动作迁移常用的方法和思路(比如bvh->robot)
  • 第六届机器学习与计算机应用国际学术会议
  • 正交匹配追踪(OMP)详解:压缩感知的基石算法
  • Github项目推荐:Made-With-ML 机器学习工程学习指南
  • 【Java实战㉞】从0到1:Spring Boot Web开发与接口设计实战
  • Python从入门到精通_01_python基础
  • 基于开源做的图片压缩工具
  • 联邦学习与大模型结合
  • SQL隐式链接显式连接
  • pd19虚拟机安装Win11系统
  • 【面试场景题】如何进行高并发系统的性能测试?
  • Keepalived配置好后,域名解析到哪里
  • 滑动窗口题目:长度最小的子数组
  • 如何Maven 构建问题排查与依赖管理
  • 嵌入式学习日记(42)ARM