Browse Source

Wayland: Properly discover displays and their modes.

Fixes Bugzilla #2913.
Emmanuel Gil Peyrot 10 years ago
parent
commit
89be609adf

+ 72 - 122
src/video/wayland/SDL_waylandvideo.c

@@ -43,11 +43,6 @@
 
 #define WAYLANDVID_DRIVER_NAME "wayland"
 
-struct wayland_mode {
-    SDL_DisplayMode mode;
-    struct wl_list link;
-};
-
 /* Initialization/Query functions */
 static int
 Wayland_VideoInit(_THIS);
@@ -87,7 +82,7 @@ static SDL_VideoDevice *
 Wayland_CreateDevice(int devindex)
 {
     SDL_VideoDevice *device;
-    
+
     if (!SDL_WAYLAND_LoadSymbols()) {
         return NULL;
     }
@@ -135,27 +130,6 @@ VideoBootStrap Wayland_bootstrap = {
     Wayland_Available, Wayland_CreateDevice
 };
 
-static void
-wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m)
-{
-    struct wayland_mode *mode;
-
-    /* Check for duplicate mode */
-    wl_list_for_each(mode, &d->modes_list, link)
-        if (mode->mode.w == m.w && mode->mode.h == m.h &&
-	    mode->mode.refresh_rate == m.refresh_rate)
-	    return;
-
-    /* Add new mode to the list */
-    mode = (struct wayland_mode *) SDL_calloc(1, sizeof *mode);
-
-    if (!mode)
-	return;
-
-    mode->mode = m;
-    WAYLAND_wl_list_insert(&d->modes_list, &mode->link);
-}
-
 static void
 display_handle_geometry(void *data,
                         struct wl_output *output,
@@ -168,54 +142,78 @@ display_handle_geometry(void *data,
                         int transform)
 
 {
-    SDL_VideoData *d = data;
+    SDL_VideoDisplay *display = data;
 
-    d->screen_allocation.x = x;
-    d->screen_allocation.y = y;
+    display->name = strdup(model);
+    display->driverdata = output;
 }
 
 static void
 display_handle_mode(void *data,
-                    struct wl_output *wl_output,
+                    struct wl_output *output,
                     uint32_t flags,
                     int width,
                     int height,
                     int refresh)
 {
-    SDL_VideoData *d = data;
+    SDL_VideoDisplay *display = data;
     SDL_DisplayMode mode;
 
     SDL_zero(mode);
     mode.w = width;
     mode.h = height;
-    mode.refresh_rate = refresh / 1000;
-
-    wayland_add_mode(d, mode);
+    mode.refresh_rate = refresh / 1000; // mHz to Hz
+    SDL_AddDisplayMode(display, &mode);
 
     if (flags & WL_OUTPUT_MODE_CURRENT) {
-        d->screen_allocation.width = width;
-        d->screen_allocation.height = height;
+        display->current_mode = mode;
+        display->desktop_mode = mode;
     }
 }
 
+static void
+display_handle_done(void *data,
+                    struct wl_output *output)
+{
+    SDL_VideoDisplay *display = data;
+    SDL_AddVideoDisplay(display);
+    SDL_free(display->name);
+    SDL_free(display);
+}
+
+static void
+display_handle_scale(void *data,
+                     struct wl_output *output,
+                     int32_t factor)
+{
+    // TODO: do HiDPI stuff.
+}
+
 static const struct wl_output_listener output_listener = {
     display_handle_geometry,
-    display_handle_mode
+    display_handle_mode,
+    display_handle_done,
+    display_handle_scale
 };
 
 static void
-shm_handle_format(void *data,
-                  struct wl_shm *shm,
-                  uint32_t format)
+Wayland_add_display(SDL_VideoData *d, uint32_t id)
 {
-    SDL_VideoData *d = data;
+    SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
+    if (!display) {
+        SDL_OutOfMemory();
+        return;
+    }
+    SDL_zero(*display);
 
-    d->shm_formats |= (1 << format);
-}
+    struct wl_output *output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
+    if (!output) {
+        SDL_SetError("Failed to retrieve output.");
+        return;
+    }
 
-static const struct wl_shm_listener shm_listener = {
-    shm_handle_format
-};
+    wl_output_add_listener(output, &output_listener, display);
+}
 
 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
 static void
@@ -238,15 +236,14 @@ static const struct qt_windowmanager_listener windowmanager_listener = {
 
 static void
 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
-					const char *interface, uint32_t version)
+                      const char *interface, uint32_t version)
 {
     SDL_VideoData *d = data;
-    
+
     if (strcmp(interface, "wl_compositor") == 0) {
         d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
     } else if (strcmp(interface, "wl_output") == 0) {
-        d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1);
-        wl_output_add_listener(d->output, &output_listener, d);
+        Wayland_add_display(d, id);
     } else if (strcmp(interface, "wl_seat") == 0) {
         Wayland_display_add_input(d, id);
     } else if (strcmp(interface, "wl_shell") == 0) {
@@ -255,8 +252,7 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
         d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
         d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
         d->default_cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
-        wl_shm_add_listener(d->shm, &shm_listener, d);
-    
+
 #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
     } else if (strcmp(interface, "qt_touch_extension") == 0) {
         Wayland_touch_create(d, id);
@@ -272,26 +268,19 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
 }
 
 static const struct wl_registry_listener registry_listener = {
-	display_handle_global
+    display_handle_global
 };
 
 int
 Wayland_VideoInit(_THIS)
 {
-    SDL_VideoData *data;
-    SDL_VideoDisplay display;
-    SDL_DisplayMode mode;
-    int i;
-    
-    data = malloc(sizeof *data);
+    SDL_VideoData *data = SDL_malloc(sizeof *data);
     if (data == NULL)
         return 0;
     memset(data, 0, sizeof *data);
 
     _this->driverdata = data;
 
-    WAYLAND_wl_list_init(&data->modes_list);
-    
     data->display = WAYLAND_wl_display_connect(NULL);
     if (data->display == NULL) {
         SDL_SetError("Failed to connect to a Wayland display");
@@ -299,25 +288,18 @@ Wayland_VideoInit(_THIS)
     }
 
     data->registry = wl_display_get_registry(data->display);
-   
-    if ( data->registry == NULL) {
+    if (data->registry == NULL) {
         SDL_SetError("Failed to get the Wayland registry");
         return 0;
     }
-    
+
     wl_registry_add_listener(data->registry, &registry_listener, data);
 
-    for (i=0; i < 100; i++) {
-        if (data->screen_allocation.width != 0 || WAYLAND_wl_display_get_error(data->display) != 0) {
-            break;
-        }
-        WAYLAND_wl_display_dispatch(data->display);
-    }
-    
-    if (data->screen_allocation.width == 0) {
-        SDL_SetError("Failed while waiting for screen allocation: %d ", WAYLAND_wl_display_get_error(data->display));
-        return 0;
-    }
+    // First roundtrip to receive all registry objects.
+    wl_display_roundtrip(data->display);
+
+    // Second roundtrip to receive all output events.
+    wl_display_roundtrip(data->display);
 
     data->xkb_context = WAYLAND_xkb_context_new(0);
     if (!data->xkb_context) {
@@ -325,20 +307,7 @@ Wayland_VideoInit(_THIS)
         return 0;
     }
 
-    /* Use a fake 32-bpp desktop mode */
-    mode.format = SDL_PIXELFORMAT_RGB888;
-    mode.w = data->screen_allocation.width;
-    mode.h = data->screen_allocation.height;
-    mode.refresh_rate = 0;
-    mode.driverdata = NULL;
-    wayland_add_mode(data, mode);
-    SDL_zero(display);
-    display.desktop_mode = mode;
-    display.current_mode = mode;
-    display.driverdata = NULL;
-    SDL_AddVideoDisplay(&display);
-
-    Wayland_InitMouse ();
+    Wayland_InitMouse();
 
     WAYLAND_wl_display_flush(data->display);
 
@@ -348,46 +317,30 @@ Wayland_VideoInit(_THIS)
 static void
 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
 {
-    SDL_VideoData *data = _this->driverdata;
-    SDL_DisplayMode mode;
-    struct wayland_mode *m;
-
-    Wayland_PumpEvents(_this);
-
-    wl_list_for_each(m, &data->modes_list, link) {
-        m->mode.format = SDL_PIXELFORMAT_RGB888;
-        SDL_AddDisplayMode(sdl_display, &m->mode);
-        m->mode.format = SDL_PIXELFORMAT_RGBA8888;
-        SDL_AddDisplayMode(sdl_display, &m->mode);
-    }
-
-    mode.w = data->screen_allocation.width;
-    mode.h = data->screen_allocation.height;
-    mode.refresh_rate = 0;
-    mode.driverdata = NULL;
-
-    mode.format = SDL_PIXELFORMAT_RGB888;
-    SDL_AddDisplayMode(sdl_display, &mode);
-    mode.format = SDL_PIXELFORMAT_RGBA8888;
-    SDL_AddDisplayMode(sdl_display, &mode);
+    // Nothing to do here, everything was already done in the wl_output
+    // callbacks.
 }
 
 static int
 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
 {
-    return 0;
+    SDL_SetError("SetDisplayMode not (yet?) supported on Wayland.");
+    return -1;
 }
 
 void
 Wayland_VideoQuit(_THIS)
 {
     SDL_VideoData *data = _this->driverdata;
-    struct wayland_mode *t, *m;
+    int i;
 
     Wayland_FiniMouse ();
 
-    if (data->output)
-        wl_output_destroy(data->output);
+    for (i = 0; i < _this->num_displays; ++i) {
+        SDL_VideoDisplay *display = &_this->displays[i];
+        wl_output_destroy(display->driverdata);
+        display->driverdata = NULL;
+    }
 
     Wayland_display_destroy_input(data);
 
@@ -417,16 +370,13 @@ Wayland_VideoQuit(_THIS)
     if (data->compositor)
         wl_compositor_destroy(data->compositor);
 
+    if (data->registry)
+        wl_registry_destroy(data->registry);
+
     if (data->display) {
         WAYLAND_wl_display_flush(data->display);
         WAYLAND_wl_display_disconnect(data->display);
     }
-    
-    wl_list_for_each_safe(m, t, &data->modes_list, link) {
-        WAYLAND_wl_list_remove(&m->link);
-        free(m);
-    }
-
 
     free(data);
     _this->driverdata = NULL;

+ 2 - 11
src/video/wayland/SDL_waylandvideo.h

@@ -40,33 +40,24 @@ typedef struct {
     struct wl_display *display;
     struct wl_registry *registry;
     struct wl_compositor *compositor;
-    struct wl_output *output;
     struct wl_shm *shm;
     struct wl_cursor_theme *cursor_theme;
     struct wl_cursor *default_cursor;
     struct wl_pointer *pointer;
     struct wl_shell *shell;
 
-    struct {
-        int32_t x, y, width, height;
-    } screen_allocation;
-
-    struct wl_list modes_list;
-
     EGLDisplay edpy;
     EGLContext context;
     EGLConfig econf;
 
     struct xkb_context *xkb_context;
     struct SDL_WaylandInput *input;
-    
-#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH    
+
+#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
     struct SDL_WaylandTouch *touch;
     struct qt_surface_extension *surface_extension;
     struct qt_windowmanager *windowmanager;
 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
-
-    uint32_t shm_formats;
 } SDL_VideoData;
 
 #endif /* _SDL_waylandvideo_h */

+ 0 - 11
src/video/wayland/SDL_waylandwindow.c

@@ -179,17 +179,6 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
     }
 #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
 
-    /**
-     * If the user specified 0x0 as the size (turned to 1x1 by SDL_CreateWindow
-     * in SDL_video.c), we want to make the window fill the whole screen
-     **/
-    if (window->w == 1) {
-        window->w = c->screen_allocation.width;
-    }
-    if (window->h == 1) {
-        window->h = c->screen_allocation.height;
-    }
-
     data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
                                             window->w, window->h);