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

离北况归
发布于 2025-9-8 17:46
浏览
0收藏

文章写作环境

openharmony 5.0.0

前提

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

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=xxxx
 const.product.software.version=xxxx
 const.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       5000
 
 namespace 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 = true
  part_name = ""
  subsystem_name = ""
}

运行效果(rk3568):

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

在OpenHarmony上适配图形显示【2】——调试display hdi的技巧-鸿蒙开发者社区

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
已于2025-9-8 17:47:06修改
收藏
回复
举报
回复
    相关推荐