Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
654 views
in Technique[技术] by (71.8m points)

c++ - SDL2 on Raspberry Pi without X?

I'm hoping to develop some code that uses SDL2 to display graphics on the 7" RPi touchscreen, but I'd rather not install a full desktop OS. I've got Raspbian Buster Lite installed. Some simple test code gets an error when I try to run it:

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

I'm trying to create the window with

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

I found a post that referenced instructions on how to build SDL2 without X, but I was hoping someone could educate me a bit more about how SDL finds the display in various environments, and if it’s even possible to do what I want to do.

A few years ago I used SDL 1.2 to do full-screen graphics on a Beaglebone Black running a version of Debian, but I seem to have lost that installation, and don’t remember how it was set up. I vaguely recall some issues around fbdev and it being non-accelerated graphics, but that didn’t matter at the time (and while I’d like to get accelerated graphics now, it’s not critical).

Example code:

/*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
", 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
", 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;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Alrighty, got it working on my Raspberry Pi 3 with 2019-07-10-raspbian-buster-lite.img, both with the default Broadcom blobs & the KMS/DRM backend:

  1. Install SDL2 build dependencies:

     # install everything Debian uses to build SDL
     sudo apt build-dep libsdl2
    
     # needed for the KMSDRM backend:
     sudo apt install libdrm-dev libgbm-dev
    
  2. Grab the latest stable SDL source tarball or tag (release-2.0.10) from Mercurial/Git and extract it somewhere like ~/sdl-src

  3. Run SDL's configure script:

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

    Here's my configure summary, note the rpi and kmsdrm(dynamic) entries in the Video drivers list:

     SDL2 Configure Summary:
     Building Shared Libraries
     Building Static Libraries
     Enabled modules : atomic audio video render events joystick haptic sensor power filesystem threads timers file loadso cpuinfo assembly
     Assembly Math   :
     Audio drivers   : disk dummy oss alsa(dynamic) pulse(dynamic) sndio(dynamic)
     Video drivers   : dummy rpi x11(dynamic) kmsdrm(dynamic) opengl opengl_es1 opengl_es2 vulkan wayland(dynamic)
     X11 libraries   : xcursor xdbe xinerama xinput2 xinput2_multitouch xrandr xscrnsaver xshape xvidmode
     Input drivers   : linuxev linuxkd
     Using libsamplerate : YES
     Using libudev       : YES
     Using dbus          : YES
     Using ime           : YES
     Using ibus          : YES
     Using fcitx         : YES
    
  4. Build & install SDL; took ~4.5 minutes on my Rpi3:

     make -j4 && sudo make install
    
  5. Build test program:

     g++ main.cpp `pkg-config --cflags --libs sdl2`
    
  6. (Optional) Enable the "Full KMS" driver if you want to use the KMSDRM backend instead of the default OpenGL ES blobs:

     $ sudo raspi-config
     select '7 Advanced Options'
     select 'A7 GL Driver'
     select 'G3 GL (Full KMS)'
     reboot
    
  7. Run test program:

     $ ./a.out 
     Testing video drivers...
     The path /dev/dri/ cannot be opened or is not available
     The path /dev/dri/ cannot be opened or is not available
     SDL_VIDEODRIVER available: x11 wayland KMSDRM RPI dummy
     SDL_VIDEODRIVER usable   : RPI
     The path /dev/dri/ cannot be opened or is not available
     The path /dev/dri/ cannot be opened or is not available
     SDL_VIDEODRIVER selected : RPI
     SDL_RENDER_DRIVER available: opengl opengles2 opengles software
     SDL_RENDER_DRIVER selected : opengles2
    

    You can use environment variables to override the default video/render driver selection:

     SDL_VIDEODRIVER=KMSDRM SDL_RENDER_DRIVER=software ./a.out
    

    I had to hold SDL's hand a bit with envvars to get the KMSDRM backend to load:

     # no envvars, fails:
     $ ./a.out 
     Testing video drivers...
     SDL_VIDEODRIVER available: x11 wayland KMSDRM RPI dummy
     SDL_VIDEODRIVER usable   : KMSDRM
     SDL_VIDEODRIVER selected : KMSDRM
     SDL_CreateWindow(): Could not initialize OpenGL / GLES library
    
     # with envvars, succeeds:
     $ SDL_VIDEO_EGL_DRIVER=libEGL.so SDL_VIDEO_GL_DRIVER=libGLESv2.so ./a.out
     Testing video drivers...
     SDL_VIDEODRIVER available: x11 wayland KMSDRM RPI dummy
     SDL_VIDEODRIVER usable   : KMSDRM
     SDL_VIDEODRIVER selected : KMSDRM
     SDL_RENDER_DRIVER available: opengl opengles2 opengles software
     SDL_RENDER_DRIVER selected : opengl
    

Here's the test program I've been using:

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

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

    std::cout << "Testing video drivers..." << '
';
    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 << '
';

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

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

    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() << '
';
        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 << '
';

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

    bool running = true;
    unsigned char i = 0;
    while( running )
    {
        SDL_Event ev;
        while( SDL_PollEvent( &ev ) )
        {
            if( ( ev.type == SDL_QUIT ) ||
                ( ev.type == SDL_KEYDOWN && ev.key.keysym.sym == SDLK_ESCAPE ) )
            {
                running = false;
            }
        }

        SDL_SetRenderDrawColor( renderer, i, i, i, SDL_ALPHA_OPAQUE );
        SDL_RenderClear( renderer );
        SDL_RenderPresent( renderer );
        i++;
    }

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...