OpenGL ES 在无头嵌入式 linux 平台中的使用
OpenGL ES use in a headless embedded linux platform
在我们的项目中,我们希望使用 Freescale iMX6Q ARM 处理器的 GPU 渲染图像,然后通过 gstreamer 管道写入 VNC 服务器。
顺序如下:
- 初始化 OpenGL
- 对于视频流的每一帧:
- 使用 OpenGL ES 将图像渲染为使用帧缓冲区和
渲染缓冲区
- 使用
glReadPixels()
读取图像像素
- 将图像数据复制到视频帧
- 推帧到视频流
我们使用 Yocto 1.8 作为构建系统,初始化序列下方的源代码适用于我们的 nitrogen6X-lite 原型板(定义了 USE_PBUFFER
),但不适用于我们的无头生产板。在生产板上我们无法初始化 "display":无论是否定义了 USE_PBUFFER
,我们都会得到一个 0x3003 EGL_BAD_ALLOC
错误。我们有 vfb
内核模块加载了 vfb_enable=1
和 video=vfb
内核选项。开发文件 /dev/fb0
创建成功。在 yocto 中,我们尝试了默认模式下的 fsl-image-multimedia-full
、image-core
和 image-core-directfb
图像,以及
DISTRO_FEATURES_remove = " x11 wayland"
DISTRO_FEATURES_append = " directfb"
在我们的 conf/local.conf
文件中。
我们应该如何在嵌入式 Linux 设置中使用 iMX 处理器的 GPU 在没有显示器的情况下进行离屏渲染?什么是合适的内核设置?什么是合适的 user-space 使用的功能?
当前用户-space OpenGL 初始化序列的实现:
EGLDisplay display;
EGLSurface surface;
#ifdef USE_PBUFFER
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
#else
int fbnum = 0; // fbnum is an integer for /dev/fb0 fbnum = 0
EGLNativeDisplayType native_display = fbGetDisplayByIndex(fbnum);
EGLNativeWindowType native_window = fbCreateWindow(native_display, 0, 0, 0, 0);
display = eglGetDisplay(native_display);
#endif
if (display == EGL_NO_DISPLAY) {
g_print("Unable to open connection to Window system: 0x%x\n",eglGetError());
return 0; // <-- Point of failure, both with and without USE_PBUFFER set
}
// ...
if (!eglInitialize(display, &majorVersion, &minorVersion)) {
g_print("Unable to initialize Display: 0x%x\n",eglGetError());
return 0;
}
// ...
#ifdef USE_PBUFFER
surface = eglCreatePbufferSurface(display, config, surfaceAttribList);
#else
surface = eglCreateWindowSurface(display, config, native_display, surfaceAttribList);
#endif
当前内核配置的提取,基于 3.14.28
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
CONFIG_HDMI=y
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
# CONFIG_FB_BOOT_VESA_SUPPORT is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
CONFIG_FB_SYS_FILLRECT=m
CONFIG_FB_SYS_COPYAREA=m
CONFIG_FB_SYS_IMAGEBLIT=m
# CONFIG_FB_FOREIGN_ENDIAN is not set
CONFIG_FB_SYS_FOPS=m
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
#
# Frame buffer hardware drivers
#
# CONFIG_FB_IMX is not set
# CONFIG_FB_UVESA is not set
# CONFIG_FB_OPENCORES is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_TMIO is not set
# CONFIG_FB_SMSCUFX is not set
# CONFIG_FB_UDL is not set
# CONFIG_FB_GOLDFISH is not set
CONFIG_FB_VIRTUAL=m
# CONFIG_FB_METRONOME is not set
CONFIG_FB_MX3=y
# CONFIG_FB_BROADSHEET is not set
# CONFIG_FB_AUO_K190X is not set
# CONFIG_FB_MXS is not set
# CONFIG_FB_SIMPLE is not set
# CONFIG_EXYNOS_VIDEO is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
CONFIG_FB_MXC=y
# CONFIG_FB_MXC_SYNC_PANEL is not set
CONFIG_FB_MXC_EDID=y
# CONFIG_FB_MXC_EINK_PANEL is not set
2015-09-24更新:
好吧,作为解决问题的第一步,我们将正确的 MXC 帧缓冲驱动程序添加到内核和设备树中,但我们仍然不断收到 EGL_BAD_ALLOC 错误(无论是否将 x11 和 wayland 添加到图像中).我们使用以下内核命令行:
[..] video=mxcfb0:dev=hdmi,1920x1080M@60,if=RGB24 gpumem=64M fbmem=32M,32M [..]
此外,设备文件 /dev/fb0
和 /dev/fb1
已正确创建并在 /sys/class/graphics/fb0
上输出。 fb1
看起来合理(即与我的台式电脑和氮气参考板相同)
好的,您 运行 遇到的问题是,您正试图打开一个 "native" 显示,它期望在某种显示设备上显示 运行 .显然,这不适用于无头系统。
由于您使用的是 EGL,因此您需要某种 "display" 特定版本的 EGL 知道如何与之交谈。但是,您删除了所有可以解决问题的内容 (DISTRO_FEATURES_remove = " x11 wayland"
)。事情是这样的:
你完全是 overthinking/overengineering 的全部;假设有适当的 Wayland 支持。
如果您可以使用 Wayland,而不是做 "render to FBO with texture/renderbuffer attached then glReadPixels" 舞蹈,您可以实现 VNC Wayland 系统合成器,即提供由 VNC(或您使用 RealVNC http://www.realvnc.com/products/vnc/wayland/ 的现有实现)。由于 Wayland 协议本身与 GPU 无关,这允许您的应用程序使用 GPU,而图形输出将通过作为合成器的 VNC 服务器重定向到 VNC 服务器。
根据 https://community.freescale.com/thread/375384,这是 3.14.28 内核和 imx6 处理器的 Vivante 库之间的兼容性问题。因此,解决方案是回到另一个内核版本。
在我们的项目中,我们希望使用 Freescale iMX6Q ARM 处理器的 GPU 渲染图像,然后通过 gstreamer 管道写入 VNC 服务器。 顺序如下:
- 初始化 OpenGL
- 对于视频流的每一帧:
- 使用 OpenGL ES 将图像渲染为使用帧缓冲区和 渲染缓冲区
- 使用
glReadPixels()
读取图像像素
- 将图像数据复制到视频帧
- 推帧到视频流
我们使用 Yocto 1.8 作为构建系统,初始化序列下方的源代码适用于我们的 nitrogen6X-lite 原型板(定义了 USE_PBUFFER
),但不适用于我们的无头生产板。在生产板上我们无法初始化 "display":无论是否定义了 USE_PBUFFER
,我们都会得到一个 0x3003 EGL_BAD_ALLOC
错误。我们有 vfb
内核模块加载了 vfb_enable=1
和 video=vfb
内核选项。开发文件 /dev/fb0
创建成功。在 yocto 中,我们尝试了默认模式下的 fsl-image-multimedia-full
、image-core
和 image-core-directfb
图像,以及
DISTRO_FEATURES_remove = " x11 wayland"
DISTRO_FEATURES_append = " directfb"
在我们的 conf/local.conf
文件中。
我们应该如何在嵌入式 Linux 设置中使用 iMX 处理器的 GPU 在没有显示器的情况下进行离屏渲染?什么是合适的内核设置?什么是合适的 user-space 使用的功能?
当前用户-space OpenGL 初始化序列的实现:
EGLDisplay display;
EGLSurface surface;
#ifdef USE_PBUFFER
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
#else
int fbnum = 0; // fbnum is an integer for /dev/fb0 fbnum = 0
EGLNativeDisplayType native_display = fbGetDisplayByIndex(fbnum);
EGLNativeWindowType native_window = fbCreateWindow(native_display, 0, 0, 0, 0);
display = eglGetDisplay(native_display);
#endif
if (display == EGL_NO_DISPLAY) {
g_print("Unable to open connection to Window system: 0x%x\n",eglGetError());
return 0; // <-- Point of failure, both with and without USE_PBUFFER set
}
// ...
if (!eglInitialize(display, &majorVersion, &minorVersion)) {
g_print("Unable to initialize Display: 0x%x\n",eglGetError());
return 0;
}
// ...
#ifdef USE_PBUFFER
surface = eglCreatePbufferSurface(display, config, surfaceAttribList);
#else
surface = eglCreateWindowSurface(display, config, native_display, surfaceAttribList);
#endif
当前内核配置的提取,基于 3.14.28
# CONFIG_VGASTATE is not set
# CONFIG_VIDEO_OUTPUT_CONTROL is not set
CONFIG_HDMI=y
CONFIG_FB=y
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB_DDC is not set
# CONFIG_FB_BOOT_VESA_SUPPORT is not set
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
CONFIG_FB_SYS_FILLRECT=m
CONFIG_FB_SYS_COPYAREA=m
CONFIG_FB_SYS_IMAGEBLIT=m
# CONFIG_FB_FOREIGN_ENDIAN is not set
CONFIG_FB_SYS_FOPS=m
# CONFIG_FB_SVGALIB is not set
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_BACKLIGHT is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
#
# Frame buffer hardware drivers
#
# CONFIG_FB_IMX is not set
# CONFIG_FB_UVESA is not set
# CONFIG_FB_OPENCORES is not set
# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_TMIO is not set
# CONFIG_FB_SMSCUFX is not set
# CONFIG_FB_UDL is not set
# CONFIG_FB_GOLDFISH is not set
CONFIG_FB_VIRTUAL=m
# CONFIG_FB_METRONOME is not set
CONFIG_FB_MX3=y
# CONFIG_FB_BROADSHEET is not set
# CONFIG_FB_AUO_K190X is not set
# CONFIG_FB_MXS is not set
# CONFIG_FB_SIMPLE is not set
# CONFIG_EXYNOS_VIDEO is not set
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
CONFIG_FB_MXC=y
# CONFIG_FB_MXC_SYNC_PANEL is not set
CONFIG_FB_MXC_EDID=y
# CONFIG_FB_MXC_EINK_PANEL is not set
2015-09-24更新: 好吧,作为解决问题的第一步,我们将正确的 MXC 帧缓冲驱动程序添加到内核和设备树中,但我们仍然不断收到 EGL_BAD_ALLOC 错误(无论是否将 x11 和 wayland 添加到图像中).我们使用以下内核命令行:
[..] video=mxcfb0:dev=hdmi,1920x1080M@60,if=RGB24 gpumem=64M fbmem=32M,32M [..]
此外,设备文件 /dev/fb0
和 /dev/fb1
已正确创建并在 /sys/class/graphics/fb0
上输出。 fb1
看起来合理(即与我的台式电脑和氮气参考板相同)
好的,您 运行 遇到的问题是,您正试图打开一个 "native" 显示,它期望在某种显示设备上显示 运行 .显然,这不适用于无头系统。
由于您使用的是 EGL,因此您需要某种 "display" 特定版本的 EGL 知道如何与之交谈。但是,您删除了所有可以解决问题的内容 (DISTRO_FEATURES_remove = " x11 wayland"
)。事情是这样的:
你完全是 overthinking/overengineering 的全部;假设有适当的 Wayland 支持。
如果您可以使用 Wayland,而不是做 "render to FBO with texture/renderbuffer attached then glReadPixels" 舞蹈,您可以实现 VNC Wayland 系统合成器,即提供由 VNC(或您使用 RealVNC http://www.realvnc.com/products/vnc/wayland/ 的现有实现)。由于 Wayland 协议本身与 GPU 无关,这允许您的应用程序使用 GPU,而图形输出将通过作为合成器的 VNC 服务器重定向到 VNC 服务器。
根据 https://community.freescale.com/thread/375384,这是 3.14.28 内核和 imx6 处理器的 Vivante 库之间的兼容性问题。因此,解决方案是回到另一个内核版本。