From 4ffe6ef25a20a5bc0c60665c6b8f69d7c2e7ea27 Mon Sep 17 00:00:00 2001 From: Matvii Zorin Date: Fri, 17 Jul 2020 17:40:46 +0300 Subject: [PATCH] gbm_gralloc: Add feature to search for KMS DRI card Most modern SOCs have separate IP cores for GPU and Display Unit (KMS). To work properly mesa requires initialize gbm interface using KMS card. Mesa uses it to allocate buffers with SCANOUT flag and does not require fd or pathname explicitly specified for GPU. Mesa will search for GPU and load the proper driver. Also, there is no warranty that the KMS card will always have /dev/dri/card0 path and GPU - /dev/dri/card1. Order can depend on many factors. For example: on the rpi4 board, it was observed that enabling the WIFI kernel module swapping the card order. Therefore searching for the KMS card is the only efficient solution. The is_kms_dev function returns true when the libdrm function is returned resources and the target device has at least one CTRC, connector, and encoder. The open_first_kms_dev function returns opened file descriptor on success using the previous function to check for each device. It also returns zeroed value for the case of KMS absence, or the -EINVAL on glob function error. In the case of absence of the "hwc.drm.device" system property the first KMS device or the default path /dev/dri/renderD128 will be used to open. Signed-off-by: Matvii Zorin Reviewed-by: Roman Stratiienko --- gralloc_gbm.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++-- gralloc_gbm_priv.h | 3 +++ 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/gralloc_gbm.cpp b/gralloc_gbm.cpp index f5729b9..5746466 100644 --- a/gralloc_gbm.cpp +++ b/gralloc_gbm.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include @@ -311,10 +313,23 @@ struct gbm_device *gbm_dev_create(void) { struct gbm_device *gbm; char path[PROPERTY_VALUE_MAX]; + int path_len; int fd; - property_get("gralloc.gbm.device", path, "/dev/dri/renderD128"); - fd = open(path, O_RDWR | O_CLOEXEC); + path_len = property_get("gralloc.gbm.device", path, "/dev/dri/card*"); + /* Search for KMS device with the pattern or open it from property */ + if (path[path_len - 1] == '*') { + fd = open_first_kms_dev(path); + } else { + fd = open(path, O_RDWR | O_CLOEXEC); + } + + /* Open default path when KMS device wasn't found */ + if (!fd) { + strcpy(path, "/dev/dri/renderD128"); + fd = open(path, O_RDWR | O_CLOEXEC); + } + if (fd < 0) { ALOGE("failed to open %s", path); return NULL; @@ -529,3 +544,49 @@ int gralloc_gbm_bo_lock_ycbcr(buffer_handle_t handle, return 0; } + +/* + * Check if target device has KMS. + */ +bool is_kms_dev(int fd) +{ + auto res = drmModeGetResources(fd); + if (!res) + return false; + + bool is_kms = res->count_crtcs > 0 && res->count_connectors > 0 && + res->count_encoders > 0; + + drmModeFreeResources(res); + + return is_kms; +} + +/* + * Search for a KMS device. Return opened file descriptor on success. + */ +int open_first_kms_dev(const char *pattern) +{ + glob_t glob_buf; + memset(&glob_buf, 0, sizeof(glob_buf)); + int fd; + + int ret = glob(pattern, 0, NULL, &glob_buf); + if (ret) { + globfree(&glob_buf); + return -EINVAL; + } + + for (size_t i = 0; i < glob_buf.gl_pathc; ++i) { + fd = open(glob_buf.gl_pathv[i], O_RDWR | O_CLOEXEC); + if (fd < 0 || is_kms_dev(fd)) + break; + + close(fd); + fd = 0; + } + + globfree(&glob_buf); + + return fd; +} diff --git a/gralloc_gbm_priv.h b/gralloc_gbm_priv.h index cbe9256..320f086 100644 --- a/gralloc_gbm_priv.h +++ b/gralloc_gbm_priv.h @@ -51,6 +51,9 @@ int gralloc_gbm_bo_lock_ycbcr(buffer_handle_t handle, int usage, struct gbm_device *gbm_dev_create(void); void gbm_dev_destroy(struct gbm_device *gbm); +bool is_kms_dev(int fd); +int open_first_kms_dev(const char *pattern); + #ifdef __cplusplus } #endif