SDL2 not able to read the current display mode after a display mode is changed via wlr-randr or arandr (for Wayland SDL_GetDisplayMode error: "index must be in the range of 0 - -1") #319
When I change the display mode using wlr-randr or arandr, it causes SDL2 applications to no longer be able to read the current display mode until they are restarted. The issue occurs both with the Wayland backend, where SDL_GetDisplayMode consistently returns the error:
index must be in the range of 0 - -1
and with the X11 backend, where SDL_GetDisplayMode starts returning the old mode, which does not match the actual one.
Steps to reproduce
1) sudo apt install libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev
2) Create test-vblank3.c and copy/paste code (see below)
3) Compile it with gcc -o test-vblank3 test-vblank3.c -Wall -lGL -lSDL2 -lSDL2_ttf -lSDL2_image
4) Run it with ./test-vblank3 --driver wayland
5) Run arandr and change video mode (for example refresh rate), or use wlr-randr (for example wlr-randr --output HDMI-A-1 --custom-mode 1280x1024@50Hz)
Expected result: SDL2 properly returns a new video mode
Actual result: For wayland backend SDL_GetDisplayMode fails with error. For x11 backend it returns incorrect video mode.
Screenshots
Test code
test-vblank3.c
```c
// sudo apt install libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev
// sudo pacman -S sdl2 sdl2_ttf sdl2_image
// gcc -o test-vblank3 test-vblank3.c -Wall -lGL -lSDL2 -lSDL2_ttf -lSDL2_image
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef _WIN32
#include
#define MAX_PATH_LENGTH MAX_PATH
#else
#include
#define MAX_PATH_LENGTH PATH_MAX
#endif
// Simple queue implementation
typedef struct {
uint64_t* data;
size_t front;
size_t rear;
size_t size;
size_t capacity;
} Queue64;
void queue_init(Queue64* q, size_t capacity) {
q->capacity = capacity;
q->size = 0;
q->front = 0;
q->rear = 0;
q->data = (uint64_t*)malloc(capacity * sizeof(uint64_t));
}
void queue_free(Queue64* q) {
free(q->data);
}
void queue_resize(Queue64* q, size_t new_capacity) {
if (new_capacity < q->size) {
printf("warn: queue_resize(): new capacity %zu is smaller than current size %zu. The last %zu elements will be discarded.\n", new_capacity, q->size, q->size - new_capacity);
q->size = new_capacity; // Truncate elements if the new size is smaller than the current size
}
uint64_t* new_data = (uint64_t*)malloc(new_capacity * sizeof(uint64_t));
// copy elements to a new buffer
for (size_t i = 0; i < q->size; i++) {
new_data[i] = q->data[(q->front + i) % q->capacity];
}
// Free the old buffer and update pointers
free(q->data);
q->data = new_data;
q->front = 0;
q->rear = q->size;
q->capacity = new_capacity;
}
void queue_enqueue(Queue64* q, uint64_t value) {
// If the queue is full, resize it
if (q->size == q->capacity) {
queue_resize(q, q->capacity * 2); // Double the capacity
}
// Add the element to the queue
q->data[q->rear] = value;
q->rear = (q->rear + 1) % q->capacity; // Circular move
q->size++;
}
uint64_t queue_dequeue(Queue64* q) {
if (q->size == 0) {
printf("error: queue_dequeue() failed: queue is empty\n");
return 0;
}
uint64_t value = q->data[q->front];
q->front = (q->front + 1) % q->capacity;
q->size--;
return value;
}
// Function to remove N oldest elements from the front of the queue
void queue_trimFront(Queue64* q, size_t n) {
if (n >= q->size) {
printf("warn: queue_trimFront(): trying to remove more elements (%zu) than the queue contains (%zu). Clearing the entire queue.\n", n, q->size);
q->front = 0; // Reset the front pointer
q->size = 0; // Reset the size
} else {
// Directly update the front pointer to remove N elements
q->front = (q->front + n) % q->capacity;
q->size -= n;
}
}
size_t queue_getSize(Queue64* q) {
return q->size;
}
uint64_t queue_getElement(Queue64* queue, int index) {
if (index < 0 || index >= queue->size) {
printf("error: queue_getElement() failed: index %d is out of bounds\n", index);
return 0; // or some default value for error
}
// Calculate the actual index in the circular queue
size_t actual_index = (queue->front + index) % queue->capacity;
return queue->data[actual_index];
}
Queue64 _queue;
uint64_t _frameCounter;
void fillRect(float x, float y, float w, float h) {
GLfloat vertices[] = { x, y + h, x + w, y + h, x + w, y, x, y };
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
//glDisableClientState(GL_VERTEX_ARRAY);
}
void fillTexturedRect(float x, float y, float w, float h) {
GLfloat vertices[] = { x, y + h, x + w, y + h, x + w, y, x, y };
GLfloat texCoords[] = { 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f };
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
//glDisableClientState(GL_TEXTURE_COORD_ARRAY);
//glDisableClientState(GL_VERTEX_ARRAY);
}
void drawLine(float x1, float y1, float x2, float y2) {
GLfloat vertices[2 * 2] = { x1,y1, x2,y2 };
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawArrays(GL_LINE_STRIP, 0, 2);
//glDisableClientState(GL_VERTEX_ARRAY);
}
void drawText(TTF_Font* font, const char* text, int x, int y, SDL_Color color) {
glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT);
glDisable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//TTF_SetFontOutline(font, outlineWidth);
SDL_Surface* surface = TTF_RenderText_Blended(font, text, color);
if (surface == NULL) {
glPopAttrib();
printf("TTF_RenderText_Blended() failed: %s\n", TTF_GetError());
return;
}
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->pitch / SDL_BYTESPERPIXEL(surface->format->format));
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surface->w, surface->h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, surface->pixels);
// shadow imitation
//glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
//fillTexturedRect(x+1, y+1, surface->w, surface->h);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
fillTexturedRect(x, y, surface->w, surface->h);
SDL_FreeSurface(surface);
glDeleteTextures(1, &texture);
glPopAttrib();
}
#define max(a, b) ((a) > (b) ? (a) : (b))
int _swapInterval = 1;
int _fullscreen = 0;
SDL_DisplayMode _displayMode;
void window_onRender(SDL_Window* window, TTF_Font* font, int width, int height) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
char buf[128];
SDL_Color textColor = {255, 255, 0}; // Green
int x = 10, y = 10, step=24;
if (SDL_GetDisplayMode(0, 0, &_displayMode) != 0) {
snprintf(buf, sizeof(buf), "SDL_GetDisplayMode() failed: %s\n", SDL_GetError());
drawText(font, buf, x, y, textColor);
y+=step;
//return;
}
int swapInterval = SDL_GL_GetSwapInterval();
double fps = 0.0;
uint64_t tmax = 0;
uint64_t tmin = -1;
uint64_t tavg = 0;
size_t length = queue_getSize(&_queue);
if (length > 0) {
// find tavg for the last second (for fps)
size_t counter = 0;
for (size_t i=max(length-_displayMode.refresh_rate, 0); i < length; i++) {
uint64_t v = queue_getElement(&_queue, i);
tavg += v;
counter++;
}
if (counter > 0) {
tavg /= counter;
}
fps = (double)1000000000UL / tavg;
// find statistics
tmax = 0;
tmin = -1;
tavg = 0;
for (size_t i=0; i < length; i++) {
uint64_t v = queue_getElement(&_queue, i);
if (v > tmax) tmax = v;
if (v < tmin) tmin = v;
tavg += v;
}
tavg /= length;
}
float targetRate = 0.0;
float targetTime = 0.0;
float viewMax = 0.0;
if (abs(swapInterval) == 0 || _displayMode.refresh_rate == 0) {
targetRate = INFINITY;
targetTime = 0;
viewMax = 1000000000.0 / max(_displayMode.refresh_rate, 30);
} else {
targetRate = (double)_displayMode.refresh_rate / abs(swapInterval);
targetTime = 1000000000.0 / targetRate;
viewMax = targetTime;
}
viewMax *= 1.2;
if (tmax > viewMax) viewMax = tmax;
float scale = viewMax!=0 ? height / viewMax : 0;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Draw grid and limit lines
glColor4f(1.0f, 1.0f, 1.0f, 0.2f); // White
// horizontal grid
for (uint64_t t=0; t < viewMax; t+=1000000.0) {
drawLine(0, height - scale * t, width-1, height - scale * t);
}
// vertical grid
for (int x=_frameCounter%_displayMode.refresh_rate; x < width; x+=_displayMode.refresh_rate) {
drawLine(width-x, 0, width-x, height);
}
// target time line
//glColor4f(1.0f, 0.0f, 1.0f, 0.6f); // Magenta
//drawLine(0, height - scale * targetTime, width-1, height - scale * targetTime);
float limitMax;
float limitMin;
if (abs(swapInterval) == 0) {
limitMin = 0.0;
limitMax = 0.0;
} else {
limitMin = 1000000000.0 / (targetRate+1);
limitMax = 1000000000.0 / (targetRate-1);
}
float limitMinY = height - scale * limitMin;
float limitMaxY = height - scale * limitMax;
//glColor4f(1.0f, 0.0f, 0.0f, 0.6f);
//drawLine(0, limitMinY, width-1, limitMinY);
//drawLine(0, limitMinY, width-1, limitMaxY);
// time graph
int startIndex = width - length;
GLfloat vertices[width * 2]; // (x, y)
for (int i = 0; i < width; ++i) {
uint64_t v = 0;
if (i >= startIndex) {
v = queue_getElement(&_queue, i-startIndex);
}
vertices[i * 2] = i; // x
vertices[i * 2 + 1] = height - scale * v; // y (reversed)
}
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glColor4f(0.0f, 1.0f, 0.0f, 0.8f); // Green
glDrawArrays(GL_LINE_STRIP, 0, sizeof(vertices)/(2*sizeof(GLfloat)));
glDisableClientState(GL_VERTEX_ARRAY);
// +-1 fps area
glColor4f(1.0f, 1.0f, 0.0f, 0.3f); // Yellow
fillRect(0, limitMinY, width-1, limitMaxY-limitMinY);
glDisable(GL_BLEND);
snprintf(buf, sizeof(buf), "real: %7.3f fps", fps);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "need: %7.3f fps", targetRate);
drawText(font, buf, x, y, textColor);
y+=step;
y+=step;
snprintf(buf, sizeof(buf), "tmin: %7.3f ms", tmin/1000000.0);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "tmax: %7.3f ms", tmax/1000000.0);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "tavg: %7.3f ms", tavg/1000000.0);
drawText(font, buf, x, y, textColor);
y+=step;
y+=step;
if (swapInterval < 0)
snprintf(buf, sizeof(buf), "swap: %d, \"%s\"", swapInterval, SDL_GetError());
else
snprintf(buf, sizeof(buf), "swap: %d", swapInterval);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "need: %d", _swapInterval);
drawText(font, buf, x, y, textColor);
y+=step;
y+=step;
snprintf(buf, sizeof(buf), "drv: %s", (const char*)SDL_GetCurrentVideoDriver());
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "mode: %dx%d@%d", _displayMode.w, _displayMode.h, _displayMode.refresh_rate);
drawText(font, buf, x, y, textColor);
y+=step;
snprintf(buf, sizeof(buf), "size: %dx%d", width, height);
drawText(font, buf, x, y, textColor);
}
void window_onResize(int width, int height) {
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0.0, width, height, 0.0, -1.0, 1.0); // coordinate setup: (0,0)=(left,top), (width,height)=(bottom,right)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int findFont(const char* font_name, char *buffer, size_t buffer_size) {
char command[MAX_PATH_LENGTH];
snprintf(command, sizeof(command), "fc-match -f '%%{file}' %s", font_name);
FILE *fp = popen(command, "r");
if (fp == NULL) {
return 0;
}
if (fgets(buffer, buffer_size, fp) == NULL) {
pclose(fp);
return 0;
}
buffer[strcspn(buffer, "\n")] = '\0';
pclose(fp);
return 1;
}
void saveScreenshot(SDL_Window* window) {
int width, height;
SDL_GetWindowSize(window, &width, &height);
SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_RGBA32);
if (!surface) {
printf("SDL_CreateRGBSurfaceWithFormat failed: %s\n", SDL_GetError());
return;
}
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels);
if (glGetError() != GL_NO_ERROR) {
printf("glReadPixels failed\n");
SDL_FreeSurface(surface);
return;
}
Uint32* pixels = (Uint32*)surface->pixels;
for (int y = 0; y < height / 2; ++y) {
for (int x = 0; x < width; ++x) {
Uint32 temp = pixels[y * width + x];
pixels[y * width + x] = pixels[(height - y - 1) * width + x];
pixels[(height - y - 1) * width + x] = temp;
}
}
// Create unique filename
char filename[128];
int counter = 1;
do {
snprintf(filename, sizeof(filename), "screenshot_%d.png", counter++);
} while (SDL_RWFromFile(filename, "rb") != NULL);
// Save
if (IMG_SavePNG(surface, filename) != 0) {
printf("IMG_SavePNG() failed: %s\n", IMG_GetError());
} else {
printf("Screenshot saved to %s\n", filename);
}
SDL_FreeSurface(surface);
}
int main(int argc, char *argv[]) {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("Failed to initialize SDL: %s\n", SDL_GetError());
return -1;
}
//printf("SDL_GetCurrentVideoDriver(): %s\n", (const char*)SDL_GetCurrentVideoDriver());
int width = 800;
int height = 600;
int doublebuffer = 1;
const char *drivername = NULL;
// parse command line
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--help") == 0) {
printf("USAGE: %s [options]\n", argv[0]);
printf(" F1 - toggle swapInterval\n");
printf(" F11 - toggle fullscreen mode\n");
printf(" F12 - save screenshot\n");
printf(" ESC - exit\n");
printf("options:\n");
printf(" --list list available SDL video drivers\n");
printf(" --driver set SDL video driver (equals to SDL_VIDEODRIVER env.variable)\n");
printf(" --size set initial window size\n");
printf(" --doublebuffer <1|0> set SDL_GL_DOUBLEBUFFER attribute value\n");
SDL_Quit();
return 0;
} else if (strcmp(argv[i], "--list") == 0) {
int num_drivers = SDL_GetNumVideoDrivers();
printf("\nAvailable --driver values:\n");
for (int j = 0; j < num_drivers; ++j) {
printf(" \"%s\"\n", SDL_GetVideoDriver(j));
}
SDL_Quit();
return 0;
} else if (strcmp(argv[i], "--driver") == 0 && i + 1 < argc) {
drivername = argv[i + 1];
printf("--driver %s\n", drivername);
i++;
} else if (strcmp(argv[i], "--size") == 0 && i + 1 < argc) {
if (sscanf(argv[i + 1], "%d,%d", &width, &height) != 2) {
printf("Invalid --size format. Expected --size \n");
SDL_Quit();
return -1;
}
printf("--size %d,%d\n", width, height);
i++;
} else if (strcmp(argv[i], "--doublebuffer") == 0 && i + 1 < argc) {
if (sscanf(argv[i + 1], "%d", &doublebuffer) != 1) {
printf("Invalid --doublebuffer format. Expected --doublebuffer <0|1>\n");
SDL_Quit();
return -1;
}
doublebuffer = doublebuffer ? 1 : 0;
printf("--doublebuffer %d\n", doublebuffer);
i++;
} else {
printf("error: unknown command line option \"%s\"\n", argv[i]);
SDL_Quit();
return -1;
}
}
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, doublebuffer);
if (SDL_VideoInit(drivername) < 0) {
printf("SDL_VideoInit(\"%s\") failed: %s\n", drivername, SDL_GetError());
SDL_Quit();
return -1;
}
printf("SDL_GetCurrentVideoDriver(): %s\n", (const char*)SDL_GetCurrentVideoDriver());
if (SDL_GetDisplayMode(0, 0, &_displayMode) != 0) {
printf("SDL_GetDisplayMode() failed: %s\n", SDL_GetError());
SDL_Quit();
return -1;
}
printf("SDL_GetDisplayMode(): %d x %d @ %d, format=0x%08x\n", _displayMode.w, _displayMode.h, _displayMode.refresh_rate, _displayMode.format);
if (TTF_Init() < 0) {
printf("TTF_Init() failed: %s\n", TTF_GetError());
SDL_Quit();
return -1;
}
// find path: $ fc-match -f '%{file}\n' Monospace
char fontPath[MAX_PATH_LENGTH];
if (!findFont("Monospace", fontPath, sizeof(fontPath))) {
printf("findFont(\"Monospace\") failed\n");
return -1;
}
TTF_Font* font = TTF_OpenFont(fontPath, 20);
if (font == NULL) {
printf("TTF_OpenFont() failed: %s\n", TTF_GetError());
TTF_Quit();
SDL_Quit();
return -1;
}
if (IMG_Init(IMG_INIT_PNG) == 0) {
printf("IMG_Init failed: %s\n", IMG_GetError());
SDL_Quit();
return -1;
}
SDL_Window* window = SDL_CreateWindow(
"test-vblank3",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
width, height,
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE);
if (window == NULL) {
printf("SDL_CreateWindow() failed: %s\n", SDL_GetError());
TTF_CloseFont(font);
TTF_Quit();
SDL_Quit();
return -1;
}
if (_fullscreen)
{
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
SDL_GLContext glContext = SDL_GL_CreateContext(window);
SDL_GL_SetSwapInterval(_swapInterval);
printf("SDL_GL_SetSwapInterval(%d) => SDL_GL_GetSwapInterval() = %d\n", _swapInterval, SDL_GL_GetSwapInterval());
const int printAttrs[] = { SDL_GL_DOUBLEBUFFER, SDL_GL_MULTISAMPLEBUFFERS, SDL_GL_MULTISAMPLESAMPLES, 0 };
const char* printNames[] = { "SDL_GL_DOUBLEBUFFER", "SDL_GL_MULTISAMPLEBUFFERS", "SDL_GL_MULTISAMPLESAMPLES", 0 };
for (int i=0; printAttrs[i] != 0; i++) {
int value;
if (SDL_GL_GetAttribute(printAttrs[i], &value)) {
printf("SDL_GL_GetAttribute(%s) failed: %s\n", printNames[i], SDL_GetError());
continue;
}
printf("%s = %d\n", printNames[i], value);
}
SDL_GetWindowSize(window, &width, &height);
printf("SDL_GetWindowSize(): %d, %d\n", width, height);
window_onResize(width, height);
int running = 1;
struct timespec ts1, ts2;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts1);
queue_init(&_queue, 16384);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
while (running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
running = 0;
}
if (event.type == SDL_KEYDOWN) {
if (event.key.keysym.sym == SDLK_ESCAPE) {
running = 0;
}
if (event.key.keysym.sym == SDLK_F11) {
_fullscreen = _fullscreen ? 0:1;
printf("SDL_SetWindowFullscreen(%d)\n", _fullscreen);
SDL_SetWindowFullscreen(window, _fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
}
if (event.key.keysym.sym == SDLK_F1) {
_swapInterval = (_swapInterval+1) & 3;
SDL_GL_SetSwapInterval(_swapInterval);
printf("SDL_GL_SetSwapInterval(%d) => SDL_GL_GetSwapInterval() = %d\n", _swapInterval, SDL_GL_GetSwapInterval());
}
if (event.key.keysym.sym == SDLK_F12) {
saveScreenshot(window);
}
}
if (event.type == SDL_WINDOWEVENT) {
if (event.window.event == SDL_WINDOWEVENT_RESIZED ||
event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) {
width = event.window.data1;
height = event.window.data2;
window_onResize(width, height);
}
}
}
window_onRender(window, font, width, height);
SDL_GL_SwapWindow(window);
clock_gettime(CLOCK_MONOTONIC_RAW, &ts2);
uint64_t dt_ns = ((uint64_t)ts2.tv_sec - (uint64_t)ts1.tv_sec) * 1000000000UL + (ts2.tv_nsec - ts1.tv_nsec);
ts1 = ts2;
_frameCounter++;
queue_enqueue(&_queue, dt_ns);
SDL_GetWindowSize(window, &width, &height);
ssize_t excess_elements = (ssize_t)queue_getSize(&_queue) - width;
if (excess_elements > 0) {
queue_trimFront(&_queue, excess_elements);
}
}
queue_free(&_queue);
IMG_Quit();
TTF_CloseFont(font);
TTF_Quit();
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
```
I'm using latest raspios with labwc on RPI4.
When I change the display mode using
wlr-randr
orarandr
, it causes SDL2 applications to no longer be able to read the current display mode until they are restarted. The issue occurs both with the Wayland backend, where SDL_GetDisplayMode consistently returns the error:and with the X11 backend, where SDL_GetDisplayMode starts returning the old mode, which does not match the actual one.
Steps to reproduce
1)
sudo apt install libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev
2) Createtest-vblank3.c
and copy/paste code (see below) 3) Compile it withgcc -o test-vblank3 test-vblank3.c -Wall -lGL -lSDL2 -lSDL2_ttf -lSDL2_image
4) Run it with./test-vblank3 --driver wayland
5) Run arandr and change video mode (for example refresh rate), or use wlr-randr (for examplewlr-randr --output HDMI-A-1 --custom-mode 1280x1024@50Hz
)Expected result: SDL2 properly returns a new video mode
Actual result: For wayland backend SDL_GetDisplayMode fails with error. For x11 backend it returns incorrect video mode.
Screenshots
Test code
test-vblank3.c
```c // sudo apt install libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev // sudo pacman -S sdl2 sdl2_ttf sdl2_image // gcc -o test-vblank3 test-vblank3.c -Wall -lGL -lSDL2 -lSDL2_ttf -lSDL2_image #include