Can't create SDL2 window under X11 without root permissions (FreeBSD 13.1)

Hello, I'm trying to run a minimal SDL2 window under X11.
When binary is run with sudo, it works.
With standard user permissions, I get an "Inappropriate ioctl for device".
My test user is in the "video" group.

Does someone know why ?
Thanks for your help.

Makefile:
CC = clang++
CFLAGS = -g -std=c++17 -Wunused-variable
drm_cflags = -I/usr/local/include/SDL2 -I/usr/local/include -L/usr/local/lib

targets = sdltest


all: $(targets)

sdltest: sdltest.cpp
    $(CC) $(CFLAGS) $(drm_cflags) -o $@ $^ -lncursesw -lSDL2


.PHONY: clean
clean:
    $(RM) *.o
    $(RM) $(targets)

C++:
#include <SDL.h>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <curses.h>
#include <iostream>
#include <fstream>


// #define DRIVER_NAME "KMSDRM"
#define DRIVER_NAME "x11"
// #define DRIVER_NAME "directfb"
// #define DRIVER_NAME "wayland"

SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
WINDOW *win = NULL;
std::ofstream logger("log.txt");


void freeIfNeeded(SDL_Window *window, SDL_Renderer *renderer, WINDOW *win)
{
    if (renderer) SDL_DestroyRenderer(renderer);
    if (window) SDL_DestroyWindow(window);
    if (win) endwin();
    logger.close();
}


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

    int ch;
    win = initscr();
    nodelay(win, true);
    noecho();

    SDL_Init(0);

    // Find the driver
    bool init = false;
    for (int i = 0; i < SDL_GetNumVideoDrivers(); i++) {
        const char *name = SDL_GetVideoDriver(i);
        if (strcmp(name, DRIVER_NAME) == 0) {
            SDL_VideoInit(name);
            init = true;
            break;
        }
    }
    if (!init) {
        perror("Couldn't find a suitable video driver !");
        logger << "Couldn't find a suitable video driver !" << std::endl;
        freeIfNeeded(window, renderer, win);
        return -1;
    }

    // logger << "SDL Video Driver selected :" << SDL_GetCurrentVideoDriver() << std::endl;

    SDL_Init(SDL_INIT_EVERYTHING);

    window = SDL_CreateWindow(
            "sdl",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            640,
            480,
            SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_SHOWN);

    if (window == nullptr) {
        perror("Could not create window !");
        logger << "Could not create window !" << std::endl;
        freeIfNeeded(window, renderer, win);
        return -1;
    }

    // select resolution and refresh rate of the main window
    // i915 kmsdrm : rgba order
    const SDL_DisplayMode mode = { SDL_PIXELTYPE(SDL_PIXELTYPE_ARRAYU32), 640, 480, 75, 0 };
    SDL_SetWindowDisplayMode(window, &mode);

    for (int i = 0; i < SDL_GetNumRenderDrivers(); i++) {
        SDL_RendererInfo info;
        SDL_GetRenderDriverInfo(i, &info);
        logger << "Renderer[" << i << "]=" << info.name << std::endl;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (renderer == nullptr) {
        perror("Could not create renderer !");
        logger << "Could not create renderer !" << std::endl;
        freeIfNeeded(window, renderer, win);
        return -1;
    }

    SDL_RendererInfo rendererInfo;
    SDL_GetRendererInfo(renderer, &rendererInfo);
    logger << "Current renderer" << rendererInfo.name << std::endl;

    SDL_ShowCursor(false);
    SDL_RenderClear(renderer);

    bool loop = true;
    int i = 0;
    while (loop) {

        SDL_Event event;
        while(SDL_PollEvent(&event) != 0) {

            if (event.type == SDL_QUIT) {
                loop = false;
            }

        }

        // KMSDRM : without window manager, keyboard events must be read on term
        // curses keyboard management
        ch = getch();
        if (ch == 'q') {
            loop = false;
        }

        SDL_SetRenderDrawColor(renderer, 0x00, 0x80, 0x80, 0xFF);
        SDL_RenderClear(renderer);

        if (i % 2 == 0)
            SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
        else
            SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF);

        SDL_RenderDrawLine(renderer, 0, 0, 640, 480);
        SDL_RenderPresent(renderer);
        SDL_Delay(20);

        i++;
    }

    freeIfNeeded(window, renderer, win);
    SDL_Quit();
}
 
I couldn't used your code 1:1, I had to adjust the Makefile a bit:
Code:
    $(CC) $(CFLAGS) $(drm_cflags) -o $@ sdltest.cpp
without it I ran into the linking issue:
Code:
clang++ -g -std=c++17 -Wunused-variable -I/usr/local/include/SDL2 -I/usr/local/include -L/usr/local/lib -lncursesw -lSDL2 -o sdltest
ld: error: undefined symbol: main
>>> referenced by crt1_c.c:75 (/usr/src/lib/csu/amd64/crt1_c.c:75)
>>>               /usr/lib/crt1.o:(_start)
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
*** Error code 1
Also make clean doesn't work properly as there's no object files created the whole clean stops on error (rm -f would help).

Anyway, with that change I was able to execute it as normal user, window got displayed with one horizontal, flickering line.
 
Thanks for your reply.
The compilation error with this Makefile is probably due to the make binary used. I use gmake and not the default freebsd make.
Could you tell me which FreeBSD version you are using ?
 
After googling, I found a workaround by setting an environment variable.
export SDL_VIDEODRIVER=x11
I thought that the 'SDL_VideoInit("x11")' would be sufficient.
Could you tell me if SDL_VIDEODRIVER is set on your user ?
 
I'm on a generic 13.1-RELEASE-p2, with
Code:
# pkg info sdl\*
sdl-1.2.15_15,2
sdl2-2.24.0_1
User has no special env set
Code:
$ env|grep -i sdl
$
 
Thanks. I've forgot I set this var in my profile:
Code:
export SDL_VIDEODRIVER=kmsdrm
By unsetting it, it works.
 
Back
Top