我在Ultra96/Ultra96-V2上尝试在Ubuntu20.04上运行Lima (DRI Lima版本)
请注意(2022年10月12日补充)
请参考我于2022年10月发布的以下文章,这是一篇在2021年4月发布的旧文章,其中包含了过时的内容。
在ZynqMP上尝试在Ubuntu22.04上运行Lima(DRI Lima编)的文章。
首先
Lima是Mali-400/450的开源图形驱动程序。我在Ultra96/Ultra96-V2上的Ubuntu 20.04上试验性地运行了Lima。由于运行起来有点困难,所以我会分几次说明运行的方法。
-
概要編
DRM Lima 編
DRI Lima 編 (この記事)
共有バッファ編
ストライド問題編
インストール編
Ubuntu Desktop ビルド編
本篇文章将讲解有关Mesa提供的DRI Lima驱动适配到xlnx所需要的修正点以及Debian软件包的构建方法。
需要注意的是,截至到目前(2021年4月),我们确认Ubuntu 20.04的gnome-shell可以运行,但请注意,并不是所有应用程序都进行了确认。
DRI Lima 是什麼?
DRI Lima是Mesa的DRI(Direct Rendering Infrastructure)驱动程序,它将OpenGL命令序列转换为Lima命令,并使用DRM Lima将命令发送到硬件。DRI Lima在用户空间尽可能多地处理,而DRM Lima在内核空间执行必要的操作。

图1 利马DRI
将DRI Lima转换为xlnx兼容的形式。
在 Ubuntu 20.04 中使用的 libGL DRI 驱动程序在 Debian 软件包中提供的 libgl1-mesa-dri 中。而且,该软件包中包含了适用于 Lima 的 DRI 驱动程序。然而,令人遗憾的是,该软件包中包含的 Lima DRI 不支持 DDX Xlnx 和 DRM Xlnx。因此,您需要单独构建支持 xlnx 的 DRI Lima。本章将解释这些更改的内容。
源代码
Ubuntu 20.04 使用的 libgl1-mesa-dri 版本为 20.2.6-0ubuntu0.20.04.1。源代码可通过 apt-get 的 source 命令进行下载。
shell$ apt-get source mesa=20.2.6-0ubuntu0.20.04.1
shell$ cd mesa-20.2.6
添加图书馆
为了使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 7cd8666..c85dc74 100644
--- a/src/gallium/targets/dri/meson.build
+++ b/src/gallium/targets/dri/meson.build
@@ -84,6 +84,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/targets/dri/target.c中添加xlnx的入口点。
index f71f690..e8f4340 100644
--- a/src/gallium/targets/dri/target.c
+++ b/src/gallium/targets/dri/target.c
@@ -110,6 +110,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
地理環境研究所利馬的建築
在本章中,将介绍如何构建适用于xlnx的DRI Lima的Debian软件包。
构建环境
为了构建Mesa的Debian软件包,需要许多不同的包,如适用于arm64的编译器,而且这些软件包的版本必须相互兼容。在PC(x86架构)上交叉编译这些环境,或者使用QEMU等虚拟环境进行构建并不顺利。因此,我安装了Ubuntu20.04的CUI版本在Ultra96-V2上,并进行了自主编译。使用自主编译就无需担心版本不一致的问题。
在Ultra96-V2上的Ubuntu 20.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=20.2.6-0ubuntu0.20.04.1
shell$ cd mesa-20.2.6
修改源代码
在源代码中进行了修正以使其与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 c1f316b..d1b0bcf 100644
--- a/debian/control
+++ b/debian/control
@@ -427,4 +427,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 cbbf298..b457d91 100755
--- a/debian/rules
+++ b/debian/rules
@@ -202,6 +202,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 \\
构建软件包
下面是构建整个软件包的方法。
shell$ sudo debian/rules binary
由于Ultra96-V2的I/O速度较慢,可能需要一些时间。请耐心等待,然后您将获得包含libgl1-mesa-xlnx-dri软件包在内的所有Debian软件包。
shell$ dpkg --info ../libgl1-mesa-xlnx-dri_20.2.6-0ubuntu0.20.04.1_arm64.deb
new Debian package, version 2.0.
size 5167796 bytes: control archive=1048 bytes.
1095 bytes, 21 lines control
397 bytes, 5 lines md5sums
Package: libgl1-mesa-xlnx-dri
Source: mesa
Version: 20.2.6-0ubuntu0.20.04.1
Architecture: arm64
Maintainer: Debian X Strike Force <debian-x@lists.debian.org>
Installed-Size: 18260
Depends: libc6 (>= 2.29), libdrm-amdgpu1 (>= 2.4.100), libdrm-nouveau2 (>= 2.4.66), libdrm-radeon1 (>= 2.4.31), libdrm2 (>= 2.4.89), libelf1 (>= 0.142), libexpat1 (>= 2.0.1), libglapi-mesa (= 20.2.6-0ubuntu0.20.04.1), libllvm11 (>= 1:9~svn298832-1~), libsensors5 (>= 1:3.5.0), libstdc++6 (>= 5.2), libunwind8, libzstd1 (>= 1.3.2), zlib1g (>= 1:1.1.4)
Section: libs
Priority: optional
Multi-Arch: same
Homepage: https://mesa3d.org/
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.
仓库
本章所介绍的内容已经在以下的 GitHub 代码仓库中准备好了。
-
https://github.com/ikwzm/mesa-xlnx
提供Debian软件包
在前一章中详细说明了自建方法,但由于需要 Ultra96 + Ubuntu 20.04 的构建环境,所以非常繁琐。因此,我已经在以下的 github 仓库中准备了适用于 Ubuntu 20.04 的 Debian 软件包,如果你觉得自己构建太麻烦,可以直接下载使用。
https://github.com/ikwzm/ZynqMP-FPGA-Ubuntu20.04-Lima-Ultra96
libgl1-mesa-xlnx-dri_20.2.6-0ubuntu0~20.04.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驱动程序。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)动态库名称将函数加载到内存中,使用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() 函数将返回与 driver_name 指定的 DRI 驱动程序名称相对应的入口点名称。例如,如果 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;
}
获取扩展驱动_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)
:
请提供下列资料作为参考。
Lima web (https://gitlab.freedesktop.org/lima/web)
Mesa 3D and Direct Rendering Infrastructure wiki (https://dri.freedesktop.org/wiki)
https://github.com/ikwzm/ZynqMP-FPGA-Ubuntu20.04-Lima-Ultra96
https://github.com/ikwzm/mesa-xlnx
Mesa 3D and Direct Rendering Infrastructure wiki (https://dri.freedesktop.org/wiki)
https://github.com/ikwzm/ZynqMP-FPGA-Ubuntu20.04-Lima-Ultra96
https://github.com/ikwzm/mesa-xlnx