src/video/wayland/SDL_waylandvideo.c
author Gabriel Jacobo <gabomdq@gmail.com>
Sat, 14 Dec 2013 20:18:43 -0300
changeset 8062 4fc5f66d63cc
child 8082 5b83ad3f01ac
permissions -rw-r--r--
Wayland support

Based on the original port to Wayland by: Joel Teichroeb, Benjamin Franzke, Scott Moreau, et al.

Additional changes in this commit, done by me:

* Wayland uses the common EGL framework
* EGL can now create a desktop OpenGL context
* testgl2 loads GL functions dynamically, no need to link to libGL anymore
* Assorted fixes to the Wayland backend

Tested on the Weston Compositor (v1.0.5) that ships with Ubuntu 13.10,
running Weston under X. Tests ran: testrendercopyex (all backends), testgl2, testgles2,testintersections
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 #include "SDL_config.h"
    23 
    24 #include "SDL_video.h"
    25 #include "SDL_mouse.h"
    26 #include "../../events/SDL_events_c.h"
    27 
    28 #include "SDL_waylandvideo.h"
    29 #include "SDL_waylandevents_c.h"
    30 #include "SDL_waylandwindow.h"
    31 #include "SDL_waylandopengles.h"
    32 #include "SDL_waylandmouse.h"
    33 
    34 #include <fcntl.h>
    35 #include <xkbcommon/xkbcommon.h>
    36 
    37 #define WAYLANDVID_DRIVER_NAME "wayland"
    38 
    39 struct wayland_mode {
    40     SDL_DisplayMode mode;
    41     struct wl_list link;
    42 };
    43 
    44 /* Initialization/Query functions */
    45 static int
    46 Wayland_VideoInit(_THIS);
    47 
    48 static void
    49 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
    50 static int
    51 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
    52 
    53 static void
    54 Wayland_VideoQuit(_THIS);
    55 
    56 /* Wayland driver bootstrap functions */
    57 static int
    58 Wayland_Available(void)
    59 {
    60     struct wl_display *display = NULL;
    61 
    62     display = wl_display_connect(NULL);
    63     if (display != NULL) {
    64         wl_display_disconnect(display);
    65     }
    66 
    67     return (display != NULL);
    68 }
    69 
    70 static void
    71 Wayland_DeleteDevice(SDL_VideoDevice *device)
    72 {
    73     SDL_free(device);
    74 }
    75 
    76 static SDL_VideoDevice *
    77 Wayland_CreateDevice(int devindex)
    78 {
    79     SDL_VideoDevice *device;
    80 
    81     /* Initialize all variables that we clean on shutdown */
    82     device = SDL_calloc(1, sizeof(SDL_VideoDevice));
    83     if (!device) {
    84         SDL_OutOfMemory();
    85         return NULL;
    86     }
    87 
    88     /* Set the function pointers */
    89     device->VideoInit = Wayland_VideoInit;
    90     device->VideoQuit = Wayland_VideoQuit;
    91     device->SetDisplayMode = Wayland_SetDisplayMode;
    92     device->GetDisplayModes = Wayland_GetDisplayModes;
    93     device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
    94 
    95     device->PumpEvents = Wayland_PumpEvents;
    96 
    97     device->GL_SwapWindow = Wayland_GLES_SwapWindow;
    98     device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
    99     device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
   100     device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
   101     device->GL_CreateContext = Wayland_GLES_CreateContext;
   102     device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
   103     device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
   104     device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
   105     device->GL_DeleteContext = Wayland_GLES_DeleteContext;
   106 
   107     device->CreateWindow = Wayland_CreateWindow;
   108     device->ShowWindow = Wayland_ShowWindow;
   109     device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
   110     device->SetWindowSize = Wayland_SetWindowSize;
   111     device->DestroyWindow = Wayland_DestroyWindow;
   112 
   113     device->free = Wayland_DeleteDevice;
   114 
   115     return device;
   116 }
   117 
   118 VideoBootStrap Wayland_bootstrap = {
   119     WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
   120     Wayland_Available, Wayland_CreateDevice
   121 };
   122 
   123 static void
   124 wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m)
   125 {
   126     struct wayland_mode *mode;
   127 
   128     /* Check for duplicate mode */
   129     wl_list_for_each(mode, &d->modes_list, link)
   130         if (mode->mode.w == m.w && mode->mode.h == m.h &&
   131 	    mode->mode.refresh_rate == m.refresh_rate)
   132 	    return;
   133 
   134     /* Add new mode to the list */
   135     mode = SDL_calloc(1, sizeof *mode);
   136 
   137     if (!mode)
   138 	return;
   139 
   140     mode->mode = m;
   141     wl_list_insert(&d->modes_list, &mode->link);
   142 }
   143 
   144 static void
   145 display_handle_geometry(void *data,
   146                         struct wl_output *output,
   147                         int x, int y,
   148                         int physical_width,
   149                         int physical_height,
   150                         int subpixel,
   151                         const char *make,
   152                         const char *model,
   153                         int transform)
   154 
   155 {
   156     SDL_VideoData *d = data;
   157 
   158     d->screen_allocation.x = x;
   159     d->screen_allocation.y = y;
   160 }
   161 
   162 static void
   163 display_handle_mode(void *data,
   164                     struct wl_output *wl_output,
   165                     uint32_t flags,
   166                     int width,
   167                     int height,
   168                     int refresh)
   169 {
   170     SDL_VideoData *d = data;
   171     SDL_DisplayMode mode;
   172 
   173     SDL_zero(mode);
   174     mode.w = width;
   175     mode.h = height;
   176     mode.refresh_rate = refresh / 1000;
   177 
   178     wayland_add_mode(d, mode);
   179 
   180     if (flags & WL_OUTPUT_MODE_CURRENT) {
   181         d->screen_allocation.width = width;
   182         d->screen_allocation.height = height;
   183     }
   184 }
   185 
   186 static const struct wl_output_listener output_listener = {
   187     display_handle_geometry,
   188     display_handle_mode
   189 };
   190 
   191 static void
   192 shm_handle_format(void *data,
   193                   struct wl_shm *shm,
   194                   uint32_t format)
   195 {
   196     SDL_VideoData *d = data;
   197 
   198     d->shm_formats |= (1 << format);
   199 }
   200 
   201 static const struct wl_shm_listener shm_listener = {
   202     shm_handle_format
   203 };
   204 
   205 static void
   206 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
   207 					const char *interface, uint32_t version)
   208 {
   209     SDL_VideoData *d = data;
   210 
   211     if (strcmp(interface, "wl_compositor") == 0) {
   212         d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
   213     } else if (strcmp(interface, "wl_output") == 0) {
   214         d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1);
   215         wl_output_add_listener(d->output, &output_listener, d);
   216     } else if (strcmp(interface, "wl_seat") == 0) {
   217         Wayland_display_add_input(d, id);
   218     } else if (strcmp(interface, "wl_shell") == 0) {
   219         d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
   220     } else if (strcmp(interface, "wl_shm") == 0) {
   221         d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
   222         d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
   223         d->default_cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
   224         wl_shm_add_listener(d->shm, &shm_listener, d);
   225     }
   226 }
   227 
   228 static const struct wl_registry_listener registry_listener = {
   229 	display_handle_global
   230 };
   231 
   232 int
   233 Wayland_VideoInit(_THIS)
   234 {
   235     SDL_VideoData *data;
   236 
   237     data = malloc(sizeof *data);
   238     if (data == NULL)
   239         return 0;
   240     memset(data, 0, sizeof *data);
   241 
   242     _this->driverdata = data;
   243 
   244     wl_list_init(&data->modes_list);
   245     
   246     data->display = wl_display_connect(NULL);
   247     if (data->display == NULL) {
   248         SDL_SetError("Failed to connect to a Wayland display");
   249         return 0;
   250     }
   251 
   252     data->registry = wl_display_get_registry(data->display);
   253     wl_registry_add_listener(data->registry, &registry_listener, data);
   254 
   255     while (data->screen_allocation.width == 0)
   256         wl_display_dispatch(data->display);
   257 
   258     data->xkb_context = xkb_context_new(0);
   259     if (!data->xkb_context) {
   260         SDL_SetError("Failed to create XKB context");
   261         return 0;
   262     }
   263 
   264     SDL_VideoDisplay display;
   265     SDL_DisplayMode mode;
   266 
   267     /* Use a fake 32-bpp desktop mode */
   268     mode.format = SDL_PIXELFORMAT_RGB888;
   269     mode.w = data->screen_allocation.width;
   270     mode.h = data->screen_allocation.height;
   271     mode.refresh_rate = 0;
   272     mode.driverdata = NULL;
   273     wayland_add_mode(data, mode);
   274     SDL_zero(display);
   275     display.desktop_mode = mode;
   276     display.current_mode = mode;
   277     display.driverdata = NULL;
   278     SDL_AddVideoDisplay(&display);
   279 
   280     Wayland_InitMouse ();
   281 
   282     wayland_schedule_write(data);
   283 
   284     return 0;
   285 }
   286 
   287 static void
   288 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
   289 {
   290     SDL_VideoData *data = _this->driverdata;
   291     SDL_DisplayMode mode;
   292     struct wayland_mode *m;
   293 
   294     Wayland_PumpEvents(_this);
   295 
   296     wl_list_for_each(m, &data->modes_list, link) {
   297         m->mode.format = SDL_PIXELFORMAT_RGB888;
   298         SDL_AddDisplayMode(sdl_display, &m->mode);
   299         m->mode.format = SDL_PIXELFORMAT_RGBA8888;
   300         SDL_AddDisplayMode(sdl_display, &m->mode);
   301     }
   302 
   303     mode.w = data->screen_allocation.width;
   304     mode.h = data->screen_allocation.height;
   305     mode.refresh_rate = 0;
   306     mode.driverdata = NULL;
   307 
   308     mode.format = SDL_PIXELFORMAT_RGB888;
   309     SDL_AddDisplayMode(sdl_display, &mode);
   310     mode.format = SDL_PIXELFORMAT_RGBA8888;
   311     SDL_AddDisplayMode(sdl_display, &mode);
   312 }
   313 
   314 static int
   315 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
   316 {
   317     return 0;
   318 }
   319 
   320 void
   321 Wayland_VideoQuit(_THIS)
   322 {
   323     SDL_VideoData *data = _this->driverdata;
   324     struct wayland_mode *t, *m;
   325 
   326     Wayland_FiniMouse ();
   327 
   328     if (data->output)
   329         wl_output_destroy(data->output);
   330 
   331     Wayland_display_destroy_input(data);
   332 
   333     if (data->xkb_context) {
   334         xkb_context_unref(data->xkb_context);
   335         data->xkb_context = NULL;
   336     }
   337 
   338     if (data->shm)
   339         wl_shm_destroy(data->shm);
   340 
   341     if (data->cursor_theme)
   342         wl_cursor_theme_destroy(data->cursor_theme);
   343 
   344     if (data->shell)
   345         wl_shell_destroy(data->shell);
   346 
   347     if (data->compositor)
   348         wl_compositor_destroy(data->compositor);
   349 
   350     if (data->display) {
   351         wl_display_flush(data->display);
   352         wl_display_disconnect(data->display);
   353     }
   354     
   355     wl_list_for_each_safe(m, t, &data->modes_list, link) {
   356         wl_list_remove(&m->link);
   357         free(m);
   358     }
   359 
   360 
   361     free(data);
   362     _this->driverdata = NULL;
   363 }
   364 
   365 /* vi: set ts=4 sw=4 expandtab: */