SDL
SDL copied to clipboard
SDL_CreateWindow() requires SDL_WINDOW_ALLOW_HIGHDPI flag to successfully use Wayland video driver
- Linux distribution:
NixOS 22.05 - SDL2 version:
2.0.22 - Wayland compositor:
river(wlroots) with XWayland enabled - Other details: I use fractional scaling and strongly suspect that the problem does not occur at 1.0 scale. I could do more testing on this front if needed.
Explanation and minimum reproducible examples
Example 1 results in a solid red window of size 1280x720 (multiplied by my scale factor) rendered as an X window through XWayland. SDL sends no messages to stdout.
Example 2 results in a solid red window of size 1280x720 (multiplied by my scale factor) rendered as a native Wayland window. SDL sends no messages to stdout.
Example 1
#include <stdlib.h>
#include <error.h>
#include <SDL2/SDL.h>
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
int main() {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
fprintf(stderr, "SDL_Init Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
// create window
int window_flags =
SDL_WINDOW_SHOWN;
SDL_Window* window = SDL_CreateWindow(
"title",
100, 100,
SCREEN_WIDTH, SCREEN_HEIGHT,
window_flags
);
if (window == NULL) {
fprintf(stderr, "SDL_CreateWindow Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
int render_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, render_flags);
if (renderer == NULL) {
fprintf(stderr, "SDL_CreateRenderer Error: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_FAILURE;
}
// event loop
SDL_bool done = SDL_FALSE;
while (!done) {
SDL_Event event;
SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
done = SDL_TRUE;
}
}
SDL_RenderPresent(renderer);
}
if (renderer) SDL_DestroyRenderer(renderer);
if (window) SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
Example 2
#include <stdlib.h>
#include <error.h>
#include <SDL2/SDL.h>
#define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720
int main() {
if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
fprintf(stderr, "SDL_Init Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
// create window
int window_flags =
SDL_WINDOW_ALLOW_HIGHDPI |
SDL_WINDOW_SHOWN;
SDL_Window* window = SDL_CreateWindow(
"title",
100, 100,
SCREEN_WIDTH, SCREEN_HEIGHT,
window_flags
);
if (window == NULL) {
fprintf(stderr, "SDL_CreateWindow Error: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
int render_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC;
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, render_flags);
if (renderer == NULL) {
fprintf(stderr, "SDL_CreateRenderer Error: %s\n", SDL_GetError());
SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_FAILURE;
}
// event loop
SDL_bool done = SDL_FALSE;
while (!done) {
SDL_Event event;
SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
done = SDL_TRUE;
}
}
SDL_RenderPresent(renderer);
}
if (renderer) SDL_DestroyRenderer(renderer);
if (window) SDL_DestroyWindow(window);
SDL_Quit();
return EXIT_SUCCESS;
}
The only difference is that Example 2 includes the SDL_ALLOW_HIGHDPI flag when creating the window, whereas Example 1 does not.
I've universally exported SDL_VIDEODRIVER=wayland and compile both examples with
gcc -lSDL2 -o test main.c
Please let me know if anything else is needed. (Apologies for the slightly confusing formatting. It seems one of my plugins uses tabs when auto-indenting, whereas I'm using spaces everywhere else).
Can you run it with WAYLAND_DEBUG=1 and post the output?
Here's the output of running Example 1, the X window, with WAYLAND_DEBUG=1:
Example1_DEBUG.txt
And the output of WAYLAND_DEBUG=1 for Example 2, the Wayland window:
Example2_DEBUG.txt
If example 1 is producing debug output with Wayland debug enabled, then it's native and not an X window. Neither of these logs show any errors, and they are basically identical except the second uses a viewport to scale the output while the first does not, which is exactly what they should be showing.
This makes sense, as SDL doesn't fall back to X11 if Wayland is explicitly enabled; it either works, or it doesn't. This sounds like something in your compositor being weird vs a bug in SDL.
I was previously going to say that I could guarantee Example 1 displays an XWayland window. I use 1.3x fractional scaling, and XWayland works by rendering at 100% and having the Wayland compositor scale up. This means XWayland windows are slightly but very noticeably blurry, whereas native Wayland windows are tack sharp. Mousing over the window produced by Example 1 results in a blurry cursor.
However, I am now wondering is if SDL2 in Example 1 is triggering the same mechanism that lets XWayland windows get scaled up, while still providing a native Wayland window. I've never had a blurry native window this way, only XWayland, but it sounds possible. If this is indeed the case, perhaps SDL_WINDOW_ALLOW_HIGHDPI should be enabled by default or at least better documented, since one of the killer features of Wayland is flawless fractional scaling at any value and I don't see why this should go unused because it's not obvious how to enable it or what exactly the flag does ("window should be created in high-DPI mode if supported"). Again, I have only ever observed this "fake scaling" with windows I know for certain were running through XWayland, and not native ones, which makes SDL2's behaviour seem out of place.
The above is just speculation and I'm not sure exactly what's going on. But to me it seems that in the worst case, this is an SDL problem, and in the best case, the documentation should be clearer or the flag should be enabled by default.
Edit: this was probably clear already, but I've confirmed both examples produce native Wayland windows. Sorry for assuming that the window with "fake scaling" was running through XWayland - I did so because I've never encountered other Wayland programs behaving this way.
However, I am now wondering is if SDL2 in Example 1 is triggering the same mechanism that lets XWayland windows get scaled up, while still providing a native Wayland window.
That's exactly what's supposed to happen if you don't pass SDL_WINDOW_ALLOW_HIGHDPI.
So is there something that needs to be done here or is this working as expected?
Nope, everything the OP provided shows things working as they are supposed to.