Wayland: Properly discover displays and their modes.
authorEmmanuel Gil Peyrot <linkmauve@linkmauve.fr>
Wed, 18 Mar 2015 01:14:45 +0100
changeset 9467975453c4e217
parent 9466 510c9a2f0951
child 9468 d001cff818bb
Wayland: Properly discover displays and their modes.

Fixes Bugzilla #2913.
src/video/wayland/SDL_waylandvideo.c
src/video/wayland/SDL_waylandvideo.h
src/video/wayland/SDL_waylandwindow.c
     1.1 --- a/src/video/wayland/SDL_waylandvideo.c	Tue Apr 07 21:52:22 2015 -0400
     1.2 +++ b/src/video/wayland/SDL_waylandvideo.c	Wed Mar 18 01:14:45 2015 +0100
     1.3 @@ -43,11 +43,6 @@
     1.4  
     1.5  #define WAYLANDVID_DRIVER_NAME "wayland"
     1.6  
     1.7 -struct wayland_mode {
     1.8 -    SDL_DisplayMode mode;
     1.9 -    struct wl_list link;
    1.10 -};
    1.11 -
    1.12  /* Initialization/Query functions */
    1.13  static int
    1.14  Wayland_VideoInit(_THIS);
    1.15 @@ -87,7 +82,7 @@
    1.16  Wayland_CreateDevice(int devindex)
    1.17  {
    1.18      SDL_VideoDevice *device;
    1.19 -    
    1.20 +
    1.21      if (!SDL_WAYLAND_LoadSymbols()) {
    1.22          return NULL;
    1.23      }
    1.24 @@ -136,27 +131,6 @@
    1.25  };
    1.26  
    1.27  static void
    1.28 -wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m)
    1.29 -{
    1.30 -    struct wayland_mode *mode;
    1.31 -
    1.32 -    /* Check for duplicate mode */
    1.33 -    wl_list_for_each(mode, &d->modes_list, link)
    1.34 -        if (mode->mode.w == m.w && mode->mode.h == m.h &&
    1.35 -	    mode->mode.refresh_rate == m.refresh_rate)
    1.36 -	    return;
    1.37 -
    1.38 -    /* Add new mode to the list */
    1.39 -    mode = (struct wayland_mode *) SDL_calloc(1, sizeof *mode);
    1.40 -
    1.41 -    if (!mode)
    1.42 -	return;
    1.43 -
    1.44 -    mode->mode = m;
    1.45 -    WAYLAND_wl_list_insert(&d->modes_list, &mode->link);
    1.46 -}
    1.47 -
    1.48 -static void
    1.49  display_handle_geometry(void *data,
    1.50                          struct wl_output *output,
    1.51                          int x, int y,
    1.52 @@ -168,55 +142,79 @@
    1.53                          int transform)
    1.54  
    1.55  {
    1.56 -    SDL_VideoData *d = data;
    1.57 +    SDL_VideoDisplay *display = data;
    1.58  
    1.59 -    d->screen_allocation.x = x;
    1.60 -    d->screen_allocation.y = y;
    1.61 +    display->name = strdup(model);
    1.62 +    display->driverdata = output;
    1.63  }
    1.64  
    1.65  static void
    1.66  display_handle_mode(void *data,
    1.67 -                    struct wl_output *wl_output,
    1.68 +                    struct wl_output *output,
    1.69                      uint32_t flags,
    1.70                      int width,
    1.71                      int height,
    1.72                      int refresh)
    1.73  {
    1.74 -    SDL_VideoData *d = data;
    1.75 +    SDL_VideoDisplay *display = data;
    1.76      SDL_DisplayMode mode;
    1.77  
    1.78      SDL_zero(mode);
    1.79      mode.w = width;
    1.80      mode.h = height;
    1.81 -    mode.refresh_rate = refresh / 1000;
    1.82 -
    1.83 -    wayland_add_mode(d, mode);
    1.84 +    mode.refresh_rate = refresh / 1000; // mHz to Hz
    1.85 +    SDL_AddDisplayMode(display, &mode);
    1.86  
    1.87      if (flags & WL_OUTPUT_MODE_CURRENT) {
    1.88 -        d->screen_allocation.width = width;
    1.89 -        d->screen_allocation.height = height;
    1.90 +        display->current_mode = mode;
    1.91 +        display->desktop_mode = mode;
    1.92      }
    1.93  }
    1.94  
    1.95 +static void
    1.96 +display_handle_done(void *data,
    1.97 +                    struct wl_output *output)
    1.98 +{
    1.99 +    SDL_VideoDisplay *display = data;
   1.100 +    SDL_AddVideoDisplay(display);
   1.101 +    SDL_free(display->name);
   1.102 +    SDL_free(display);
   1.103 +}
   1.104 +
   1.105 +static void
   1.106 +display_handle_scale(void *data,
   1.107 +                     struct wl_output *output,
   1.108 +                     int32_t factor)
   1.109 +{
   1.110 +    // TODO: do HiDPI stuff.
   1.111 +}
   1.112 +
   1.113  static const struct wl_output_listener output_listener = {
   1.114      display_handle_geometry,
   1.115 -    display_handle_mode
   1.116 +    display_handle_mode,
   1.117 +    display_handle_done,
   1.118 +    display_handle_scale
   1.119  };
   1.120  
   1.121  static void
   1.122 -shm_handle_format(void *data,
   1.123 -                  struct wl_shm *shm,
   1.124 -                  uint32_t format)
   1.125 +Wayland_add_display(SDL_VideoData *d, uint32_t id)
   1.126  {
   1.127 -    SDL_VideoData *d = data;
   1.128 +    SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
   1.129 +    if (!display) {
   1.130 +        SDL_OutOfMemory();
   1.131 +        return;
   1.132 +    }
   1.133 +    SDL_zero(*display);
   1.134  
   1.135 -    d->shm_formats |= (1 << format);
   1.136 +    struct wl_output *output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
   1.137 +    if (!output) {
   1.138 +        SDL_SetError("Failed to retrieve output.");
   1.139 +        return;
   1.140 +    }
   1.141 +
   1.142 +    wl_output_add_listener(output, &output_listener, display);
   1.143  }
   1.144  
   1.145 -static const struct wl_shm_listener shm_listener = {
   1.146 -    shm_handle_format
   1.147 -};
   1.148 -
   1.149  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   1.150  static void
   1.151  windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
   1.152 @@ -238,15 +236,14 @@
   1.153  
   1.154  static void
   1.155  display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
   1.156 -					const char *interface, uint32_t version)
   1.157 +                      const char *interface, uint32_t version)
   1.158  {
   1.159      SDL_VideoData *d = data;
   1.160 -    
   1.161 +
   1.162      if (strcmp(interface, "wl_compositor") == 0) {
   1.163          d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
   1.164      } else if (strcmp(interface, "wl_output") == 0) {
   1.165 -        d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1);
   1.166 -        wl_output_add_listener(d->output, &output_listener, d);
   1.167 +        Wayland_add_display(d, id);
   1.168      } else if (strcmp(interface, "wl_seat") == 0) {
   1.169          Wayland_display_add_input(d, id);
   1.170      } else if (strcmp(interface, "wl_shell") == 0) {
   1.171 @@ -255,8 +252,7 @@
   1.172          d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
   1.173          d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
   1.174          d->default_cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
   1.175 -        wl_shm_add_listener(d->shm, &shm_listener, d);
   1.176 -    
   1.177 +
   1.178  #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
   1.179      } else if (strcmp(interface, "qt_touch_extension") == 0) {
   1.180          Wayland_touch_create(d, id);
   1.181 @@ -272,26 +268,19 @@
   1.182  }
   1.183  
   1.184  static const struct wl_registry_listener registry_listener = {
   1.185 -	display_handle_global
   1.186 +    display_handle_global
   1.187  };
   1.188  
   1.189  int
   1.190  Wayland_VideoInit(_THIS)
   1.191  {
   1.192 -    SDL_VideoData *data;
   1.193 -    SDL_VideoDisplay display;
   1.194 -    SDL_DisplayMode mode;
   1.195 -    int i;
   1.196 -    
   1.197 -    data = malloc(sizeof *data);
   1.198 +    SDL_VideoData *data = SDL_malloc(sizeof *data);
   1.199      if (data == NULL)
   1.200          return 0;
   1.201      memset(data, 0, sizeof *data);
   1.202  
   1.203      _this->driverdata = data;
   1.204  
   1.205 -    WAYLAND_wl_list_init(&data->modes_list);
   1.206 -    
   1.207      data->display = WAYLAND_wl_display_connect(NULL);
   1.208      if (data->display == NULL) {
   1.209          SDL_SetError("Failed to connect to a Wayland display");
   1.210 @@ -299,25 +288,18 @@
   1.211      }
   1.212  
   1.213      data->registry = wl_display_get_registry(data->display);
   1.214 -   
   1.215 -    if ( data->registry == NULL) {
   1.216 +    if (data->registry == NULL) {
   1.217          SDL_SetError("Failed to get the Wayland registry");
   1.218          return 0;
   1.219      }
   1.220 -    
   1.221 +
   1.222      wl_registry_add_listener(data->registry, &registry_listener, data);
   1.223  
   1.224 -    for (i=0; i < 100; i++) {
   1.225 -        if (data->screen_allocation.width != 0 || WAYLAND_wl_display_get_error(data->display) != 0) {
   1.226 -            break;
   1.227 -        }
   1.228 -        WAYLAND_wl_display_dispatch(data->display);
   1.229 -    }
   1.230 -    
   1.231 -    if (data->screen_allocation.width == 0) {
   1.232 -        SDL_SetError("Failed while waiting for screen allocation: %d ", WAYLAND_wl_display_get_error(data->display));
   1.233 -        return 0;
   1.234 -    }
   1.235 +    // First roundtrip to receive all registry objects.
   1.236 +    wl_display_roundtrip(data->display);
   1.237 +
   1.238 +    // Second roundtrip to receive all output events.
   1.239 +    wl_display_roundtrip(data->display);
   1.240  
   1.241      data->xkb_context = WAYLAND_xkb_context_new(0);
   1.242      if (!data->xkb_context) {
   1.243 @@ -325,20 +307,7 @@
   1.244          return 0;
   1.245      }
   1.246  
   1.247 -    /* Use a fake 32-bpp desktop mode */
   1.248 -    mode.format = SDL_PIXELFORMAT_RGB888;
   1.249 -    mode.w = data->screen_allocation.width;
   1.250 -    mode.h = data->screen_allocation.height;
   1.251 -    mode.refresh_rate = 0;
   1.252 -    mode.driverdata = NULL;
   1.253 -    wayland_add_mode(data, mode);
   1.254 -    SDL_zero(display);
   1.255 -    display.desktop_mode = mode;
   1.256 -    display.current_mode = mode;
   1.257 -    display.driverdata = NULL;
   1.258 -    SDL_AddVideoDisplay(&display);
   1.259 -
   1.260 -    Wayland_InitMouse ();
   1.261 +    Wayland_InitMouse();
   1.262  
   1.263      WAYLAND_wl_display_flush(data->display);
   1.264  
   1.265 @@ -348,46 +317,30 @@
   1.266  static void
   1.267  Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
   1.268  {
   1.269 -    SDL_VideoData *data = _this->driverdata;
   1.270 -    SDL_DisplayMode mode;
   1.271 -    struct wayland_mode *m;
   1.272 -
   1.273 -    Wayland_PumpEvents(_this);
   1.274 -
   1.275 -    wl_list_for_each(m, &data->modes_list, link) {
   1.276 -        m->mode.format = SDL_PIXELFORMAT_RGB888;
   1.277 -        SDL_AddDisplayMode(sdl_display, &m->mode);
   1.278 -        m->mode.format = SDL_PIXELFORMAT_RGBA8888;
   1.279 -        SDL_AddDisplayMode(sdl_display, &m->mode);
   1.280 -    }
   1.281 -
   1.282 -    mode.w = data->screen_allocation.width;
   1.283 -    mode.h = data->screen_allocation.height;
   1.284 -    mode.refresh_rate = 0;
   1.285 -    mode.driverdata = NULL;
   1.286 -
   1.287 -    mode.format = SDL_PIXELFORMAT_RGB888;
   1.288 -    SDL_AddDisplayMode(sdl_display, &mode);
   1.289 -    mode.format = SDL_PIXELFORMAT_RGBA8888;
   1.290 -    SDL_AddDisplayMode(sdl_display, &mode);
   1.291 +    // Nothing to do here, everything was already done in the wl_output
   1.292 +    // callbacks.
   1.293  }
   1.294  
   1.295  static int
   1.296  Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
   1.297  {
   1.298 -    return 0;
   1.299 +    SDL_SetError("SetDisplayMode not (yet?) supported on Wayland.");
   1.300 +    return -1;
   1.301  }
   1.302  
   1.303  void
   1.304  Wayland_VideoQuit(_THIS)
   1.305  {
   1.306      SDL_VideoData *data = _this->driverdata;
   1.307 -    struct wayland_mode *t, *m;
   1.308 +    int i;
   1.309  
   1.310      Wayland_FiniMouse ();
   1.311  
   1.312 -    if (data->output)
   1.313 -        wl_output_destroy(data->output);
   1.314 +    for (i = 0; i < _this->num_displays; ++i) {
   1.315 +        SDL_VideoDisplay *display = &_this->displays[i];
   1.316 +        wl_output_destroy(display->driverdata);
   1.317 +        display->driverdata = NULL;
   1.318 +    }
   1.319  
   1.320      Wayland_display_destroy_input(data);
   1.321  
   1.322 @@ -417,16 +370,13 @@
   1.323      if (data->compositor)
   1.324          wl_compositor_destroy(data->compositor);
   1.325  
   1.326 +    if (data->registry)
   1.327 +        wl_registry_destroy(data->registry);
   1.328 +
   1.329      if (data->display) {
   1.330          WAYLAND_wl_display_flush(data->display);
   1.331          WAYLAND_wl_display_disconnect(data->display);
   1.332      }
   1.333 -    
   1.334 -    wl_list_for_each_safe(m, t, &data->modes_list, link) {
   1.335 -        WAYLAND_wl_list_remove(&m->link);
   1.336 -        free(m);
   1.337 -    }
   1.338 -
   1.339  
   1.340      free(data);
   1.341      _this->driverdata = NULL;
     2.1 --- a/src/video/wayland/SDL_waylandvideo.h	Tue Apr 07 21:52:22 2015 -0400
     2.2 +++ b/src/video/wayland/SDL_waylandvideo.h	Wed Mar 18 01:14:45 2015 +0100
     2.3 @@ -40,33 +40,24 @@
     2.4      struct wl_display *display;
     2.5      struct wl_registry *registry;
     2.6      struct wl_compositor *compositor;
     2.7 -    struct wl_output *output;
     2.8      struct wl_shm *shm;
     2.9      struct wl_cursor_theme *cursor_theme;
    2.10      struct wl_cursor *default_cursor;
    2.11      struct wl_pointer *pointer;
    2.12      struct wl_shell *shell;
    2.13  
    2.14 -    struct {
    2.15 -        int32_t x, y, width, height;
    2.16 -    } screen_allocation;
    2.17 -
    2.18 -    struct wl_list modes_list;
    2.19 -
    2.20      EGLDisplay edpy;
    2.21      EGLContext context;
    2.22      EGLConfig econf;
    2.23  
    2.24      struct xkb_context *xkb_context;
    2.25      struct SDL_WaylandInput *input;
    2.26 -    
    2.27 -#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH    
    2.28 +
    2.29 +#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
    2.30      struct SDL_WaylandTouch *touch;
    2.31      struct qt_surface_extension *surface_extension;
    2.32      struct qt_windowmanager *windowmanager;
    2.33  #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
    2.34 -
    2.35 -    uint32_t shm_formats;
    2.36  } SDL_VideoData;
    2.37  
    2.38  #endif /* _SDL_waylandvideo_h */
     3.1 --- a/src/video/wayland/SDL_waylandwindow.c	Tue Apr 07 21:52:22 2015 -0400
     3.2 +++ b/src/video/wayland/SDL_waylandwindow.c	Wed Mar 18 01:14:45 2015 +0100
     3.3 @@ -179,17 +179,6 @@
     3.4      }
     3.5  #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
     3.6  
     3.7 -    /**
     3.8 -     * If the user specified 0x0 as the size (turned to 1x1 by SDL_CreateWindow
     3.9 -     * in SDL_video.c), we want to make the window fill the whole screen
    3.10 -     **/
    3.11 -    if (window->w == 1) {
    3.12 -        window->w = c->screen_allocation.width;
    3.13 -    }
    3.14 -    if (window->h == 1) {
    3.15 -        window->h = c->screen_allocation.height;
    3.16 -    }
    3.17 -
    3.18      data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
    3.19                                              window->w, window->h);
    3.20