问题
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\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:
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:
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
Grab the latest stable SDL source tarball or tag (release-2.0.10) from Mercurial/Git and extract it somewhere like
~/sdl-src
Run SDL's configure script:
cd ~/sdl-src ./configure --enable-video-kmsdrm
Here's my
configure
summary, note therpi
andkmsdrm(dynamic)
entries in theVideo 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
Build & install SDL; took ~4.5 minutes on my Rpi3:
make -j4 && sudo make install
Build test program:
g++ `pkg-config --cflags --libs sdl2` main.cpp
(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
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..." << '\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 );
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;
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;
}
来源:https://stackoverflow.com/questions/57672568/sdl2-on-raspberry-pi-without-x