Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

video: Only prefer Wayland if fifo-v1 and commit-timing-v1 are available #9383

Merged
merged 2 commits into from
Aug 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/video/SDL_sysvideo.h
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@ extern VideoBootStrap KMSDRM_bootstrap;
extern VideoBootStrap KMSDRM_LEGACY_bootstrap;
extern VideoBootStrap DUMMY_bootstrap;
extern VideoBootStrap DUMMY_evdev_bootstrap;
extern VideoBootStrap Wayland_preferred_bootstrap;
extern VideoBootStrap Wayland_bootstrap;
extern VideoBootStrap VIVANTE_bootstrap;
extern VideoBootStrap Emscripten_bootstrap;
Expand Down
41 changes: 36 additions & 5 deletions src/video/SDL_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,15 @@ static VideoBootStrap *bootstrap[] = {
#ifdef SDL_VIDEO_DRIVER_COCOA
&COCOA_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_X11
#ifdef SDL_VIDEO_DRIVER_WAYLAND
&Wayland_bootstrap,
&Wayland_preferred_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_X11
&X11_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND
&Wayland_bootstrap,
#endif
#ifdef SDL_VIDEO_DRIVER_VIVANTE
&VIVANTE_bootstrap,
#endif
Expand Down Expand Up @@ -438,15 +441,41 @@ static int SDL_UninitializedVideo(void)
return SDL_SetError("Video subsystem has not been initialized");
}

/* Deduplicated list of video bootstrap drivers. */
static const VideoBootStrap *deduped_bootstrap[SDL_arraysize(bootstrap) - 1];

int SDL_GetNumVideoDrivers(void)
{
return SDL_arraysize(bootstrap) - 1;
static int num_drivers = -1;

if (num_drivers >= 0) {
return num_drivers;
}

num_drivers = 0;

/* Build a list of unique video drivers. */
for (int i = 0; bootstrap[i] != NULL; ++i) {
SDL_bool duplicate = SDL_FALSE;
for (int j = 0; j < i; ++j) {
if (SDL_strcmp(bootstrap[i]->name, bootstrap[j]->name) == 0) {
duplicate = SDL_TRUE;
break;
}
}

if (!duplicate) {
deduped_bootstrap[num_drivers++] = bootstrap[i];
}
}

return num_drivers;
}

const char *SDL_GetVideoDriver(int index)
{
if (index >= 0 && index < SDL_GetNumVideoDrivers()) {
return bootstrap[index]->name;
return deduped_bootstrap[index]->name;
}
return NULL;
}
Expand Down Expand Up @@ -504,7 +533,9 @@ int SDL_VideoInit(const char *driver_name)
if ((driver_attempt_len == SDL_strlen(bootstrap[i]->name)) &&
(SDL_strncasecmp(bootstrap[i]->name, driver_attempt, driver_attempt_len) == 0)) {
video = bootstrap[i]->create();
break;
if (video) {
break;
}
}
}

Expand Down
79 changes: 77 additions & 2 deletions src/video/wayland/SDL_waylandvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,54 @@ static void Wayland_DeleteDevice(SDL_VideoDevice *device)
SDL_WAYLAND_UnloadSymbols();
}

static SDL_VideoDevice *Wayland_CreateDevice(void)
typedef struct
{
SDL_bool has_fifo_v1;
SDL_bool has_commit_timing_v1;
} SDL_WaylandPreferredData;

static void wayland_preferred_check_handle_global(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
{
SDL_WaylandPreferredData *d = data;

if (SDL_strcmp(interface, "wp_fifo_manager_v1") == 0) {
d->has_fifo_v1 = SDL_TRUE;
} else if (SDL_strcmp(interface, "wp_commit_timing_manager_v1") == 0) {
misyltoad marked this conversation as resolved.
Show resolved Hide resolved
d->has_commit_timing_v1 = SDL_TRUE;
}
}

static void wayland_preferred_check_remove_global(void *data, struct wl_registry *registry, uint32_t id)
{
/* No need to do anything here. */
}

static const struct wl_registry_listener preferred_registry_listener = {
wayland_preferred_check_handle_global,
wayland_preferred_check_remove_global
};

static SDL_bool Wayland_IsPreferred(struct wl_display *display)
{
struct wl_registry *registry = wl_display_get_registry(display);
SDL_WaylandPreferredData preferred_data = { 0 };

if (!registry) {
SDL_SetError("Failed to get the Wayland registry");
return SDL_FALSE;
}

wl_registry_add_listener(registry, &preferred_registry_listener, &preferred_data);

WAYLAND_wl_display_roundtrip(display);

wl_registry_destroy(registry);

return preferred_data.has_fifo_v1 && preferred_data.has_commit_timing_v1;
}

static SDL_VideoDevice *Wayland_CreateDevice(SDL_bool require_preferred_protocols)
{
SDL_VideoDevice *device;
SDL_VideoData *data;
Expand Down Expand Up @@ -398,6 +445,18 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
}
}

/*
* If we are checking for preferred Wayland, then let's query for
* fifo-v1 and commit-timing-v1's existence, so we don't regress
* GPU-bound performance and frame-pacing by default due to
* swapchain starvation.
*/
if (require_preferred_protocols && !Wayland_IsPreferred(display)) {
WAYLAND_wl_display_disconnect(display);
SDL_WAYLAND_UnloadSymbols();
return NULL;
}

data = SDL_calloc(1, sizeof(*data));
if (!data) {
WAYLAND_wl_display_disconnect(display);
Expand Down Expand Up @@ -523,9 +582,25 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
return device;
}

static SDL_VideoDevice *Wayland_Preferred_CreateDevice(void)
{
return Wayland_CreateDevice(SDL_TRUE);
}

static SDL_VideoDevice *Wayland_Fallback_CreateDevice(void)
{
return Wayland_CreateDevice(SDL_FALSE);
}

VideoBootStrap Wayland_preferred_bootstrap = {
WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
Wayland_Preferred_CreateDevice,
Wayland_ShowMessageBox
};

VideoBootStrap Wayland_bootstrap = {
WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
Wayland_CreateDevice,
Wayland_Fallback_CreateDevice,
Wayland_ShowMessageBox
};

Expand Down