我在使用适用于ZynqMP的Ubuntu22.04上尝试运行Lima(DRI Lima篇)
首先
Lima是Mali-400/450的开源图形驱动程序。本文作者尝试在ZynqMP的Ubuntu 22.04上试验性地运行了Lima。由于遇到了一些困难,因此将其方法分为几个部分进行解释。
-
- 概要編
-
- DRM Lima 編
-
- DRI Lima 編 (この記事)
-
- 共有バッファ編
-
- ストライド問題編
-
- GEM キャッシュ編
-
- インストール編(近日公開)
- [glmrak2編]
在这篇文章中,将解释Mesa提供的DRI Lima驱动程序在xlnx上的修正点以及Debian软件包的构建方法。
DRI Lima是什么意思?
DRI Lima 是 Mesa(一种开源的 OpenGL 实现)的 DRI(直接渲染基础设施)驱动程序。DRI Lima 将 OpenGL 命令序列转换为 Lima 命令,并使用 DRM Lima 将命令发送到硬件上。DRI Lima 在用户空间尽可能多地进行处理,以便 DRM Lima 在内核空间中完成其所需的全部工作。
图1 利马 DRI
将DRI Lima适应xlnx技术。
Ubuntu 22.04 使用的 libGL 的 DRI 驱动程序以 Debian 包 libgl1-mesa-dri 的形式提供。该包中包含了适用于 Lima 的 DRI 驱动程序。然而,遗憾的是,该包中包含的 Lima DRI 不支持 DDX Xlnx 和 DRM Xlnx。因此,需要单独构建支持 xlnx 的 DRI Lima。本章将详细解释这些更改。
源代码
Ubuntu 22.04使用的libgl1-mesa-dri版本为22.0.5-0ubuntu0.1。您可以使用apt-get的source命令下载源代码。
shell$ apt-get source mesa=22.0.5-0ubuntu0.1
shell$ cd mesa-22.0.5
添加图书馆
为了让 DRI Lima 与 xlnx 兼容,需要一个名为 /usr/lib/aarch64-linux-gnu/dri/xlnx_dri.so 的动态库。
实际上,libgl1-mesa-dri提供的DRI驱动程序只是通过硬链接给一个库文件取了另一个名字,并且虽然文件很多,但也只是一个库文件。因此,如果只想创建一个名为xlnx_dri.so的动态库,只需在src/gallium/targets/dri/meson.build中添加 ‘xlnx_dri.so’ ,编译时就会生成xlnx_dri.so。然而,目前缺乏与xlnx相对应的入口点,所以与动态库的链接会失败。
index d066ce6..d1b0824 100644
--- a/src/gallium/targets/dri/meson.build
+++ b/src/gallium/targets/dri/meson.build
@@ -91,6 +91,7 @@ foreach d : [[with_gallium_kmsro, [
'st7735r_dri.so',
'stm_dri.so',
'sun4i-drm_dri.so',
+ 'xlnx_dri.so',
]],
[with_gallium_radeonsi, 'radeonsi_dri.so'],
[with_gallium_nouveau, 'nouveau_dri.so'],
添加入口点
为了让DRI Lima与xlnx兼容,仅仅有一个名为xlnx_dri.so的动态库是不足够的。除此之外,动态库还必须定义一个名为__driDriverGetExtensions_xlnx()的函数作为入口点。因此,我们需要在src/gallium/targes/dri/target.c中添加xlnx的入口点。
index 2ac9ef4..ae5a7b3 100644
--- a/src/gallium/targets/dri/target.c
+++ b/src/gallium/targets/dri/target.c
@@ -120,6 +120,7 @@ DEFINE_LOADER_DRM_ENTRYPOINT(st7586)
DEFINE_LOADER_DRM_ENTRYPOINT(st7735r)
DEFINE_LOADER_DRM_ENTRYPOINT(stm)
DEFINE_LOADER_DRM_ENTRYPOINT(sun4i_drm)
+DEFINE_LOADER_DRM_ENTRYPOINT(xlnx)
#endif
利马DRI的建筑
在这一章中,我们将介绍如何构建适用于 xlnx 平台的 DRI Lima 的 Debian 包。
构建环境
为了构建Mesa的Debian软件包,需要用到各种arm64编译器等不同的软件包。而且这些软件包的版本必须相互匹配。尝试在PC(x86架构)上进行交叉编译或使用QEMU等虚拟环境构建并不成功。因此,本文作者选择在Ultra96-V2上安装Ubuntu22.04的CUI版本,并进行自身编译。通过自身编译,就不需要担心版本不匹配的问题。
在 Ultra96-V2 上的 Ubuntu 22.04 系统中,按照以下步骤来建立构建环境。
shell$ sudo apt-get build-dep mesa
shell$ sudo apt-get install cmake valgrind libunwind-dev libconfig-dev
下载源代码
请使用 apt-get 的 source 命令来下载源代码。
shell$ apt-get source mesa=22.0.5-0ubuntu0.1
shell$ cd mesa-22.0.5
源代码的修正
为了使DRI Lima与xlnx兼容,我将在源代码中进行修正,详细过程在前一节已经解释过,这里就不再赘述。
增加附加套餐
通过前面的修改,可以构建与 xlnx 兼容的 DRI Lima (xlnx_dri.so)。然而,按照目前的方式,xlnx_dri.so 将被包含在 libgl1-mesa-dri 包中,如果要将 xlnx_dri.so 添加到已安装 libgl1-mesa-dri 包的系统中,就必须覆盖 libgl1-mesa-dri 包本身。无论是更改包含 xlnx_dri.so 的包的版本号还是不更改,都可能引起管理上的问题。
因此,我们将创建一个包含 xlnx_dri.so 的 libgl1-mesa-xlnx-dri 包。如果已经安装了libgl1-mesa-dri包的系统,我们可以通过后续安装这个包来只安装 xlnx_dri.so。
具体操作如下:修改 `debian/control` 和 `debian/rules` 的内容如下。
index 061ee58..4cf2442 100644
--- a/debian/control
+++ b/debian/control
@@ -429,4 +429,23 @@ Description: free implementation of the OpenCL API -- ICD runtime
provides a standardized interface for computational analysis on graphical
processing units.
+Package: libgl1-mesa-xlnx-dri
+Section: libs
+Architecture: any
+Pre-Depends: ${misc:Pre-Depends}
+Depends:
+ ${shlibs:Depends},
+ ${misc:Depends}
+Multi-Arch: same
+Description: free implementation of the OpenGL API -- xlnx dri module
+ This version of Mesa provides GLX and DRI capabilities: it is capable of
+ both direct and indirect rendering. For direct rendering, it can use DRI
+ modules from the libgl1-mesa-dri package to accelerate drawing.
+ .
+ This package does not include the OpenGL library itself, only the DRI
+ modules for accelerating direct rendering.
+ .
+ For a complete description of Mesa, please look at the
+ libglx-mesa0 package.
+
# vim: tw=0
index 9dc0560..91cc60a 100755
--- a/debian/rules
+++ b/debian/rules
@@ -216,6 +216,11 @@ override_dh_install:
rm debian/tmp/usr/lib/*/libEGL_mesa.so
rm debian/tmp/usr/lib/*/libGLX_mesa.so
+ # Copy the hardlinked xlnx_dri.so correctly.
+ install -m755 -d debian/libgl1-mesa-xlnx-dri/usr/lib/${DEB_HOST_MULTIARCH}/dri/
+ cp debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/dri/xlnx_dri.so \
+ debian/libgl1-mesa-xlnx-dri/usr/lib/${DEB_HOST_MULTIARCH}/dri/
+
# Copy the hardlinked *_dri.so correctly.
install -m755 -d debian/libgl1-mesa-dri/usr/lib/${DEB_HOST_MULTIARCH}/dri/
mv debian/tmp/usr/lib/${DEB_HOST_MULTIARCH}/dri/*_dri.so \';
CntSty={
ParSty='diff
构建软件包
以下是构建整个软件包的步骤。
shell$ sudo debian/rules binary
因为Ultra96-V2的I/O速度较慢,所以可能需要一些时间。耐心等待,就可以得到包含libgl1-mesa-xlnx-dri包的Mesa的所有Debian包。
shell$ dpkg --info ./libgl1-mesa-dri_22.0.5-0ubuntu0.1_arm64.deb
new Debian package, version 2.0.
size 6920362 bytes: control archive=1390 bytes.
1115 bytes, 22 lines control
3665 bytes, 47 lines md5sums
168 bytes, 5 lines * postinst #!/bin/sh
168 bytes, 5 lines * postrm #!/bin/sh
168 bytes, 5 lines * preinst #!/bin/sh
168 bytes, 5 lines * prerm #!/bin/sh
Package: libgl1-mesa-dri
Source: mesa
Version: 22.0.5-0ubuntu0.1
Architecture: arm64
Maintainer: Debian X Strike Force <debian-x@lists.debian.org>
Installed-Size: 21569
Depends: libc6 (>= 2.34), libdrm-amdgpu1 (>= 2.4.105), libdrm-nouveau2 (>= 2.4\
.66), libdrm-radeon1 (>= 2.4.31), libdrm2 (>= 2.4.89), libelf1 (>= 0.142), libe\
xpat1 (>= 2.0.1), libgcc-s1 (>= 3.0), libglapi-mesa (= 22.0.5-0ubuntu0.1), libl\
lvm13, libsensors5 (>= 1:3.5.0), libstdc++6 (>= 11), libvulkan1 (>= 1.2.131.2),\
libzstd1 (>= 1.4.0), zlib1g (>= 1:1.1.4)
Recommends: libgl1-amber-dri
Section: libs
Priority: optional
Multi-Arch: same
Homepage: https://mesa3d.org/
Description: free implementation of the OpenGL API -- DRI modules
This version of Mesa provides GLX and DRI capabilities: it is capable of
both direct and indirect rendering. For direct rendering, it can use DRI
modules from the libgl1-mesa-dri package to accelerate drawing.
.
This package does not include the OpenGL library itself, only the DRI
modules for accelerating direct rendering.
.
For a complete description of Mesa, please look at the
libglx-mesa0 package.
存储库
這章所解釋的內容可以在以下的 GitHub 儲存庫找到。
- https://github.com/ikwzm/mesa-xlnx
提供Debian软件包
前一章中提到的自建方法非常麻煩,因為需要Ultra96 + Ubuntu 22.04的建置環境。因此,我們在以下的github儲存庫中準備了已經針對Ubuntu 22.04建置的Debian套件。如果覺得自己建置太麻煩的話,請下載這些套件。
https://github.com/ikwzm/mesa-xlnx/tree/mesa-xlnx-dri_22.0.5-0ubuntu0.1
libgl1-mesa-xlnx-dri_22.0.5-0ubuntu0.1_arm64.deb
libGL加载DRI驱动的机制需要补充。
在这一章中,我们将解释libGL加载DRI驱动程序的机制。
创建DRi3屏幕
在DRI3的情况下,调用dri3_create_screen()来生成屏幕。此屏幕生成函数按以下步骤加载DRI驱动。
-
- 调用glx_screen_init()进行初始化。
-
- 调用loader_dri3_open()获取当前X-Server正在使用的DRM驱动程序的文件描述符(psc->fd)。
-
- 例如,如果X-Server使用/dev/dri/card0,则是该设备文件的文件描述符。
-
- 调用loader_get_driver_for_fd()获取通过2得到的文件描述符的DRM驱动程序名称(driverName)。
-
- 例如,如果/dev/dri/card0的DRM驱动程序名称是xlnx,则是”xlnx”。
- 调用driOpenDriver()加载在3中获取的DRI驱动程序名称的DRI驱动程序。driOpenDriver()将在下一节中说明。
static struct glx_screen *
dri3_create_screen(int screen, struct glx_display * priv)
{
xcb_connection_t *c = XGetXCBConnection(priv->dpy);
const __DRIconfig **driver_configs;
const __DRIextension **extensions;
const struct dri3_display *const pdp = (struct dri3_display *)priv->dri3Display;
struct dri3_screen *psc;
__GLXDRIscreen *psp;
struct glx_config *configs = NULL, *visuals = NULL;
char *driverName, *tmp;
int i;
unsigned char disable;
psc = calloc(1, sizeof *psc);
if (psc == NULL)
return NULL;
psc->fd = -1;
if (!glx_screen_init(&psc->base, screen, priv)) {
free(psc);
return NULL;
}
psc->fd = loader_dri3_open(c, RootWindow(priv->dpy, screen), None);
if (psc->fd < 0) {
int conn_error = xcb_connection_has_error(c);
glx_screen_cleanup(&psc->base);
free(psc);
InfoMessageF("screen %d does not appear to be DRI3 capable\n", screen);
if (conn_error)
ErrorMessageF("Connection closed during DRI3 initialization failure");
return NULL;
}
psc->fd = loader_get_user_preferred_fd(psc->fd, &psc->is_different_gpu);
driverName = loader_get_driver_for_fd(psc->fd);
if (!driverName) {
ErrorMessageF("No driver found\n");
goto handle_error;
}
extensions = driOpenDriver(driverName, &psc->driver);
if (extensions == NULL)
goto handle_error;
:
(後略)
:
}
打开驱动程序
driOpenDriver() 函数会调用 loader_open_driver()。在此过程中,会传递用于搜索 DRI 驱动程序的目录环境变量的名称。loader_open_driver() 函数将在下一节中进行解释。
_X_HIDDEN const __DRIextension **
driOpenDriver(const char *driverName, void **out_driver_handle)
{
void *glhandle;
/* Attempt to make sure libGL symbols will be visible to the driver */
glhandle = dlopen(GL_LIB_NAME, RTLD_NOW | RTLD_GLOBAL);
static const char *search_path_vars[] = {
"LIBGL_DRIVERS_PATH",
"LIBGL_DRIVERS_DIR", /* deprecated */
NULL
};
const __DRIextension **extensions =
loader_open_driver(driverName, out_driver_handle, search_path_vars);
if (glhandle)
dlclose(glhandle);
return extensions;
}
加载器打开驱动程序
loader_open_driver() 函数会按照以下步骤来加载与指定的 DRI 驱动名称对应的动态库到内存中。
-
- 创建一个名为search_paths的路径名数组。
-
- 通过sprintf(“%.*s/%s_dri.so”, p, driver_name)将名为driver_name的动态库加载到内存中,加载方法为dlopen()。其中p是要搜索的路径名。
-
- 例如,如果driver_name为”xlnx”,则从搜索目录中查找”xlnx_dri.so”。
-
- 调用loader_get_extensions_name(driver_name)来获取get_extensions_name。
-
- 例如,如果driver_name为”xlnx”,那么它将变成”__driDriverGetExtensions_xlnx”。
-
- 通过动态库中指定的get_extensions_name符号获得get_extensions的地址。
- 通过调用获得地址的get_extensions函数,获得extensions。
const struct __DRIextensionRec **
loader_open_driver(const char *driver_name,
void **out_driver_handle,
const char **search_path_vars)
{
char path[PATH_MAX], *search_paths, *next, *end;
char *get_extensions_name;
const struct __DRIextensionRec **extensions = NULL;
const struct __DRIextensionRec **(*get_extensions)(void);
search_paths = NULL;
if (geteuid() == getuid() && search_path_vars) {
for (int i = 0; search_path_vars[i] != NULL; i++) {
search_paths = getenv(search_path_vars[i]);
if (search_paths)
break;
}
}
if (search_paths == NULL)
search_paths = DEFAULT_DRIVER_DIR;
void *driver = NULL;
end = search_paths + strlen(search_paths);
for (char *p = search_paths; p < end; p = next + 1) {
int len;
next = strchr(p, ':');
if (next == NULL)
next = end;
len = next - p;
#if USE_ELF_TLS
snprintf(path, sizeof(path), "%.*s/tls/%s_dri.so", len, p, driver_name);
driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
#endif
if (driver == NULL) {
snprintf(path, sizeof(path), "%.*s/%s_dri.so", len, p, driver_name);
driver = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
if (driver == NULL)
log_(_LOADER_DEBUG, "MESA-LOADER: failed to open %s: %s\n",
path, dlerror());
}
/* not need continue to loop all paths once the driver is found */
if (driver != NULL)
break;
}
if (driver == NULL) {
log_(_LOADER_WARNING, "MESA-LOADER: failed to open %s (search paths %s)\n",
driver_name, search_paths);
*out_driver_handle = NULL;
return NULL;
}
log_(_LOADER_DEBUG, "MESA-LOADER: dlopen(%s)\n", path);
get_extensions_name = loader_get_extensions_name(driver_name);
if (get_extensions_name) {
get_extensions = dlsym(driver, get_extensions_name);
if (get_extensions) {
extensions = get_extensions();
} else {
log_(_LOADER_DEBUG, "MESA-LOADER: driver does not expose %s(): %s\n",
get_extensions_name, dlerror());
}
free(get_extensions_name);
}
if (!extensions)
extensions = dlsym(driver, __DRI_DRIVER_EXTENSIONS);
if (extensions == NULL) {
log_(_LOADER_WARNING,
"MESA-LOADER: driver exports no extensions (%s)\n", dlerror());
dlclose(driver);
}
*out_driver_handle = driver;
return extensions;
}
加载器_获取扩展名
loader_get_extensions_name()函数返回与指定的DRI驱动程序名称driver_name对应的入口点名称。例如,如果driver_name为”xlnx”,那么返回的名称将为”__driDriverGetExtensions_xlnx”。
char *
loader_get_extensions_name(const char *driver_name)
{
char *name = NULL;
if (asprintf(&name, "%s_%s", __DRI_DRIVER_GET_EXTENSIONS, driver_name) < 0)
return NULL;
const size_t len = strlen(name);
for (size_t i = 0; i < len; i++) {
if (name[i] == '-')
name[i] = '_';
}
return name;
}
__driDriverGetExtensions_xlnx 取得驱动程式扩展_xlnx
__driDriverGetExtensions_xlnx是定义在动态库xlnx_dri.so中的入口点。这个入口点是在前一章中描述的DRI Lima构建过程中添加的。
#define DEFINE_LOADER_DRM_ENTRYPOINT(drivername) \
const __DRIextension **__driDriverGetExtensions_##drivername(void); \
PUBLIC const __DRIextension **__driDriverGetExtensions_##drivername(void) \
{ \
globalDriverAPI = &galliumdrm_driver_api; \
return galliumdrm_driver_extensions; \
}
:
:
DEFINE_LOADER_DRM_ENTRYPOINT(xlnx)
:
请你提供以下的参考。
Debian软件包
我們在以下網址上提供了修復了DRI Lima的Debian軟件包。同時,我們也提供了修復用的補丁檔案作為參考。
- https://github.com/ikwzm/mesa-xlnx/tree/mesa-xlnx-dri_22.0.5-0ubuntu0.1
这是一篇过时的文章。
这篇文章是对下一篇文章进行了修改和补充。
- 『Ultra96/Ultra96-V2 向け Ubuntu20.04で Lima を動かしてみた(DRI Lima 編)』@Qiita
其他
-
- Lima web (https://gitlab.freedesktop.org/lima/web)
- Mesa 3D and Direct Rendering Infrastructure wiki (https://dri.freedesktop.org/wiki)