树莓派上如何在没有X的情况下安装SDL2?

19

我希望开发一些使用SDL2在7英寸RPi触摸屏上显示图形的代码,但我不想安装完整的桌面操作系统。我已经安装了Raspbian Buster Lite。当我尝试运行一些简单的测试代码时,会出现错误:

user@rpi4:~/01_hello_SDL $ ./hw
Window could not be created! SDL_Error: Could not initialize EGL
user@rpi4:~/01_hello_SDL $ sudo ./hw
error: XDG_RUNTIME_DIR not set in the environment.
Window could not be created! SDL_Error: Could not initialize EGL

我正在尝试创建窗口

SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL )

我找到了一篇文章,其中提到了如何在不使用X的情况下构建SDL2的说明,但是我希望有人可以更详细地告诉我SDL在各种环境中如何找到显示器,以及是否可能做到我想要做的事情。

几年前,我使用SDL 1.2在运行Debian版本的Beaglebone Black上进行全屏图形处理,但是我似乎已经失去了那个安装文件,并且不记得它是如何设置的。我依稀记得在fbdev周围存在一些问题,它不是加速图形,但那时无关紧要(尽管我现在希望获得加速图形,但这并不是关键)。

示例代码:

/*This source code copyrighted by Lazy Foo' Productions (2004-2019)
and may not be redistributed without written permission.*/

//Using SDL and standard IO
#include <SDL.h>
#include <stdio.h>

//Screen dimension constants
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 480;

int main( int argc, char* args[] )
{
    //The window we'll be rendering to
    SDL_Window* window = NULL;
    
    //The surface contained by the window
    SDL_Surface* screenSurface = NULL;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
    }
    else
    {
        //Create window
        window = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL );
        if( window == NULL )
        {
            printf( "Window could not be created! SDL_Error: %s\n", SDL_GetError() );
        }
        else
        {
            //Get window surface
            screenSurface = SDL_GetWindowSurface( window );

            //Fill the surface white
            SDL_FillRect( screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0xFF, 0xFF, 0xFF ) );
            
            //Update the surface
            SDL_UpdateWindowSurface( window );

            //Wait two seconds
            SDL_Delay( 2000 );
        }
    }

    //Destroy window
    SDL_DestroyWindow( window );

    //Quit SDL subsystems
    SDL_Quit();

    return 0;
}

1
如果您只需要将视频/图形输出到屏幕上而不需要鼠标或菜单,您可以使用fb设备,并在不到1毫秒的时间内更新整个1024x768屏幕... 在Raspi 4上,fb设备会自动以“DRM模拟”方式启动,无需进行任何特殊操作。 - Mark Setchell
1个回答

27
好的,我已经在我的Raspberry Pi 3上成功运行了2019-07-10-raspbian-buster-lite.img,同时使用了默认的Broadcom blobsKMS/DRM后端。
  1. 安装SDL2的构建依赖项:

    # 安装Debian用于构建SDL的所有内容
    sudo apt build-dep libsdl2
    
    # KMSDRM后端所需:
    sudo apt install libdrm-dev libgbm-dev
    
  2. 获取最新稳定版的SDL源代码压缩包或标签(release-2.0.10)从Git并将其解压到某个位置,如~/sdl-src

  3. 运行SDL的configure脚本:

    cd ~/sdl-src
    ./configure --enable-video-kmsdrm
    

    这是我的configure摘要:

    SDL2 Configure Summary:
    构建共享库
    构建静态库
    启用模块:atomic audio video render events joystick haptic sensor power filesystem threads timers file loadso cpuinfo assembly
    Assembly Math   :
    音频驱动程序   : disk dummy oss alsa(dynamic) pulse(dynamic) sndio(dynamic)
    视频驱动程序   : dummy rpi x11(dynamic) kmsdrm(dynamic) opengl opengl_es1 opengl_es2 vulkan wayland(dynamic)
    X11库   : xcursor xdbe xinerama xinput2 xinput2_multitouch xrandr xscrnsaver xshape xvidmode
    输入驱动程序   : linuxev linuxkd
    使用libsamplerate : YES
    使用libudev       : YES
    使用dbus          : YES
    使用ime           : YES
    使用ibus          : YES
    使用fcitx         : YES
    

    请注意Video drivers列表中的rpikmsdrm(dynamic)条目:

    视频驱动程序   : dummy rpi x11(dynamic) kmsdrm(dynamic) opengl opengl_es1 opengl_es2 vulkan wayland(dynamic)
                            ^^^              ^^^^^^^^^^^^^^^
    
  4. 构建并安装SDL;在我的Rpi3上花费了约4.5分钟:

    make -j4 && sudo make install
    
  5. 构建测试程序:

    g++ main.cpp `pkg-config --cflags --libs sdl2`
    
  6. (可选)如果您想使用KMSDRM后端而不是默认的OpenGL ES blob,请启用“Full KMS”驱动程序:

    $ sudo raspi-config
    选择“7 Advanced Options”
    选择“A7 GL Driver”
    选择“G3 GL (Full KMS)”
    重新启动
    
  7. 运行测试程序:

    $ ./a.out 
    测试视频驱动程序...
    无法打开路径/dev/dri/或路径不可用
    无法打开路径/dev/dri/或路径不可用
    SDL_VIDEODRIVER可用:x11 wayland KMSDRM RPI dummy
    SDL_VIDEODRIVER可用   :RPI
    无法打开路径/dev/dri/或路径不可用
    无法打开路径/dev/dri/或路径不可用
    SDL_VIDEODRIVER已选择:RPI
    SDL_RENDER_DRIVER可用:opengl opengles2 opengles software
    SDL_RENDER_DRIVER已选择:opengles2
    

    您可以使用环境变量来覆盖默认的视频/渲染驱动程序选择:

    SDL_VIDEODRIVER=KMSDRM SDL_RENDER_DRIVER=software ./a.out
    

    我需要使用环境变量来手动加载KMSDRM后端:

    # 没有环境变量,失败:
    $ ./a.out 
    测试视频驱动程序...
    SDL_VIDEODRIVER可用:x11 wayland KMSDRM RPI dummy
    SDL_VIDEODRIVER可用   :KMSDRM
    SDL_VIDEODRIVER已选择:KMSDRM
    SDL_CreateWindow(): Could not initialize OpenGL / GLES library
    
    # 使用环境变量,成功:
    $ SDL_VIDEO_EGL_DRIVER=libEGL.so SDL_VIDEO_GL_DRIVER=libGLESv2.so ./a.out
    测试视频驱动程序...
    SDL_VIDEODRIVER可用:x11 wayland KMSDRM RPI dummy
    SDL_VIDEODRIVER可用   :KMSDRM
    SDL_VIDEODRIVER已选择:KMSDRM
    SDL_RENDER_DRIVER可用:opengl opengles2 opengles software
    SDL_RENDER_DRIVER已选择:opengl
    
这是我一直在使用的测试程序:
// g++ main.cpp `pkg-config --cflags --libs sdl2`
#include <SDL.h>
#include <iostream>
#include <vector>

int main( int argc, char** argv )
{
    SDL_Init( 0 );

    std::cout << "Testing video drivers..." << '\n';
    std::vector< bool > drivers( SDL_GetNumVideoDrivers() );
    for( int i = 0; i < drivers.size(); ++i )
    {
        drivers[ i ] = ( 0 == SDL_VideoInit( SDL_GetVideoDriver( i ) ) );
        SDL_VideoQuit();
    }

    std::cout << "SDL_VIDEODRIVER available:";
    for( int i = 0; i < drivers.size(); ++i )
    {
        std::cout << " " << SDL_GetVideoDriver( i );
    }
    std::cout << '\n';

    std::cout << "SDL_VIDEODRIVER usable   :";
    for( int i = 0; i < drivers.size(); ++i )
    {
        if( !drivers[ i ] ) continue;
        std::cout << " " << SDL_GetVideoDriver( i );
    }
    std::cout << '\n';

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

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

    std::cout << "SDL_RENDER_DRIVER available:";
    for( int i = 0; i < SDL_GetNumRenderDrivers(); ++i )
    {
        SDL_RendererInfo info;
        SDL_GetRenderDriverInfo( i, &info );
        std::cout << " " << info.name;
    }
    std::cout << '\n';

    SDL_Renderer* renderer = SDL_CreateRenderer(
        window,
        -1,
        SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC );
    if( nullptr == renderer )
    {
        std::cerr << "SDL_CreateRenderer(): " << SDL_GetError() << '\n';
        return EXIT_FAILURE;
    }
    SDL_RendererInfo info;
    SDL_GetRendererInfo( renderer, &info );
    std::cout << "SDL_RENDER_DRIVER selected : " << info.name << '\n';

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

        static int dir = 1;
        static int i = 0;
        i += dir;
        if( i > 255 ) { i = 255; dir = -1; }
        if( i < 0 ) { i = 0; dir = 1; }
        SDL_SetRenderDrawColor( renderer, i, i, i, SDL_ALPHA_OPAQUE );

        SDL_RenderClear( renderer );
        SDL_RenderPresent( renderer );
    }

    SDL_DestroyRenderer( renderer );
    SDL_DestroyWindow( window );
    SDL_Quit();

    return 0;
}

所以,我选择了假的KMS并按照您上面的步骤运行。启用KMS更改了错误消息,设置SDL_VIDEO_[E]GL_DRIVER使其能够无误地执行。现在,我使用我的代码在左上角获得了两秒钟的鼠标指针,但没有我预期的白屏。 - Rick
看起来这个发行版在树莓派4上缺乏KMS支持。 - Rick
1
@Rick:别担心。'默认 blob 驱动程序' 应该是 raspi-config 中的 7 Advanced Options -> A7 GL Driver 列表中的第一项,也是 Raspbian Buster 镜像开箱即用的选项。 - genpfault
@OmarL:可能需要*-dev包来支持rpi驱动程序,你的完整configure输出是什么样子的?我会扫描它以查找失败的功能检查,然后将其与configure.log中的测试编译输出进行交叉参考。 - genpfault
我得在最新的树莓派操作系统Lite上工作。屏幕闪烁得很快,但那是因为颜色增加得太快了(帧速率)。 - Arnaud Loonstra
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接