Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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

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

1 Answer

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;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...