如果没有连接 HDMI 设备,没有 X 的 SDL2 显示 'Segmentation fault'

SDL2 without X show 'Segmentation fault' if no HDMI device connected

我想做一个非常简单的电视面板测试仪。有了这个 answer about SDL2 without X 我可以用 Raspberry Pi 零准备这样的测试仪,而且效果很好。 虽然 运行ning 我可以在电视之间切换电缆,但我在测试的电视上有非常快的绿屏。 然而,当我 运行 在没有连接任何 HDMI 设备的情况下编程时,我有 分段错误

这是代码:

#include <SDL.h>
#include <iostream>

int main( int argc, char** argv )
{

    if( SDL_Init( SDL_INIT_EVERYTHING ) < 0 )
    {
        std::cerr << "SDL_Init(): " << SDL_GetError() << '\n';
        return EXIT_FAILURE;
    }

    SDL_Window* window = SDL_CreateWindow
        (
        "SDL2",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
        1920, 1080,
        SDL_WINDOW_SHOWN
        );
    if( nullptr == window )
    {
        std::cerr << "SDL_CreateWindow(): " << SDL_GetError() << '\n';
        return EXIT_FAILURE;
    }

    SDL_Renderer* renderer = SDL_CreateRenderer( window, -1, SDL_RENDERER_ACCELERATED );
    if( nullptr == renderer )
    {
        std::cerr << "SDL_CreateRenderer(): " << SDL_GetError() << '\n';
        return EXIT_FAILURE;
    }

    bool running = true;
    while( running )
    {
        SDL_Event ev;
        while( SDL_PollEvent( &ev ))
        {
            if( ev.type == SDL_QUIT )
            {
                running = false;
            }
        }

        SDL_SetRenderDrawColor( renderer, 0x00, 0xff, 0x00, SDL_ALPHA_OPAQUE );
        SDL_RenderClear( renderer );
        SDL_RenderPresent( renderer );
    }

    SDL_DestroyRenderer( renderer );
    SDL_DestroyWindow( window );
    SDL_Quit();
    return 0;
}

strace本节目到此结束:

close(5)                                = 0
openat(AT_FDCWD, "/usr/share/drirc.d/00-mesa-defaults.conf", O_RDONLY|O_LARGEFILE) = 5
read(5, "<?xml version=\"1.0\" standalone=\""..., 4096) = 4096
getrandom("\x26\x27\xac\x36", 4, GRND_NONBLOCK) = 4
read(5, ">\n\n        <application name=\"Un"..., 4096) = 4096
read(5, "_glsl_abs_sqrt\" value=\"true\" />\n"..., 4096) = 4096
read(5, "ation>\n\n        <application nam"..., 4096) = 4096
read(5, "daptive_sync\" value=\"false\" />\n "..., 4096) = 4096
read(5, "ation>\n        <application name"..., 4096) = 4096
read(5, "executable=\"dota2\">\n            "..., 4096) = 1062
read(5, "", 4096)                       = 0
close(5)                                = 0
openat(AT_FDCWD, "/etc/drirc", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/home/pi/.drirc", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
ioctl(4, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb98e0) = 0
fcntl64(4, F_DUPFD_CLOEXEC, 3)          = 5
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb9860) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb9860) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb9860) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb9860) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb9860) = 0
ioctl(5, DRM_IOCTL_GET_CAP, 0xbecb9860) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb9898) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb98a8) = 0
gettimeofday({tv_sec=1582731761, tv_usec=164921}, NULL) = 0
openat(AT_FDCWD, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC) = 6
read(6, "0\n", 8192)                    = 2
close(6)                                = 0
openat(AT_FDCWD, "/proc/self/auxv", O_RDONLY|O_LARGEFILE|O_CLOEXEC) = 6
read(6, "[=12=][=12=][=12=]61[=12=][=12=]", 8)     = 8
close(6)                                = 0
futex(0xb5f4e3d0, FUTEX_WAKE_PRIVATE, 2147483647) = 0
ioctl(5, DRM_IOCTL_TEGRA_GET_SYNCPT_BASE or DRM_IOCTL_VC4_GET_TILING, 0xbecb9860) = -1 ENOENT (No such file or directory)
ioctl(3, DRM_IOCTL_GET_CAP, 0xbecb9910) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb8cf0) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb8cf0) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb8cf0) = 0
ioctl(5, DRM_IOCTL_AMDGPU_GEM_WAIT_IDLE or DRM_IOCTL_EXYNOS_VIDI_CONNECTION or DRM_IOCTL_TEGRA_GET_SYNCPT or DRM_IOCTL_VC4_GET_PARAM or DRM_IOCTL_VIA_DMA_INIT, 0xbecb8cf0) = 0
ioctl(3, DRM_IOCTL_MODE_GETRESOURCES, 0xbecba340) = 0
ioctl(3, DRM_IOCTL_MODE_GETRESOURCES, 0xbecba340) = 0
ioctl(3, DRM_IOCTL_MODE_GETCONNECTOR, 0xbecba2f0) = 0
ioctl(3, DRM_IOCTL_MODE_GETCONNECTOR, 0xbecba2f0) = 0
ioctl(3, DRM_IOCTL_MODE_GETCONNECTOR, 0xbecba2f0) = 0
ioctl(3, DRM_IOCTL_MODE_GETCONNECTOR, 0xbecba2f0) = 0
close(5)                                = 0
close(4)                                = 0
munmap(0xb50af000, 17353000)            = 0
munmap(0xb14ea000, 115624)              = 0
munmap(0xb14cf000, 106672)              = 0
munmap(0xb14a5000, 168220)              = 0
munmap(0xb148d000, 94536)               = 0
munmap(0xb1476000, 90356)               = 0
close(3)                                = 0
--- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x4} ---
+++ killed by SIGSEGV +++
Segmentation fault

这是config.txt hdmi_和显示相关的部分:

framebuffer_width=1920
framebuffer_height=1080
hdmi_force_hotplug=1
hdmi_ignore_edid=0xa5000080
hdmi_edid_file=1
hdmi_ignore_edid_audio=1
hdmi_force_edid_3d=1
hdmi_ignore_cec_init=1
hdmi_ignore_cec=1
hdmi_pixel_encoding=2
hdmi_blanking=0
edid_content_type=0
hdmi_group=1
hdmi_mode=16
hdmi_force_mode=1
dtoverlay=vc4-kms-v3d

我该如何解决这个问题?

在连接第一台设备之前,我可以运行作为虚拟 HDMI 输出吗?

因为我想让这个测试仪成为无头自动启动设备,因为它会在连接任何 HDMI 输出之前打开(因为启动 rPi-Zero 很慢 - 即使是简约版本)。

[编辑]

来自full version of sample app的输出:

Testing video drivers...
SDL_VIDEODRIVER available: x11 KMSDRM RPI dummy
SDL_VIDEODRIVER usable   : KMSDRM
SDL_VIDEODRIVER selected : KMSDRM
SDL_RENDER_DRIVER available: opengles2 opengles software
SDL_RENDER_DRIVER selected : opengles2

这是我从 gdb 得到的:

Starting program: /home/pi/hdmitester/minimal
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/arm-linux-gnueabihf/libthread_db.so.1".
[New Thread 0xb6a8d450 (LWP 645)]

Thread 1 "minimal" received signal SIGSEGV, Segmentation fault.
KMSDRM_VideoQuit (_this=<optimized out>) at /usr/src/SDL/src/video/kmsdrm/SDL_kmsdrmvideo.c:665
665         if (dispdata->conn) {
(gdb) bt
#0  KMSDRM_VideoQuit (_this=<optimized out>) at /usr/src/SDL/src/video/kmsdrm/SDL_kmsdrmvideo.c:665
#1  0xb6f40174 in SDL_VideoQuit_REAL () at /usr/src/SDL/src/video/SDL_video.c:2869
#2  0xb6f40c38 in SDL_VideoQuit_REAL () at /usr/src/SDL/src/video/SDL_video.c:2853
#3  SDL_VideoInit_REAL (driver_name=<optimized out>) at /usr/src/SDL/src/video/SDL_video.c:533
#4  0xb6e9d63c in SDL_InitSubSystem_REAL (flags=62001) at /usr/src/SDL/src/SDL.c:206
#5  0x00010aac in main ()

正如@genpfault 在评论中指出的那样,SDL 版本。 2.0.10 解决了没有 HDMI 设备时的分段错误。 因此,如果有人使用 hg clone ...git clone ...,请确保在构建自己的版本之前切换到正确版本的 SDL2 源。